2012-08-09 34 views
41

khi đang gọi đến chức năng cudaDeviceSynchronize thực sự cần thiết ?.Khi nào cần gọi cudaDeviceSynchronize?

Theo như tôi hiểu từ tài liệu CUDA, hạt CUDA không đồng bộ, vì vậy có vẻ như chúng ta nên gọi cudaDeviceSynchronize sau mỗi lần khởi chạy hạt nhân. Tuy nhiên, tôi đã thử cùng một mã (đào tạo mạng thần kinh) có và không có bất kỳ cudaDeviceSynchronize, ngoại trừ một trước khi đo thời gian. Tôi đã tìm thấy rằng tôi nhận được kết quả tương tự nhưng với một tốc độ lên từ 7-12x (tùy thuộc vào kích thước ma trận).

Vì vậy, câu hỏi đặt ra là nếu có bất kỳ lý do nào để sử dụng cudaDeviceSynchronize ngoài việc đo thời gian.

Ví dụ:

  • Có cần thiết trước khi sao chép dữ liệu từ GPU trở lại máy chủ với cudaMemcpy?

  • Nếu tôi nhân ma trận như

    C = A * B 
    D = C * F 
    

tôi nên đặt cudaDeviceSynchronize giữa cả hai?

Từ thử nghiệm của tôi Có vẻ như tôi không làm vậy.

Tại sao cudaDeviceSynchronize làm chậm chương trình?

+0

Một trường hợp sẽ là nếu bạn có bất kỳ câu lệnh in nào trong hạt nhân, bộ đệm sẽ không in cho đến khi sự kiện đồng bộ hóa. –

Trả lời

12

Một trường hợp sử dụng cudaDeviceSynchronize() là thích hợp sẽ là khi bạn có một số hoạt động cudaStream s và bạn muốn họ trao đổi một số thông tin. Một trường hợp thực tế của điều này là sự cân bằng song song trong các mô phỏng lượng tử Monte Carlo. Trong trường hợp này, chúng tôi muốn đảm bảo rằng mọi luồng đã kết thúc chạy một số hướng dẫn và nhận được một số kết quả trước khi chúng bắt đầu truyền tin nhắn cho nhau hoặc chúng tôi sẽ kết thúc việc truyền thông tin rác. Lý do sử dụng lệnh này làm chậm chương trình rất nhiều là cudaDeviceSynchronize() buộc chương trình chờ tất cả các lệnh đã được phát hành trước đây trong tất cả các luồng trên thiết bị để hoàn thành trước khi tiếp tục (từ Hướng dẫn lập trình CUDA C). Như bạn đã nói, việc thực thi hạt nhân thường không đồng bộ, do đó, trong khi thiết bị GPU đang thực thi hạt nhân của bạn, CPU có thể tiếp tục hoạt động trên một số lệnh khác, đưa ra hướng dẫn nhiều hơn cho thiết bị, vv thay vì chờ đợi. Tuy nhiên khi bạn sử dụng lệnh đồng bộ hóa này, CPU thay vào đó bị buộc phải nhàn rỗi cho đến khi tất cả công việc của GPU đã hoàn thành trước khi thực hiện bất cứ điều gì khác. Hành vi này là hữu ích khi gỡ lỗi, vì bạn có thể có một segfault xảy ra tại dường như "ngẫu nhiên" lần vì việc thực thi không đồng bộ của mã thiết bị (cho dù trong một dòng hoặc nhiều). cudaDeviceSynchronize() sẽ buộc chương trình đảm bảo luồng/memcpys của luồng được hoàn thành trước khi tiếp tục, có thể dễ dàng tìm ra nơi truy cập bất hợp pháp đang xảy ra (vì lỗi sẽ xuất hiện trong quá trình đồng bộ).

43

Mặc dù khởi chạy hạt nhân CUDA không đồng bộ, tất cả tác vụ liên quan đến GPU được đặt trong một luồng (đó là hành vi mặc định) được thực thi tuần tự.

Vì vậy, ví dụ,

