Как потоки могут предлагать параллельное выполнение в CUDA?

В документации CUDA упоминается, что если мы используем 2 потока (stream0 и stream1) вот так: мы копируем данные в stream0, затем запускаем первое ядро ​​в stream0, затем восстанавливаем данные с устройства в stream0, а затем те же операции выполняются в потоке1, таким образом, как указано в книге "CUDA на примере 2010", не предлагается параллельное выполнение, но в "примере параллельных ядер" этот метод используется и предлагает параллельное выполнение. Итак, не могли бы вы помочь мне понять разницу между двумя примерами?


person Sara Dev    schedule 27.09.2013    source источник


Ответы (2)


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

https://developer.nvidia.com/content/how-overlap-data-transfers-cuda-cc

person kangshiyin    schedule 27.09.2013
comment
Вы правы, и блог, на который вы ссылаетесь, ясно объясняет различное поведение различных потоковых организаций на разных архитектурах. Я бы сказал, что то, как эта тема представлена ​​в книге CUDA By Example, приведет читателя к выводу, что одно (потоковые чересстрочные асинхронные копии памяти и выполнение ядра) всегда лучше, чем другое (без асинхронных копий памяти и чересстрочной развертки выполнения ядра). . - person Vitality; 27.09.2013

Я просто расширяю ответ Эрика.

В Руководстве по программированию CUDA C приводится пример использования 2 потоков, скажем, stream0 и stream1, для выполнения следующих действий.

СЛУЧАЙ А

memcpyHostToDevice --- stream0
kernel execution   --- stream0
memcpyDeviceToHost --- stream0

memcpyHostToDevice --- stream1
kernel execution   --- stream1
memcpyDeviceToHost --- stream1

Другими словами, сначала выполняются все операции stream0, а затем операции, относящиеся к stream1. Тот же самый пример описан в книге "CUDA By Example", раздел 10.5, но "очевидно" сделан вывод (в "очевидном" противоречии с руководством), что параллелизм таким образом не достигается.

В разделе 10.6 «CUDA By Example» предлагается следующее альтернативное использование потоков.

СЛУЧАЙ Б

memcpyHostToDevice --- stream0
memcpyHostToDevice --- stream1
kernel execution   --- stream0
kernel execution   --- stream1
memcpyDeviceToHost --- stream0
memcpyDeviceToHost --- stream1

Другими словами, операции копирования памяти и выполнения ядра stream0 и stream1 теперь чередуются. В книге показано, как с помощью этого решения достигается параллелизм.

На самом деле, нет никакого противоречия между книгой «CUDA By Example» и руководством по программированию на CUDA C, поскольку обсуждение в книге было проведено с конкретной ссылкой на карту GTX 285, в то время как, как уже указывал Эрик и в цитируемое сообщение в блоге Как перекрыть передачу данных в CUDA C/C++ параллелизм может быть достигнут по-разному на разных архитектурах в результате наличия зависимостей и механизмов копирования.

Например, в блоге рассматриваются две карты: C1060 и C2050. Первый имеет один механизм ядра и один механизм копирования, который может выполнять только одну транзакцию памяти (H2D или D2H) за раз. Последний имеет один механизм ядра и два механизма копирования, которые могут одновременно выполнять две транзакции памяти (H2D и D2H). Что происходит для C1060, имеющего только один механизм копирования, следующее:

СЛУЧАЙ A – C1060 – ОТСУТСТВИЕ ПАРАЛЛЕЛЬНОСТИ

Stream       Kernel engine         Copy engine             Comment

stream0 ----                       memcpyHostToDevice ----
stream0 ---- kernel execution ----                         Depends on previous memcpy
stream0 ----                       memcpyDeviceToHost ---- Depends on previous kernel
stream1 ----                       memcpyHostToDevice ---- 
stream1 ---- kernel execution ----                         Depends on previous memcpy
stream1 ----                       memcpyDeviceToHost ---- Depends on previous kernel

СЛУЧАЙ B – C1060 – ДОСТИГНУТО СОГЛАСИЕ

Stream         Kernel engine           Copy engine               Comment

stream0   ----                         memcpyHostToDevice 0 ----
stream0/1 ---- Kernel execution 0 ---- memcpyHostToDevice 1 ----  
stream0/1 ---- Kernel execution 1 ---- memcpyDeviceToHost 0 ---- 
stream1   ----                         memcpyDeviceToHost 1 ---- 

Что касается C2050 и при рассмотрении случая 3 потоков, в CASE A теперь достигается параллелизм, в отличие от C1060.

СЛУЧАЙ A – C2050 — ДОСТИГНУТО ОДНОРОДНОСТЬ

Stream           Kernel engine           Copy engine H2D           Copy engine D2H

stream0     ----                         memcpyHostToDevice 0 ----
stream0/1   ---- kernel execution 0 ---- memcpyHostToDevice 1 ----                              
stream0/1/2 ---- kernel execution 1 ---- memcpyHostToDevice 2 ---- memcpyDeviceToHost 0
stream0/1/2 ---- kernel execution 2 ----                           memcpyDeviceToHost 1
stream2     ----                                                   memcpyDeviceToHost 2
person Vitality    schedule 27.09.2013