CUDA определяет streamи на блок, блоки на каждую сетку
Я новичок в парадигме CUDA. Мой вопрос заключается в определении количества streamов на блок и блоков в сетке. Входит ли в это искусство и испытание? Я обнаружил, что многие примеры имеют, по-видимому, произвольное число, выбранное для этих вещей.
Я рассматриваю проблему, когда я мог бы передавать матрицы – любого размера – методу умножения. Таким образом, каждый элемент C (как в C = A * B) будет вычисляться одним streamом. Как бы вы определили streamи / блок, блоки / сетку в этом случае?
- Как я могу заставить свой ноутбук использовать NVIDIA вместо Intel?
- Понимание размеров сетки CUDA, размеров блоков и организации streamов (простое объяснение)
- Сообщение об ошибке: не удается найти или открыть файл PDB
- Принудительное использование графического процессора NVIDIA в ноутбуках Optimus
- Моя карта NVIDIA постоянно ломалась сама по себе? Или я могу это исправить?
- nvidia-smi Неустойчивое использование GPU-использования?
- Панель управления nVidia сбрасывает настройку гаммы после перезапуска
- Можно ли использовать графический процессор nVidia для рендеринга графики, если монитор подключен к видеопорту материнской платы?
- Программа CUDA приводит к сбою драйвера nvidia
- Как управляется память CUDA?
- Размытое / нечеткое / удвоенное изображение
- Ужасная производительность перерисовки DataGridView на одном из моих двух экранов
- 128-битное целое число на cuda?
В общем, вы хотите, чтобы ваши блоки / сетки соответствовали вашим данным и одновременно увеличивали занятость, то есть, сколько streamов одновременно активны. Основными факторами, влияющими на занятость, являются использование общей памяти, использование регистров и размер блока streamа.
Графический процессор с поддержкой CUDA имеет свои возможности обработки, разделенные на SM (streamовые мультипроцессоры), а количество SM зависит от реальной карты, но здесь мы сосредоточимся на одном SM для простоты (все они ведут себя одинаково). Каждый SM имеет конечное число 32-битных регистров, разделяемую память, максимальное количество активных блоков и максимальное количество активных streamов. Эти числа зависят от CC (вычислительная способность) вашего GPU и могут быть найдены в середине статьи Википедии http://en.wikipedia.org/wiki/CUDA .
Прежде всего, размер блока streamа всегда должен быть кратным 32, потому что ядра выдают инструкции в warps (32 streamа). Например, если у вас размер блока 50 streamов, GPU по-прежнему выдаст команды для 64 streamов, и вы просто будете их тратить.
Во-вторых, прежде чем беспокоиться об общей памяти и регистрах, попробуйте размер блоков на основе максимального количества streamов и блоков, которые соответствуют вычислительной способности вашей карты. Иногда есть несколько способов сделать это … например, карта CC 3.0 каждый SM может иметь 16 активных блоков и 2048 активных streamов. Это означает, что если у вас есть 128 streamов на блок, вы можете поместить 16 блоков в свой SM, прежде чем достигнуть предела streamа 2048. Если вы используете 256 streamов, вы можете поместиться только в 8, но вы все еще используете все доступные streamи и по-прежнему будете иметь полное заполнение. Однако при использовании 64 streamов на блок будет использоваться только 1024 streamа при ударе по 16 блокам, поэтому только 50% заполняемости. Если разделяемая память и использование регистров не являются узким местом, это должно быть вашей главной проблемой (кроме ваших размеров данных).
По теме вашей сетки … блоки в вашей сетке распределяются по SM для запуска, а затем остальные блоки помещаются в конвейер. Блоки перемещаются в SM для обработки, как только в этом SM достаточно ресурсов, чтобы взять блок. Другими словами, когда блоки завершены в SM, новые перемещаются. Вы можете сделать аргумент о том, что меньшие блоки (128 вместо 256 в предыдущем примере) могут завершиться быстрее, поскольку особенно медленный блок будет обрабатывать меньше ресурсов, но это очень сильно зависит от кода.
Что касается регистров и разделяемой памяти, посмотрите на следующее, так как это может ограничивать ваше размещение. Общая память ограничена для всего SM, поэтому попробуйте использовать ее в количестве, которое позволяет как можно больше блоков по-прежнему поместиться на SM. То же самое касается использования регистра. Опять же, эти числа зависят от вычислительной способности и могут быть найдены в таблице на странице wikipedia. Удачи!
http://developer.download.nvidia.com/compute/cuda/CUDA_Occupancy_calculator.xls
Калькулятор занятости CUDA позволяет вычислить многопроцессорное заполнение GPU данным kernelм CUDA. Многопроцессорное заполнение – это отношение активных перекосов к максимальному числу перекосов, поддерживаемых на многопроцессорном графическом процессоре. Каждый мультипроцессор на устройстве имеет набор N регистров, доступных для использования streamами программ CUDA. Эти регистры являются общим ресурсом, который распределяется между блоками streamов, выполняемыми на мультипроцессоре. Компилятор CUDA пытается минимизировать использование регистров, чтобы максимизировать количество блоков streamов, которые могут быть активны в машине одновременно. Если программа пытается запустить kernel, для которого регистры использовались в каждом streamе, размер блока streamа больше N, запуск не будет выполнен …
За редким исключением вы должны использовать постоянное количество streamов для каждого блока. Затем количество блоков на сетку определяется размером проблемы, например размерами матрицы в случае матричного умножения.
Выбор количества streamов на блок очень сложный. Большинство алгоритмов CUDA допускают широкий диапазон возможностей, и выбор основан на том, что делает kernel работать наиболее эффективно. Это почти всегда кратно 32 и по меньшей мере 64 из-за того, как работает оборудование планирования streamов. Хорошим выбором для первой попытки является 128 или 256.
Вам также необходимо учитывать общую память, поскольку streamи одного и того же блока могут обращаться к одной и той же общей памяти. Если вы разрабатываете что-то, что требует много разделяемой памяти, то больше streamов на блок может быть выгодным.
Например, с точки зрения переключения контекста любое число из 32 работает одинаково. Таким образом, для случая 1D запуск 1 блока с 64 streamами или 2 блока с 32 streamами не имеет никакого значения для доступа к глобальной памяти. Однако, если проблема под рукой, естественно, разлагается на один вектор длиной 64, тогда первый вариант будет лучше (меньше накладных расходов памяти, каждый stream может получить доступ к одной и той же общей памяти), чем второй.