Каков канонический способ проверки на наличие ошибок с помощью API времени выполнения CUDA?

Просматривая ответы и комментарии на вопросы CUDA, а также вCUDA Tag WikiЯ вижу, что часто предлагается, чтобы статус возврата каждого вызова API проверялся на наличие ошибок. Документация API содержит такие функции, как,cudaGetLastErrorcudaPeekAtLastError, а такжеcudaGetErrorString, но каков наилучший способ собрать их вместе, чтобы надежно отлавливать и сообщать об ошибках, не требуя большого количества дополнительного кода?

 chappjc18 февр. 2015 г., 19:09
@JackOLantern Нет, этоне то, что я имел в виду. Это Q &А было очень полезно для меня, и это 'Это, конечно, легче найти, чем какой-либо заголовок в SDK. Я подумал, что было бы полезно отметить, что NVIDIA также справляется с этим и где искать больше. Я'Я бы смягчил тон моего комментария, если бы мог. :)
 Taryn27 мар. 2017 г., 16:59
@ Talonmies я выигралкомментировать гнусную природу, новот больше подробностей.
 chappjc03 сент. 2014 г., 03:16
NVIDIA»с CUDAобразцы содержит заголовок helper_cuda.h, в котором есть макросыgetLastCudaError а такжеcheckCudaErrors, которые делают в значительной степени то, что описано впринятый ответ, Смотрите образцы для демонстраций. Просто выберитеустановить образцы вместе с инструментарием и у тебя это будет.
 opetrenko09 янв. 2016 г., 18:58
Инструменты отладки, позволяющиеподход" где ошибки начинаются намного лучше с 2012 года на CUDA. Я не работал с отладчиками на основе графического интерфейса, ноCUDA Tag Wiki упоминает командную строку cuda-gdb. Это ОЧЕНЬ мощный инструмент, поскольку он позволяет вам перемещаться по фактическим перекосам и потокам на самом GPU (хотя в большинстве случаев требуется архитектура 2.0+)
 talonmies25 мар. 2017 г., 19:09
@bluefeet: какова была сделка с редактированием, которое вы откатили? Похоже, что на самом деле ничего не изменилось в уценке, но это было принято в качестве редактирования. Было ли что-то гнусное на работе?
 JackOLantern18 февр. 2015 г., 18:51
@chappjc Я не думаю, что этот вопрос и ответ претендуют на то, чтобы быть оригинальными, если это то, что вы имеете в виду, но это имеет смысл в том, чтобы обучать людей, использующих проверку ошибок CUDA.

Ответы на вопрос(4)

talonmies' Ответ выше - это прекрасный способ прервать приложение вassertстиль манеры

Иногда мы можем захотеть сообщить и исправить состояние ошибки в контексте C ++ как часть более крупного приложения.

Вот'достаточно краткий способ сделать это, создав исключение C ++, полученное изstd::runtime_error с помощью :thrust::system_error

#include 
#include 
#include 

void throw_on_cuda_error(cudaError_t code, const char *file, int line)
{
  if(code != cudaSuccess)
  {
    std::stringstream ss;
    ss < file < "(" < line < ")";
    std::string file_and_line;
    ss >> file_and_line;
    throw thrust::system_error(code, thrust::cuda_category(), file_and_line);
  }
}
 chappjc18 мая 2015 г., 22:05
Заголовки тяги, кажется, были переставлены. сейчас эффективно.
 einpoklum22 мар. 2017 г., 16:00
Джаред, я думаю, моя библиотека-обертка включает в себя предложенное вами решение - в основном, и достаточно легка, чтобы ее можно было заменить. (См. Мой ответ)
Решение Вопроса

Вероятно, лучший способ проверить наличие ошибок в коде API времени выполнения - определить функцию-обработчик стиля assert и макрос-обертку, например:

#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
   if (code != cudaSuccess) 
   {
      fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
      if (abort) exit(code);
   }
}

Затем вы можете обернуть каждый вызов API с помощьюgpuErrchk макрос, который будет обрабатывать возвращаемый статус вызова API, который он переносит, например:

gpuErrchk( cudaMalloc(&a_d, size*sizeof(int)) );

Если в вызове произошла ошибка, текстовое сообщение с описанием ошибки и файлом и строкой в вашем коде, где произошла ошибка, будет отправленоstderr и приложение выйдет. Вы могли бы изменитьgpuAssert поднять исключение, а не позвонитьexit() в более сложном приложении, если бы это было необходимо.

Второй связанный с этим вопрос - как проверить наличие ошибок при запуске ядра, которые могут:не быть напрямую обернутым в вызов макроса как стандартные вызовы API времени выполнения. Для ядер что-то вроде этого:

kernel(a);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaDeviceSynchronize() );

