Ответ 1
В общем, вы хотите, чтобы ваши блоки/сетки соответствовали вашим данным и одновременно увеличивали заполняемость, то есть, сколько потоков одновременно активны. Основными факторами, влияющими на занятость, являются использование общей памяти, использование регистров и размер блока потока.
Графический процессор с поддержкой CUDA имеет свои возможности обработки, разделенные на SM (потоковые мультипроцессоры), а количество SM зависит от реальной карты, но здесь мы сосредоточимся на одном SM для простоты (все они ведут себя одинаково), Каждый SM имеет конечное число 32-битных регистров, разделяемую память, максимальное количество активных блоков и максимальное количество активных потоков. Эти числа зависят от CC (вычислительная способность) вашего GPU и могут быть найдены в середине статьи Wikipedia http://en.wikipedia.org/wiki/CUDA.
Прежде всего, размер блока потока всегда должен быть кратным 32, потому что ядра выдают инструкции в warps (32 потока). Например, если у вас размер блока 50 потоков, GPU по-прежнему выдаст команды для 64 потоков, и вы просто будете их расточать.
Во-вторых, прежде чем беспокоиться об общей памяти и регистрах, попробуйте размер блоков на основе максимального количества потоков и блоков, соответствующих вычислительной способности вашей карты. Иногда есть несколько способов сделать это... например, карта CC 3.0 каждый SM может иметь 16 активных блоков и 2048 активных потоков. Это означает, что если у вас есть 128 потоков на блок, вы можете поместить 16 блоков в свой SM, прежде чем достигнуть предела потока 2048. Если вы используете 256 потоков, вы можете поместиться только в 8, но вы все еще используете все доступные потоки и по-прежнему будете иметь полное заполнение. Однако при использовании 64 потоков на блок будет использоваться только 1024 потока при ударе по 16 блокам, поэтому только 50% заполняемости. Если разделяемая память и использование регистров не являются узким местом, это должно быть вашей главной проблемой (кроме ваших размеров данных).
По теме вашей сетки... блоки в вашей сетке распределяются по SM для запуска, а затем остальные блоки помещаются в конвейер. Блоки перемещаются в SM для обработки, как только в этом SM достаточно ресурсов, чтобы взять блок. Другими словами, когда блоки завершены в SM, новые перемещаются. Вы можете сделать аргумент о том, что меньшие блоки (128 вместо 256 в предыдущем примере) могут завершиться быстрее, поскольку особенно медленный блок будет обрабатывать меньше ресурсов, но это очень сильно зависит от кода.
Что касается регистров и разделяемой памяти, посмотрите на следующее, так как это может ограничивать ваше размещение. Общая память ограничена для всего SM, поэтому попробуйте использовать ее в количестве, которое позволяет как можно больше блоков по-прежнему поместиться на SM. То же самое касается использования регистра. Опять же, эти числа зависят от вычислительной способности и могут быть найдены в таблице на странице wikipedia. Удачи!