Вдруг кто-нибудь из читателей этот вопрос уже проходил?
В CUDA параллельная программа запускается в виде множества тредов. Треды логически группируются в блоки, а блоки – в гриды. Треды внутри одного блока имеют доступ к общей быстрой памяти и могут синхронизироваться, а треды из разных блоков могут общаться только через медленную память и не имеют встроенных средств синхронизации.
При запуске можно указать количество тредов на блок и блоков на грид, причем это количество может быть не только скаляром, а ещё и 2- или 3-мерным вектором.
Физически треды выполняются на thread processor’ах, блоки – на мультипроцессорах (каждый мультипроцессор обычно содержит 8 thread processor’ов, один блок вычислений с плавающей точкой с двойной точностью и быструю общую память, доступную только изнутри этого мультипроцессора).
А грид выполняется на всём GPU, содержащем N мультипроцессоров (например, 10).
Собственно вопрос: если задача по сути линейная (скажем, тупой перебор ключей шифрования), и тредам вообще не нужна синхронизация и обмен данными между собой, то какими следует выбирать размеры блока и грида для достижения максимального быстродействия?
Или где про это можно почитать?
Upd: на первый взгляд логично тредов делать ровно столько, сколько может физически одновременно выполнить GPU: размер блока сделать равным количеству thread processor’ов в мультипроцессоре, а размер грида равным количеству мультипроцессоров.
Но есть ещё перенос расчётных данных из основной системы в GPU и обратно, и я сильно подозреваю, что один перенос большой порции будет быстрее, чем несколько раз меньшими частями. Если это так, то лучше сразу тредов сделать побольше и передать им всем данные за один присест. Но это вызовет накладные расходы на переключение тредов, и хотя декларируется, что в GPU это операция малозатратная, но всё же ненулевая.
Оригинал этой записи. Комментировать можно тут или там.
no subject
no subject
no subject
С конца
1) Перенос большими порциями интегрально наверное быстрее (ну там ~4Gb/sec на хорошей машине, но время на сетап ненулевое). Но ты же можешь таскать данные асинхронно, пока кернел считает одну порцию, подтаскивать-утаскивать другие.
Если время трансфера существенно (относительно счета) - это окупится.
2) Оптимальный размер задачи при прочих равных.
Я даже начал писать, а потом понял, что излагаю 4-й раздел из best practices guide, проще там прочесть
no subject
про cudaMemcpy() сразу говорится, что он синхронный, и даже подчёркивается, что если его использовать для вытаскивания результатов расчёта, то больше никакая синхронизация не нужна. если его запустить после старта ядра, то он отработает не раньше, чем ядро завершится.
2) кажется, я ещё рановато приступил к практическим задачам. таки пошёл дальше читать TFM.
no subject
no subject
no subject
На Макбуке (9400M) просто волшебный эффект.
no subject
no subject
больше всего меня удивило, что на общую скорость приложения существенно влияет способ выделения памяти в хосте, которая потом копируется в девайс.
с обычным malloc'ом получилось медленнее всего, cudaHostAlloc(cudaHostAllocDefault) быстрее, cudaHostAlloc(cudaHostAllocWriteCombined) быстрее всего.
no subject
no subject
а zeroCopy через cudaHostGetDevicePointer() медленнее. хотя логично, что доступ из видеокарты к памяти хоста медленнее, чем к своей собственной.
хотя это должно существенно зависеть от объёмов. у меня данных относительно много, а расчёты относительно простые - двойной md5.
no subject
А система какая, кстати? Винды?
no subject
с выравниванием вряд ли, память выделяется большими пачками, кратными 2 килобайтам (32*64).
да, и что интересно, при разных методах выделения памяти в хосте максимальное быстродействие достигается для разных сочетаний blocks per grid и threads per block.
для malloc: 160x128,
для cudaHostAllocDefault и cudaHostAllocPortable.txt: 480x320
для out-cudaHostAllocMapped.txt: 512x480, и возможно, она не максимальная, я только до 512 блоков на грид проверял.
для cudaHostAllocWriteCombined: 480x288
видимо, копирование данных таки занимает существенную часть от общего времени работы приложения. надо будет померить на досуге.
no subject
А время трансфера померять и асинком его, асинком!
no subject
ну и код ещё есть, куда подправлять :)
no subject
no subject
no subject
а то я за повседневным скриптингом уже почти разучился получать удовольствие от красивого кода :)