Этот ответ состоит из двух частей (я его написал). Одну часть легко определить количественно, другую - более эмпирически.
Аппаратные ограничения:
Это легко измерить количественно. В приложении F к текущему руководству по программированию CUDA перечислено несколько жестких ограничений, которые ограничивают количество потоков на блок, которое может иметь запуск ядра. Если вы превысите любое из этих значений, ваше ядро никогда не запустится. Их можно грубо резюмировать следующим образом:
- В каждом блоке не может быть более 512/1024 потоков ( Compute Capability 1.x или 2.x и новее соответственно)
- Максимальные размеры каждого блока ограничены [512,512,64] / [1024,1024,64] (для вычислений 1.x / 2.x или новее).
- Каждый блок не может занимать более 8k / 16k / 32k / 64k / 32k / 64k / 32k / 64k / 32k / 64k регистров в сумме (вычисление 1.0,1.1 / 1.2,1.3 / 2.x- / 3.0 / 3.2 / 3.5-5.2 / 5.3 / 6-6.1 / 6.2 / 7.0)
- Каждый блок не может использовать более 16/48/96 КБ общей памяти (Compute 1.x / 2.x-6.2 / 7.0)
Если вы останетесь в этих пределах, любое ядро, которое вы сможете успешно скомпилировать, запустится без ошибок.
Настройка производительности:
Это эмпирическая часть. Количество потоков на блок, которое вы выбираете в рамках аппаратных ограничений, описанных выше, может и действительно влияет на производительность кода, выполняемого на оборудовании. Каждый код будет вести себя по-разному, и единственный реальный способ его количественно оценить - это тщательный сравнительный анализ и профилирование. Но, опять же, очень грубо резюмировал:
- Количество потоков на блок должно быть кратным размеру деформации, который равен 32 на всем текущем оборудовании.
- Каждый потоковый многопроцессорный блок на графическом процессоре должен иметь достаточно активных деформаций, чтобы в достаточной мере скрыть все различные задержки в памяти и конвейере команд архитектуры и достичь максимальной пропускной способности. Ортодоксальный подход здесь - попытаться достичь оптимальной загрузки оборудования (о чем говорит ответ Роджера Даля ).
Второй момент - это огромная тема, и я сомневаюсь, что кто-то попытается охватить ее в одном ответе StackOverflow. Есть люди, пишущие кандидатские диссертации по количественному анализу аспектов проблемы (см. Эту презентацию Василия Волкова из Калифорнийского университета в Беркли и эту статью Генри Вонга из Университета Торонто, где можно увидеть, насколько сложен этот вопрос на самом деле).
На начальном уровне вы должны в основном знать, что выбранный вами размер блока (в пределах диапазона допустимых размеров блока, определенного указанными выше ограничениями) может и действительно влияет на скорость выполнения вашего кода, но это зависит от оборудования. у вас есть и код, который вы используете. Путем тестирования вы, вероятно, обнаружите, что у большинства нетривиальных кодов есть «золотая середина» в диапазоне 128-512 потоков на каждый блок, но с вашей стороны потребуется некоторый анализ, чтобы найти, где это. Хорошая новость заключается в том, что, поскольку вы работаете с размерами, кратными размеру деформации, пространство поиска очень ограничено, и лучшую конфигурацию для данного фрагмента кода относительно легко найти.
В приведенных выше ответах показано, как размер блока может повлиять на производительность, и предлагается общая эвристика для его выбора, основанная на максимизации занятости. Не желая , чтобы обеспечить в критерий выбора размера блока, то стоило бы отметить , что CUDA 6.5 (сейчас в Release Candidate версии) включает в себя несколько новых функций во время выполнения , чтобы помочь в расчетах занятости и конфигурации запуска, см
Совет CUDA Pro: API занятости упрощает конфигурацию запуска
Одна из полезных функций -
cudaOccupancyMaxPotentialBlockSize
эвристическое вычисление размера блока, обеспечивающего максимальную занятость. Значения, предоставленные этой функцией, могут затем использоваться в качестве отправной точки ручной оптимизации параметров запуска. Ниже приведен небольшой пример.РЕДАКТИРОВАТЬ
Объект
cudaOccupancyMaxPotentialBlockSize
определяется вcuda_runtime.h
файле и определяется следующим образом:Значения параметров следующие
Обратите внимание, что, начиная с CUDA 6.5, необходимо вычислять собственные размеры 2D / 3D-блока из размера 1D-блока, предложенного API.
Также обратите внимание, что API драйвера CUDA содержит функционально эквивалентные API для расчета занятости, поэтому его можно использовать
cuOccupancyMaxPotentialBlockSize
в коде API драйвера таким же образом, как показано для API среды выполнения в приведенном выше примере.источник
Размер блока обычно выбирается так, чтобы максимально «заполнить». Для получения дополнительной информации выполните поиск по CUDA Occupancy. В частности, см. Таблицу CUDA Occupancy Calculator.
источник