Оптимизированные ядра, работающие на AMD GCN OpenCL, работают только с ~1024 байтами за раз?
Я начинаю разрабатывать свою первую серьезную программу OpenCL и хочу убедиться, что понимаю, как настроен мой AMD R9 290x. Архитектура GCN 2.0. Так что я просто скажу, что я понимаю, и, надеюсь, кто-то там скажет мне, где я прав или нет?
Мне кажется, что основной проблемой оптимизированных ядер является связанная с памятью производительность. Я действительно не хочу делать "преждевременную" оптимизацию здесь, но кажется, что, по крайней мере, думать о памяти очень важно для кода OpenCL в целом. (См. Сортировка с помощью графических процессоров: опрос (Дмитрий И. Архипов + другие))
Согласно руководству по оптимизации AMD, каждый векторный модуль может запускать 64 рабочих элемента каждые 4 часа, и каждый рабочий элемент имеет доступ к 256 32-битным vGPR. По сути, данные __private (пытается) хранятся в vGPR.
Это приводит к 1024 "легким" регистрам доступа для ядер OpenCL.
Похоже, что LDS (он же __local) может использоваться в качестве эффективного хранилища для ядер OpenCL, но их основной конструкцией, по-видимому, является передача данных через рабочую группу. Поскольку 64 КБ вычислительного блока распределяются между 4-векторными блоками (каждый из которых в идеале имеет по крайней мере 1 волновой фронт из 64 рабочих элементов), для каждого рабочего элемента может быть выделено не более 256 байт пространства LDS. чтобы система работала как можно шире.
Таким образом, при некотором осторожном распределении переменных __local и __private создается впечатление, что для каждого рабочего элемента доступно 1280 байтов быстрого доступа. Я предполагаю, что кэш L1 предоставляет еще 16 КБ (что составляет всего 64 байта на рабочий элемент), но это потребует некоторого тщательного жонглирования. Кроме того, кэш L1 также содержит код / инструкции и не может быть использован для данных. Пространство "__constant", по-видимому, фактически является пространством L1, с некоторой магией "мультиплексирования", которая может произойти, если волновой фронт синхронизируется с тем же индексом.
Ни один из вышеперечисленных расчетов не учитывает теоретические 10-волновые фронты на векторную единицу (которые, похоже, разделяют vGPR). Если бы R9 290x на самом деле выполнял одновременно 40-волновые фронты, он использовал бы только 100-байтовую (25-vGPR на рабочий элемент) оперативной памяти.
Итак... это правильное понимание того, сколько "быстрой" памяти получает каждый рабочий элемент в устройстве GCN, таком как R9 290x? Если мы рассматриваем пространства vGPR, L1 и LDS как совокупность "быстрого" хранилища, с которым R9 290x может работать, мы только смотрим на пространство 1024 (vGPR) + 64 (L1) + 256 (LDS) для работы с.
Я понимаю, что ядра могут обращаться к глобальной памяти (~4 ГБ на типичном R9 290x, что примерно ~1 МБ на рабочий элемент). Поскольку глобальная память на GPU по-прежнему является высокопараллельной памятью GDDR5, я ожидаю, что она будет довольно быстрой, но все же на несколько медленнее, чем пространство L1 / vGPRs / LDS. Поэтому я ожидаю, что оптимальные программы стараются избегать использования глобальной оперативной памяти, когда им это не нужно.