Как CUDA блокирует/перекосы/потоки на ядра CUDA?

Я использую CUDA в течение нескольких недель, но у меня есть некоторые сомнения в распределении блоков /warps/thread. Я изучаю архитектуру с дидактической точки зрения (университетский проект), поэтому достижение максимальной производительности не является моей проблемой.

Прежде всего, я хотел бы понять, правильно ли я получил эти факты:

  • Программист записывает ядро ​​и организует его выполнение в сетке блоков потоков.

  • Каждый блок назначается поточному мультипроцессору (SM). После назначения он не может перейти на другой SM.

  • Каждый SM разбивает свои собственные блоки на Warps (в настоящее время с максимальным размером 32 потока). Все потоки в warp выполняются одновременно на ресурсах SM.

  • Фактическое выполнение потока выполняется ядрами CUDA, содержащимися в SM. Нет конкретного сопоставления между потоками и ядрами.

  • Если warp содержит 20 потоков, но в настоящее время доступно только 16 ядер, warp не будет работать.

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

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

Правильны ли они?

Теперь у меня есть GeForce 560 Ti, поэтому в соответствии со спецификациями он оснащен 8 SM, каждый из которых содержит 48 ядер CUDA (всего 384 ядра).

Моя цель - убедиться, что каждое ядро ​​архитектуры выполняет ТОЛЬКО инструкции. Предполагая, что мой код не будет требовать больше регистра, чем те, которые доступны в каждом SM, я представил различные подходы:

  • Я создаю 8 блоков по 48 потоков каждый, так что каждый SM имеет 1 блок для выполнения. В этом случае 48 потоков будут выполняться параллельно в SM (используя все 48 ядер, доступных для них)?

  • Есть ли разница, если я запустил 64 блока из 6 потоков? (Предполагая, что они будут отображаться равномерно среди SM)

  • Если я "погружаю" графический процессор в запланированную работу (например, 1024 кадра из 1024 потоков каждый), разумно предположить, что все ядра будут использоваться в определенной точке и будут выполнять те же вычислений (при условии, что нити никогда не останавливаются)?

  • Есть ли способ проверить эти ситуации с помощью профилировщика?

  • Есть ли ссылки на этот материал? Я прочитал руководство по программированию CUDA и главы, посвященные аппаратной архитектуре в "Программирование многопараллельных процессоров" и "Разработка и разработка приложений CUDA"; но я не мог получить точный ответ.

Ответ 1

Две лучшие ссылки:

Я постараюсь ответить на каждый из ваших вопросов.

Программист делит работу на потоки, потоки на блоки потоков и блоки потоков на сетки. Распределитель вычислений распределяет блоки потоков потоковым мультипроцессорам (SMs). Когда блок потока распределяется на SM, выделяются ресурсы для блока потока (перекосы и разделяемая память), а потоки делятся на группы из 32 нитей, называемых искажениями. После выделения основы он называется активной деформацией. Два планировщика деформации выбирают два активных перекоса за цикл и отправляют основы на исполнительные блоки. Подробнее о исполнительных устройствах и диспетчеризации см. 1 p.7-10 и 2.

4. Существует сопоставление между laneid (индекс нитей в основе) и ядром.

5. Если варп содержит менее 32 потоков, он будет в большинстве случаев выполняться так же, как если бы он имел 32 потока. У Warps может быть меньше 32 активных потоков по нескольким причинам: количество потоков на блок не делится на 32, программа выполняет расходящийся блок, поэтому потоки, которые не занимают текущий путь, помечены как неактивные или поток из warp завершен.

6. Блок потока будет разделен на   WarpsPerBlock = (ThreadsPerBlock + WarpSize - 1)/WarpSize Для планировщиков warp нет необходимости выбирать два искажения из одного и того же блока потоков.

7. Блок выполнения не останавливается при работе с памятью. Если ресурс недоступен, когда команда готова к отправке, инструкция будет отправлена ​​снова в будущем, когда ресурс будет доступен. Деформации могут останавливаться на барьерах, операциях с памятью, работе с текстурой, зависимостях данных... Замедленная деформация не может быть выбрана планировщиком варпа. На Ферми полезно иметь по меньшей мере 2 подходящих искажения за такт, чтобы планировщик warp мог выдать инструкцию.

См. ссылку 2 для различий между GTX480 и GTX560.

Если вы прочитаете справочный материал (несколько минут), я думаю, вы обнаружите, что ваша цель не имеет смысла. Я постараюсь ответить на ваши вопросы.

1. Если вы запустили ядро ​​< < 8, 48 → > , вы получите 8 блоков с двумя перекосами из 32 и 16 потоков. Нет гарантии, что эти 8 блоков будут назначены различным SM. Если для SM назначены 2 блока, то возможно, что каждый планировщик деформаций может выбрать деформацию и выполнить деформацию. Вы будете использовать только 32 из 48 ядер.

2. Существует большая разница между 8 блоками из 48 потоков и 64 блоками из 6 потоков. Предположим, что ваше ядро ​​не имеет расхождения, и каждый поток выполняет 10 команд.

  • 8 блоков с 48 потоками = 16 бит * 10 инструкций = 160 инструкций
  • 64 блока с 6 потоками = 64 перекоса * 10 инструкций = 640 инструкций

Для обеспечения оптимальной эффективности разделение работы должно быть кратным 32 нитям. Аппаратное обеспечение не будет сливать потоки из разных перекосов.

3. GTX560 может иметь 8 SM * 8 блоков = 64 блока за раз или 8 SM * 48 warps = 512 бит, если ядро ​​не максимизирует регистры или разделяемую память. В любой момент времени часть работы будет активна на SM. Каждый SM имеет несколько исполнительных блоков (больше, чем CUDA). Какие ресурсы используются в любой момент времени, зависит от планировщиков warp и комбинации команд приложения. Если вы не выполняете операции TEX, то единицы TEX будут простаивать. Если вы не выполняете особую операцию с плавающей запятой, блоки SUFU будут работать.

4. Параллельный Nsight и Visual Profiler показывают

а. выполненный IPC

б. выпущен IPC

с. активные перекосы за активный цикл

д. допустимые перекосы за активный цикл (только Nsight)

е. warp stall причинам (только Nsight)

ф. активных потоков на каждую выполненную инструкцию

Профилировщик не показывает процент использования любого из исполнительных блоков. Для GTX560 приблизительная оценка будет IssuedIPC/MaxIPC. Для MaxIPC GF100 (GTX480) - 2 GF10x (GTX560) - 4, но цель - 3 - лучшая цель.

Ответ 2

"E. Если warp содержит 20 потоков, но в настоящее время доступно только 16 ядер, деформация не будет работать."

неверно. Вы путаете ядра в обычном понимании (также используемом в ЦП) - количество "многопроцессоров" в графическом процессоре, в которых говорят ядра в маркетинге nVIDIA ( "наша карта имеет тысячи ядер CUDA" ).

Сама деформация может быть запланирована только на одном ядре (= многопроцессор) и может одновременно запускать до 32 потоков; он не может использовать больше одного ядра.

Число "48 перекосов" - это максимальное количество активных перекосов (деформации, которые могут быть выбраны для работы в следующем цикле, в любой заданный цикл) на каждый процессор, на графических процессорах nVIDIA с вычислительной способностью 2.x; и это число соответствует 1536 = 48 x 32 потоков.

Ответ на основе этот веб-семинар