Одновременное выполнение ядра CUDA с несколькими ядрами на поток - PullRequest
6 голосов
/ 16 февраля 2012

Использование разных потоков для ядер CUDA делает возможным параллельное выполнение ядра.Следовательно, n ядра в n потоках теоретически могут работать одновременно, если они вписываются в аппаратное обеспечение, верно?

Теперь я сталкиваюсь со следующей проблемой: нет n отдельных ядер, но n*m где m ядра должны быть выполнены по порядку.Например, n=2 и m=3 приведут к следующей схеме выполнения с потоками:

Stream 1: <<<Kernel 0.1>>> <<<Kernel 1.1>>> <<<Kernel 2.1>>>
Stream 2: <<<Kernel 0.2>>> <<<Kernel 1.2>>> <<<Kernel 2.2>>>

Мое наивное предположение состоит в том, что ядра x.0 и y.1 должны выполняться одновременно (с теоретической точки зрения).зрения) или, по крайней мере, не последовательно (с практической точки зрения).Но мои измерения показывают, что это не так, и кажется, что выполняется последовательное выполнение (то есть K0.0, K1.0, K2.0, K0.1, K1.1, K2.1).Ядра сами по себе очень малы, поэтому параллельное выполнение не должно быть проблемой.

Теперь мой подход заключается в том, чтобы выполнить своего рода диспетчеризацию, чтобы убедиться, что ядра поставлены в очередь с чередованием в планировщикна ГПУ.Но когда имеешь дело с большим количеством потоков / ядер, это может принести больше вреда, чем пользы.

Хорошо, прямо к сути: какой подход (или, по крайней мере, другой) подход к решению этой ситуации?

Редактировать: Измерения выполняются с использованием событий CUDA.Я измерил время, необходимое для полного решения вычислений, т.е. графический процессор должен вычислять все ядра n * m.Предположение таково: при полностью параллельном выполнении ядра время выполнения примерно (в идеале) 1/n времени, необходимого для выполнения всех ядер по порядку, при этом должно быть возможно, что два или более ядра могут выполняться одновременно.Я гарантирую это, используя только два отдельных потока прямо сейчас.

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

Loop: i = 0 to m
    EnqueueKernel(Kernel i.1, Stream 1)
    EnqueueKernel(Kernel i.2, Stream 2)

против

Loop: i = 1 to n
    Loop: j = 0 to m
        EnqueueKernel(Kernel j.i, Stream i)

Последнее приводит к увеличению времени выполнения.

Правка # 2: Изменены номера потоков, чтобы они начинались с 1 (вместо 0, см. комментарииниже).

Редактировать # 3: Аппаратное обеспечение - NVIDIA Tesla M2090 (т. е. Fermi, вычислительная мощность 2.0)

1 Ответ

5 голосов
/ 20 февраля 2012

На оборудовании Fermi (также известном как Compute Capability 2.0) лучше чередовать запуск ядра в несколько потоков, а не запускать все ядра в один поток, затем в следующий поток и т. Д. Это связано с тем, что оборудование может немедленно запускать ядра для разных потоков. потоки, если есть достаточные ресурсы, тогда как, если последующие запуски находятся в том же потоке, часто вводится задержка, уменьшая параллелизм Это причина того, что ваш первый подход работает лучше, и именно этот подход вы должны выбрать.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...