Потоки CUDA не перекрываются

#cuda #cuda-streams

#cuda #cuda-потоки

Вопрос:

У меня есть что-то очень похожее на код:

 int k, no_streams = 4;
cudaStream_t stream[no_streams];
for(k = 0; k < no_streams; k  ) cudaStreamCreate(amp;stream[k]);

cudaMalloc(amp;g_in,  size1*no_streams);
cudaMalloc(amp;g_out, size2*no_streams);

for (k = 0; k < no_streams; k  )
  cudaMemcpyAsync(g_in k*size1/sizeof(float), h_ptr_in[k], size1, cudaMemcpyHostToDevice, stream[k]);

for (k = 0; k < no_streams; k  )
  mykernel<<<dimGrid, dimBlock, 0, stream[k]>>>(g_in k*size1/sizeof(float), g_out k*size2/sizeof(float));

for (k = 0; k < no_streams; k  )
  cudaMemcpyAsync(h_ptr_out[k], g_out k*size2/sizeof(float), size2, cudaMemcpyDeviceToHost, stream[k]);

cudaThreadSynchronize();

cudaFree(g_in);
cudaFree(g_out);
  

‘h_ptr_in’ и ‘h_ptr_out’ представляют собой массивы указателей, выделенных cudaMallocHost (без флагов).

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

Возможно, у меня нет ресурсов для запуска двух ядер (я думаю, что у меня есть), но, по крайней мере, выполнение ядра и копирование должны перекрываться, верно? И если я помещу все 3 (копирование H2D, выполнение ядра, копирование D2H) в один цикл for, ни один из них не перекрывается…

Пожалуйста, ПОМОГИТЕ, что может быть причиной этого?

Я работаю на:

Ubuntu 10.04 x64

Устройство: «GeForce GTX 460» (версия драйвера CUDA: 3.20, версия среды выполнения CUDA: 3.20, номер основной / второстепенной версии CUDA: 2.1, одновременное копирование и выполнение: Да, параллельное выполнение ядра: Да)

Комментарии:

1. Механизм профилирования в CUDA вызывает сериализацию в потоках при некоторых обстоятельствах. Вы не можете использовать профилировщик для оценки перекрытия асинхронных операций API.

2. Спасибо. Есть ли какой-либо другой способ точно узнать, правильно ли выполняется перекрытие? Судя по таймингам, похоже, что нет…

Ответ №1:

Согласно этому сообщению на форумах NVIDIA, профилировщик сериализует потоковую передачу для получения точных данных синхронизации. Если вы считаете, что ваши тайминги отключены, убедитесь, что вы используете события CUDA…

В последнее время я экспериментировал с потоковой передачей и обнаружил, что пример «simpleMultiCopy» из SDK действительно полезен, особенно с соответствующей логикой и синхронизациями.

Ответ №2:

Если вы хотите, чтобы ядра перекрывались с ядрами (параллельными ядрами), вам необходимо использовать CUDA Visual profiler 5.0, который поставляется с CUDA 5.0 Toolkit. Я не думаю, что предыдущие профилировщики способны на это. Также должно отображаться перекрытие ядра и memcpy.

Комментарии:

1. Действительно ли возможно наблюдать перекрытие потоков напрямую с помощью Visual Profiler 5.0? Если да, то каким образом? В настоящее время я использую профилировщик командной строки и импортирую созданный csv-файл в профилировщик, см. Сообщение NVIDIA о перекрывающихся потоках .