Код имеет дефект при обработке cudaEventRecord()
, который используется в макросах TIMERSTART
и TIMERSTOP
, определенных здесь и используемых здесь (с malloc_buffers
label).
События CUDA имеют ассоциацию устройств , неявно определяемую при их создании. Это означает, что они связаны с устройством, выбранным последним вызовом cudaSetDevice()
. Как указано в руководстве по программированию:
cudaEventRecord () завершится ошибкой, если входное событие и входной поток связаны с разными устройствами.
(обратите внимание, что каждое устройство имеет свои собственный нулевой поток - эти события записываются в нулевой поток)
И если мы запустим код с cuda-memcheck
, мы заметим, что ошибка неверного дескриптора ресурса действительно возвращается вызовом cudaEventRecord()
.
Конкретно ссылаясь на код здесь :
...
std::vector<size_t> bufs_lens(bufs_lens_scatter);
TIMERSTART(malloc_buffers)
for (gpu_id_t gpu = 0; gpu < num_gpus; ++gpu) {
cudaSetDevice(context.get_device_id(gpu)); CUERR
cudaMalloc(&bufs[gpu], sizeof(data_t)*bufs_lens[gpu]); CUERR
}
TIMERSTOP(malloc_buffers)
Макрос TIMERSTART
определяет и создает 2 события cuda, одно из которых он немедленно записывает (начало мероприятие). Макрос TIMERSTOP
использует событие остановки таймера, которое было создано в макросе TIMERSTART. Однако мы можем видеть, что промежуточный код, вероятно, изменил устройство с того, которое действовало, когда были созданы эти два события (из-за вызова cudaSetDevice
в for-l oop). Следовательно, вызовы cudaEventRecord
(и cudaEventElapsedTime
) не работают из-за этого недопустимого использования.
В качестве доказательства, когда я добавляю вызовы cudaSetDevice
в определения макросов следующим образом:
#define TIMERSTART(label) \
cudaEvent_t timerstart##label, timerstop##label; \
float timerdelta##label; \
cudaSetDevice(0); \
cudaEventCreate(&timerstart##label); \
cudaEventCreate(&timerstop##label); \
cudaEventRecord(timerstart##label, 0);
#endif
#ifndef __CUDACC__
#define TIMERSTOP(label) \
stop##label = std::chrono::system_clock::now(); \
std::chrono::duration<double> \
timerdelta##label = timerstop##label-timerstart##label; \
std::cout << "# elapsed time ("<< #label <<"): " \
<< timerdelta##label.count() << "s" << std::endl;
#else
#define TIMERSTOP(label) \
cudaSetDevice(0); \
cudaEventRecord(timerstop##label, 0); \
cudaEventSynchronize(timerstop##label); \
cudaEventElapsedTime( \
&timerdelta##label, \
timerstart##label, \
timerstop##label); \
std::cout << \
"TIMING: " << \
timerdelta##label << " ms (" << \
#label << \
")" << std::endl;
#endif
У меня код работает без ошибок. Я не считаю, что это правильное решение. Правильное исправление может заключаться в правильной настройке устройства перед вызовом макроса. Кажется очевидным, что либо создатель макроса не ожидал такого использования, либо не знал об опасности. . Когда разработчик кода ответил на вашу проблему, что они не могут воспроизвести проблему, я предполагаю, что они не тестировали код в системе с несколькими устройствами. Насколько я могу судить, ошибка была бы неизбежна при настройке с несколькими устройствами.