kernel1<<<X,Y>>>(...); // kernel start execution, CPU continues to next statement 
kernel2<<<X,Y>>>(...); // kernel is placed in queue and will start after kernel1 finishes, CPU continues to next statement 
cudaMemcpy(...); // CPU blocks until ememory is copied, memory copy starts only after kernel2 finishes 

Vì vậy, trong ví dụ của bạn không có nhu cầu cho cudaDeviceSynchronize. Tuy nhiên, có thể hữu ích khi gỡ lỗi để phát hiện hạt nhân nào của bạn đã gây ra lỗi (nếu có).

cudaDeviceSynchronize có thể gây ra một số chậm lại, nhưng 7-12x có vẻ quá nhiều.Có thể có một số vấn đề với phép đo thời gian, hoặc có thể là hạt nhân thực sự nhanh, và chi phí của việc đồng bộ hóa rõ ràng là rất lớn so với thời gian tính toán thực tế.

+0

"Dòng GPU mặc định duy nhất trừ khi được chỉ định khác" không phải lúc nào cũng được nvcc giữ lại. Tôi chỉ gỡ rối một chương trình mà tôi đã chia nhỏ một phép tính dài trên một hạt nhân thành một phép tính theo từng phần đã khởi chạy từng hạt nhân trong một vòng lặp for(). Tiếp tục cho() loop hạt nhân khởi động chọn nơi trước đó cho() loop hạt nhân còn lại bên thiết bị. Lỗi này là trình biên dịch nvcc không thể thấy điều này chỉ từ mã máy chủ và cố gắng khởi chạy từng hạt nhân cùng một lúc. Điều này có nghĩa rằng tất cả các hạt nhân nhưng hạt nhân đầu tiên được tính toán rác. – opetrenko

+2

@opetrenko Đó không phải là cách CUDA hoạt động. –

+0

@AleksandrDubinsky Vui lòng đọc nhận xét của tôi cẩn thận hơn. Tôi rất rõ ràng đặt xuống "không phải lúc nào cũng được tổ chức bởi nvcc". Sau đó tôi đã đưa ra một ví dụ về một lỗi cụ thể mà tôi đã truy tìm bằng cách sử dụng cuda-gdb làm ví dụ minh họa chính xác điều đó. Tôi chắc chắn sẽ đồng ý rằng dựa trên văn học của Nvidia, đây không phải là cách CUDA làm việc ... nhưng điều tôi nói không phải là một ý kiến: đó là một quan sát được thực hiện trong quá trình gỡ lỗi về cách nó hoạt động trong một trường hợp cụ thể. – opetrenko

3

Khi bạn muốn GPU bắt đầu xử lý một số dữ liệu, bạn thường thực hiện lời gọi kernal. Khi bạn làm như vậy, thiết bị của bạn (GPU) sẽ bắt đầu làm bất cứ điều gì bạn nói với nó để làm. Tuy nhiên, không giống như một chương trình tuần tự bình thường trên máy chủ của bạn (CPU) sẽ tiếp tục thực hiện các dòng mã tiếp theo trong chương trình của bạn. cudaDeviceSynchronize làm cho máy chủ (CPU) đợi cho đến khi thiết bị (GPU) thực hiện xong TẤT CẢ các chủ đề bạn đã bắt đầu, và do đó chương trình của bạn sẽ tiếp tục như thể nó là một chương trình tuần tự bình thường.

Trong các chương trình đơn giản, bạn thường sử dụng cudaDeviceSynchronize, khi bạn sử dụng GPU để thực hiện tính toán, để tránh tính thời gian không khớp giữa CPU yêu cầu kết quả và GPU tính toán. Để sử dụng cudaDeviceSynchronize làm cho nó dễ dàng hơn nhiều để mã chương trình của bạn, nhưng có một nhược điểm lớn: CPU của bạn là nhàn rỗi tất cả các thời gian, trong khi GPU làm cho tính toán. Vì vậy, trong tính toán hiệu suất cao, bạn thường cố gắng hướng tới việc CPU của bạn thực hiện tính toán trong khi chờ đợi cho GPU kết thúc.

Các vấn đề liên quan