CUDA определяет потоки на блок, блоки на сетку

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

Я рассматриваю проблему, при которой я мог бы передавать матрицы любого размера в метод умножения. Таким образом, каждый элемент C (как в C = A * B) будет вычисляться одним потоком. Как бы вы в этом случае определяли потоки / блок, блоки / сетку?


person dnbwise    schedule 08.12.2010    source источник


Ответы (4)


В общем, вы хотите, чтобы размер ваших блоков / сетки соответствовал вашим данным и одновременно максимизировал занятость, то есть количество потоков, активных одновременно. Основными факторами, влияющими на занятость, являются использование разделяемой памяти, использование регистров и размер блока потока.

Графический процессор с поддержкой CUDA имеет свои возможности обработки, разделенные на SM (потоковые мультипроцессоры), а количество SM зависит от фактической карты, но здесь мы сосредоточимся на одном SM для простоты (все они ведут себя одинаково). Каждый SM имеет конечное количество 32-битных регистров, разделяемую память, максимальное количество активных блоков И максимальное количество активных потоков. Эти числа зависят от CC (вычислительной мощности) вашего графического процессора и могут быть найдены в середине статьи Википедии http://en.wikipedia.org/wiki/CUDA.

Прежде всего, размер блока потока всегда должен быть кратен 32, потому что ядра выдают инструкции в виде перекосов (32 потока). Например, если у вас размер блока в 50 потоков, графический процессор по-прежнему будет выдавать команды 64 потокам, и вы просто их тратите.

Во-вторых, прежде чем беспокоиться об общей памяти и регистрах, попробуйте размер ваших блоков на основе максимального количества потоков и блоков, которые соответствуют вычислительным возможностям вашей карты. Иногда есть несколько способов сделать это ... например, карта CC 3.0 на каждом SM может иметь 16 активных блоков и 2048 активных потоков. Это означает, что если у вас 128 потоков на блок, вы можете уместить в SM 16 блоков, прежде чем достигнете предела в 2048 потоков. Если вы используете 256 потоков, вы можете уместить только 8, но вы по-прежнему используете все доступные потоки и по-прежнему будете иметь полную занятость. Однако при использовании 64 потоков на блок будет использоваться только 1024 потока при достижении предела в 16 блоков, поэтому заполнение только 50%. Если использование разделяемой памяти и регистров не является узким местом, это должно быть вашей основной проблемой (кроме размеров данных).

Что касается вашей сетки ... блоки в вашей сетке для начала распределяются по SM, а затем оставшиеся блоки помещаются в конвейер. Блоки перемещаются в SM для обработки, как только в этом SM будет достаточно ресурсов для приема блока. Другими словами, когда блоки завершаются в SM, новые перемещаются внутрь. Вы можете привести аргумент, что блоки меньшего размера (128 вместо 256 в предыдущем примере) могут выполняться быстрее, поскольку особенно медленный блок потребляет меньше ресурсов, но это очень сильно зависит от кода.

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

person underpickled    schedule 16.10.2012
comment
Почему мы не можем рассчитывать блоки / потоки, используя возможности устройства? Предположим, у меня есть устройство с возможностями 2.1 (GT 520), поэтому оно имеет 48 SM, 8 блоков в каждом и 1024 потока на блок. Я не могу понять, извините, если мой вопрос глупый. - person greg; 18.07.2013
comment
Есть ли способ определить максимальное количество потоков на блок программно, используя некоторый CUDA API? - person Serge Rogatch; 28.05.2016
comment
cudaDeviceProp prop; cudaGetDeviceProperties( &prop, 0); docs.nvidia.com/cuda/cuda-runtime-api/structcudaDevicePro .html - person Felix B.; 15.05.2020
comment
@underpickled Вы говорите, что блоки в вашей сетке распределены по SM для начала. Это что-то, что должен делать программист, или графический процессор отвечает за распространение блоков по SM? В случае последнего: если я запускаю ядро ​​на 32 блоках при использовании оборудования с 32 SM, есть ли гарантия, что каждый SM получит один блок? - person Silicomancer; 19.07.2021

https://docs.nvidia.com/cuda/cuda-occupancy-calculator/index.html

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

person jmilloy    schedule 09.12.2010
comment
404 Не Найдено. developer.download.nvidia.com/compute/cuda/ 3_2_prod / sdk / docs / вроде работает. Также онлайн-версия xmartlabs.github.io/cuda-calculator - person Tõnu Samuel; 15.08.2019

За редкими исключениями следует использовать постоянное количество потоков на блок. Количество блоков в сетке затем определяется размером задачи, например размерами матрицы в случае умножения матриц.

Выбор количества потоков на блок очень сложен. Большинство алгоритмов CUDA допускают широкий спектр возможностей, и выбор основан на том, что обеспечивает наиболее эффективную работу ядра. Это почти всегда кратно 32 и не менее 64 из-за того, как работает оборудование для планирования потоков. Хороший выбор для первой попытки - 128 или 256.

person Heatsink    schedule 08.12.2010
comment
Не могли бы вы лучше объяснить свои рассуждения о постоянных потоках на блок? (Или даже ссылку на соответствующую статью). Большое спасибо, - person Joseph Franciscus; 09.01.2018

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

Например, с точки зрения переключения контекста любое кратное 32 работает одинаково. Таким образом, в случае 1D запуск 1 блока с 64 потоками или 2 блоков с 32 потоками в каждом не имеет значения для доступа к глобальной памяти. Однако, если рассматриваемая проблема естественным образом распадается на один вектор длиной 64, тогда первый вариант будет лучше (меньше накладных расходов на память, каждый поток может получить доступ к одной и той же разделяемой памяти), чем второй.

person ely    schedule 08.11.2011