сначала проверит неверный аргумент запуска, затем заставит хост ждать, пока ядро не остановится, и проверит наличие ошибки выполнения. Синхронизация может быть устранена, если у вас есть следующий вызов API блокировки, например:

kernel(a_d);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaMemcpy(a_h, a_d, size * sizeof(int), cudaMemcpyDeviceToHost) );

в этом случаеcudaMemcpy Вызов может вернуть либо ошибки, которые произошли во время выполнения ядра, либо ошибки из самой копии памяти. Это может сбивать с толку новичка, и я бы порекомендовал использовать явную синхронизацию после запуска ядра во время отладки, чтобы было легче понять, где могут возникнуть проблемы.

 harrism06 февр. 2014 г., 06:01
не должен»т этот вопрос будет сделан "Сообщество вики "?
 Aurelius21 окт. 2014 г., 16:14
не должен»т мы добавляемcudaDeviceReset() перед выходом тоже? И пункт для освобождения памяти?
 talonmies06 февр. 2014 г., 06:19
@harrism: я неЯ так не думаю. Сообщество Wiki предназначено для вопросов или ответов, которые часто редактируются. Это н'т один из тех
 Azmisov25 мая 2017 г., 04:15
Есть ли способ получить более конкретные ошибки для выполнения ядра? Все ошибки, которые яполучаю только номер строки из кода хоста, а не из ядра.
 nurabha26 мая 2015 г., 17:55
@talonmies: Для вызовов Async CUDA во время выполнения, таких как cudaMemsetAsync и cudaMemcpyAsync, требуется ли также синхронизация устройства gpu и потока хоста посредством вызова gpuErrchk (cudaDeviceSynchronize ())?
 masterxilo07 апр. 2016 г., 02:36
Обратите внимание, что явная синхронизация после запуска ядра не является неправильной, но может серьезно изменить производительность выполнения и чередование семантики. Если вы используете чередование, выполнение явной синхронизации для отладки может скрыть целый класс ошибок, которые может быть трудно отследить в сборке выпуска.
 user1471706 апр. 2019 г., 17:50
Учитывая популярность этого ответа, не долженКто-то поместил этот макрос в API CUDA? Я'мы видели, как этот макрос превратился в миллиард репо, каждое с небольшими отличиями.
C ++ - канонический путь: Донt проверить на ошибки ... использовать привязки C ++, которые генерируют исключения.

Раньше меня раздражала эта проблема; и у меня было решение для функции macro-cum-wrapper-function, как в Talonmies и Jared 'ответы, но, если честно? Это делает использование CUDA Runtime API еще более уродливым и похожим на C.

Так что я'Мы подошли к этому по-другому и более фундаментально. Для образца результата, здесьчасть CUDAvectorAdd образец - сполный проверка ошибок каждого вызова API времени выполнения:

// (... prepare host-side buffers here ...)

auto current_device = cuda::device::current::get();
auto d_A = cuda::memory::device::make_unique(current_device, numElements);
auto d_B = cuda::memory::device::make_unique(current_device, numElements);
auto d_C = cuda::memory::device::make_unique(current_device, numElements);

cuda::memory::copy(d_A.get(), h_A.get(), size);
cuda::memory::copy(d_B.get(), h_B.get(), size);

// (... prepare a launch configuration here... )
cuda::launch( vectorAdd, launch_config,
    d_A.get(), d_B.get(), d_C.get(), numElements
);    
cuda::memory::copy(h_C.get(), d_C.get(), size);

// (... verify results here...)

Опять же - все потенциальные ошибки проверяются и сообщаются через выброшенное исключение. Этот код использует мой

Оболочки Thin Modern-C ++ для библиотеки API CUDA Runtime (Github)

Обратите внимание, что после неудачного вызова исключения содержат как строковое объяснение, так и код состояния API времени выполнения CUDA.

Несколько ссылок на то, как ошибки CUDA автоматически проверяются с помощью этих оболочек:

Тестовая программа, бросающая и ловящая кучу исключенийДокументация для функциональности, связанной с ошибками

Обсуждаемое решениеВот работал хорошо для меня. Это решение использует встроенные функции cuda и очень просто в реализации.

Соответствующий код скопирован ниже:

#include 
#include 

__global__ void foo(int *ptr)
{
  *ptr = 7;
}

int main(void)
{
  foo(0);

  // make the host block until the device is finished with foo
  cudaDeviceSynchronize();

  // check for error
  cudaError_t error = cudaGetLastError();
  if(error != cudaSuccess)
  {
    // print the CUDA error message and exit
    printf("CUDA error: %s\n", cudaGetErrorString(error));
    exit(-1);
  }

  return 0;
}

Ваш ответ на вопрос