Melihat melalui jawaban dan komentar pada pertanyaan CUDA, dan di wiki tag CUDA , saya melihat sering disarankan bahwa status pengembalian setiap panggilan API harus diperiksa untuk kesalahan. Dokumentasi API berisi fungsi-fungsi seperti cudaGetLastError
,, cudaPeekAtLastError
dan cudaGetErrorString
, tetapi apa cara terbaik untuk menyatukannya untuk menangkap dan melaporkan kesalahan secara andal tanpa memerlukan banyak kode tambahan?
cuda
error-checking
talonmies
sumber
sumber
getLastCudaError
dancheckCudaErrors
, yang melakukan cukup banyak seperti yang dijelaskan dalam jawaban yang diterima . Lihat contoh untuk demonstrasi. Cukup pilih untuk menginstal sampel bersama dengan toolkit dan Anda akan memilikinya.Jawaban:
Mungkin cara terbaik untuk memeriksa kesalahan dalam kode API runtime adalah dengan mendefinisikan fungsi penangan gaya tegas dan pembungkus makro seperti ini:
Anda kemudian dapat membungkus setiap panggilan API dengan
gpuErrchk
makro, yang akan memproses status pengembalian dari panggilan API yang dibungkus, misalnya:Jika ada kesalahan dalam panggilan, pesan teks yang menggambarkan kesalahan dan file dan baris dalam kode Anda di mana kesalahan terjadi akan dipancarkan ke
stderr
dan aplikasi akan keluar. Anda dapat memodifikasigpuAssert
untuk meningkatkan pengecualian daripada memanggilexit()
aplikasi yang lebih canggih jika diperlukan.Pertanyaan kedua yang terkait adalah bagaimana memeriksa kesalahan dalam peluncuran kernel, yang tidak dapat langsung dibungkus dengan panggilan makro seperti panggilan API runtime standar. Untuk kernel, kira-kira seperti ini:
pertama-tama akan memeriksa argumen peluncuran yang tidak valid, kemudian memaksa host untuk menunggu sampai kernel berhenti dan memeriksa kesalahan eksekusi. Sinkronisasi dapat dihilangkan jika Anda memiliki panggilan API pemblokiran berikutnya seperti ini:
dalam hal ini
cudaMemcpy
panggilan dapat mengembalikan kesalahan yang terjadi selama eksekusi kernel atau dari salinan memori itu sendiri. Ini bisa membingungkan bagi pemula, dan saya akan merekomendasikan menggunakan sinkronisasi eksplisit setelah peluncuran kernel selama debugging untuk membuatnya lebih mudah untuk memahami di mana masalah mungkin timbul.Perhatikan bahwa ketika menggunakan CUDA Dynamic Parallelism , metodologi yang sangat mirip dapat dan harus diterapkan pada penggunaan API runtime CUDA di kernel perangkat, serta setelah kernel perangkat diluncurkan:
sumber
cudaDeviceReset()
sebelum keluar juga? Dan klausa untuk alokasi memori?Jawaban talonmies di atas adalah cara yang baik untuk membatalkan aplikasi dengan
assert
cara-gaya.Terkadang kami mungkin ingin melaporkan dan memulihkan dari kondisi kesalahan dalam konteks C ++ sebagai bagian dari aplikasi yang lebih besar.
Berikut cara yang cukup singkat untuk melakukan itu dengan melempar pengecualian C ++ yang berasal dari
std::runtime_error
penggunaanthrust::system_error
:Ini akan memasukkan nama file, nomor baris, dan deskripsi bahasa Inggris dari anggota
cudaError_t
pengecualian yang dilemparkan.what()
:Hasil:
Klien
some_function
dapat membedakan kesalahan CUDA dari jenis kesalahan lainnya jika diinginkan:Karena
thrust::system_error
astd::runtime_error
, kita dapat menanganinya dengan cara yang sama dari kelas kesalahan yang luas jika kita tidak memerlukan ketepatan contoh sebelumnya:sumber
<thrust/system/cuda_error.h>
sekarang efektif<thrust/system/cuda/error.h>
.C ++ - cara kanonik: Jangan periksa kesalahan ... gunakan binding C ++ yang melempar pengecualian.
Dulu saya kesal dengan masalah ini; dan saya dulu punya solusi fungsi makro-cum-wrapper seperti di Talonmies dan jawaban Jared, tapi, jujur? Itu membuat menggunakan API CUDA Runtime lebih jelek dan seperti-C.
Jadi saya sudah mendekati ini dengan cara yang berbeda dan lebih mendasar. Untuk sampel hasil, inilah bagian dari
vectorAdd
sampel CUDA - dengan pengecekan kesalahan lengkap dari setiap panggilan API runtime:Lagi - semua kesalahan potensial diperiksa, dan pengecualian jika kesalahan terjadi (peringatan: Jika kernel menyebabkan beberapa kesalahan setelah peluncuran, itu akan ditangkap setelah upaya untuk menyalin hasil, bukan sebelumnya; untuk memastikan kernel berhasil Anda akan perlu memeriksa kesalahan antara peluncuran dan salin dengan a
cuda::outstanding_error::ensure_none()
perintah).Kode di atas menggunakan my
Pembungkus Thin Modern-C ++ untuk perpustakaan CUDA Runtime API (Github)
Perhatikan bahwa pengecualian membawa penjelasan string dan kode status API CUDA runtime setelah panggilan gagal.
Beberapa tautan ke bagaimana kesalahan CUDA diperiksa secara otomatis dengan pembungkus ini:
sumber
Solusi yang dibahas di sini bekerja dengan baik untuk saya. Solusi ini menggunakan fungsi cuda bawaan dan sangat mudah diterapkan.
Kode yang relevan disalin di bawah ini:
sumber