Для генерации кода GPU, основной механизм для создания CUDA® ядра при помощи for
-циклы. Способ записи циклов в MATLAB® код оказывает значительное влияние на количество созданных ядер, а также на эффективность сгенерированного кода. Когда вы генерируете код GPU, проверьте диагностический отчет, чтобы увидеть, есть ли у вашего сегмента цикла Loop not parallelized
извещения. Вызовы функций MATLAB в вашем коде также могут иметь for
-циклы, которые содержат эти уведомления. Чтобы получить максимальную эффективность, вы хотите убедиться, что вычислительные интенсивные сегменты цикла в вашем коде сопоставлены с ядрами и выполняются параллельно. Следующие рекомендации помогают вам в достижении этой цели и создании эффективных ядер CUDA.
Рассмотрим функцию, которая вложила for
-циклы.
function y = foo(x) ... for i1 = 1:N1 for i2 = 1:N2 for i3 = 1:N3 for i4 = 1:N4 ... end end end end
Предположим, что один из промежуточных циклов i3
не поддается параллелизации. Когда выполняет анализ цикла, чтобы создать ядра, GPU Coder™, что он рассматривает только самые внешние параллельные циклы i1,i2
и создает ядро с размерностями внешних контуров N1,N2
. Циклы i3,i4
находятся в теле ядра и выполняются последовательно. Однако, если самое сокровенное i4
является большим (итерация), тогда лучшая эффективность может быть достигнута путем создания ядер для самого внутреннего цикла.
Существует три способа, которыми можно параллелизировать самый внутренний цикл:
Перепишите код так, чтобы самый внутренний сегмент кода не находился во вложенном цикле.
Если размер итерации внешнего контура невелик, присоедините цикл к coder.unroll
функция. Эта функция отменяет перемещение for
-loop путем создания копии тела цикла для каждой итерации цикла. Для получения дополнительной информации см. coder.unroll
.
function y = foo(x) ... for i1 = coder.unroll(1:N1) ... end
Сделайте размерность внешнего контура динамическим. Таким образом, анализ параллельного цикла прекращается на внешнем контуре, в то время как он преуспевает на внутренних циклах.
function y = foo(x,N1) ... for i1 = 1:N1 ... end
Циклы с пропуском не поддерживаются.
while (i < N) ... ... if (cond2) ... ... break; end end
Удалите пропуски путем создания защитной переменной и условной.
cond = true; while (i< N) if(cond) ... ... if(cond2) cond = false; end end end
Экстракция ядра использует анализ зависимости параллельного цикла. Существуют случаи, когда анализ зависимости цикла не может обнаружить параллель для цикла. The coder.gpu.kernel
позволяет GPU Coder переопределять анализ зависимостей и форсировать создание ядра. Предупреждение предназначено для пользователя, чтобы убедиться, что цикл является циклом «for-all» без межитерации зависимостей.
Использовать coder.gpu.kernel
прагма явно на каждом из циклов for -.
GPU Coder можете не создавать ядра, когда для доступа к элементам массива используется логическое индексирование.
i = (mag ~= 0); vx(i) = vx(i)./mag(i); vy(i) = vy(i)./mag(i);
Перепишите код, используя тело цикла и охраняя с соответствующим условным.
for i = 1:numel(mag) if (mag(i) ~= 0) vx(i) = vx(i)./mag(i); vy(i) = vy(i)./mag(i); end end
Использование неподдерживаемых функций, прагм кодера, функций тулбокса и т.д. внутри цикла препятствует тому, чтобы они стали ядром.
Попробуйте переписать неподдерживаемые функции с помощью чистого MATLAB.
Если меньшие петли в вложении цикла являются внешними большинством циклов, то ядро может быть создано с просто подмножеством циклов в вложении. Если алгоритм позволяет это, всегда помещайте самые большие циклы в самое внешнее вложение.
Перепишите цикл, вложенную в большие циклы, как внешние контуры.