В этом примере показано, как сгенерировать ядра CUDA® для операций типа шаблона путем реализации "Игры Жизни" Джоном Х. Конуэем.
"Игра Жизни" является нулевым проигрывателем cellular automaton игра, которая состоит из набора ячеек (population) в прямоугольной сетке (universe). Ячейки развиваются на шагах дискретного времени, известных как generations. Набор математических правил применился к ячейкам, и его соседи управляют своей жизнью, смертью и воспроизведением. Эта "Игра Жизни" реализация основана на примере, обеспеченном в электронной книге Эксперименты в MATLAB Кливом Moler. Это следует нескольким простым правилам:
Ячейки располагаются в 2D сетке
На каждом шаге живучесть восьми самых близких соседей каждой ячейки определяет свою судьбу
Любая ячейка точно с тремя живыми соседями оживает на следующем шаге
Живая ячейка точно с двумя живыми соседями остается живой на следующем шаге
Все другие ячейки (включая тех больше чем с тремя соседями) умирают на следующем шаге или остаются пустыми
Вот некоторые примеры того, как обновляется ячейка:

Много операций над массивами могут быть выражены как stencil операция, где каждый элемент выходного массива зависит от небольшой области входного массива. Шаблон в показанном примере поэтому 3x3 область вокруг каждой ячейки. Конечные разности, свертка, медианная фильтрация и методы конечных элементов являются примерами других операций, которые может выполнить обработка шаблона.
CUDA включил NVIDIA®, графический процессор с вычисляет возможность 3.2 или выше.
NVIDIA инструментарий CUDA.
Переменные окружения для компиляторов и библиотек. Для получения информации о поддерживаемых версиях компиляторов и библиотек, смотрите Сторонние продукты. Для подготовки переменных окружения смотрите Подготовку Необходимых как условие продуктов.
Используйте coder.checkGpuInstall функционируйте и проверьте, что компиляторы и библиотеки, необходимые для выполнения этого примера, настраиваются правильно.
envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);
Будучи нулевым проигрывателем, эволюция игры определяется ее начальным состоянием. В данном примере начальная генеральная совокупность ячеек создается на двумерной сетке примерно с 25% живых местоположений.
gridSize = 500; numGenerations = 100; initialGrid = (rand(gridSize,gridSize) > .75); % Draw the initial grid imagesc(initialGrid); colormap([1 1 1;0 0.5 0]); title('Initial Grid');

Функция gameoflife_orig.m является полностью векторизованной реализацией "Игры Жизни". Функция обновляет все ячейки на сетке в одной передаче на генерацию.
type gameoflife_orig
%% MATLAB vectorized implementation
function grid = gameoflife_orig(initialGrid)
numGenerations = 100;
grid = initialGrid;
[gridSize,~] = size(initialGrid);
% Loop through each generation updating the grid and displaying it
for generation = 1:numGenerations
grid = updateGrid(grid, gridSize);
imagesc(grid);
colormap([1 1 1;0 0.5 0]);
title(['Grid at Iteration ',num2str(generation)]);
drawnow;
end
function X = updateGrid(X, N)
% Index vectors increase or decrease the centered index by one
% thereby accessing neighbors to the left,right,up,down
p = [1 1:N-1];
q = [2:N N];
% Count how many of the eight neighbors are alive.
neighbors = X(:,p) + X(:,q) + X(p,:) + X(q,:) + ...
X(p,p) + X(q,q) + X(p,q) + X(q,p);
% A live cell with two live neighbors, or any cell with
% three live neighbors, is alive at the next step.
X = (X & (neighbors == 2)) | (neighbors == 3);
end
end
Теперь играйте в игру путем вызова gameoflife_orig функция с начальной генеральной совокупностью. Игра выполняет итерации посредством 100 поколений и отображает население при каждой генерации.
gameoflife_orig(initialGrid);

Рассмотрение вычислений в updateGrid функция, очевидно, что те же операции применяются в каждом местоположении сетки независимо. Однако каждая ячейка должна знать о своих восьми соседях. Модифицированная функция gameoflife_stencil.m использует gpucoder.stencilKernel прагма, чтобы вычислить 3x3 область вокруг каждой ячейки. Реализация GPU Coder™ ядра шаблона, вычисляет один элемент сетки в каждом потоке и использует общую память, чтобы улучшить пропускную способность памяти и местность данных.
type gameoflife_stencil
function grid = gameoflife_stencil(initialGrid) %#codegen
numGenerations = 100;
grid = initialGrid;
% Loop through each generation updating the grid
for generation = 1:numGenerations
grid = gpucoder.stencilKernel(@updateElem, grid, [3,3], 'same');
end
end
function X = updateElem(window)
[winH, winW] = size(window);
neighbors = 0;
for ww = 1:winW
for wh = 1:winH
neighbors = window(1,1) + window(1,2) + window(1,3) ...
+ window(2,1) + window(2,3) ...
+ window(3,1) + window(3,2) + window(3,3);
end
end
X = (window(2,2) & (neighbors == 2)) | (neighbors == 3);
end
Сгенерировать MEX CUDA для gameoflife_stencil функционируйте, создайте код, настройка графического процессора кода возражает и использует codegen функция.
cfg = coder.gpuConfig('mex'); evalc('codegen -config cfg -args {initialGrid} gameoflife_stencil');
Запуститесь сгенерировал gameoflife_stencil_mex со случайной начальной генеральной совокупностью.
gridGPU = gameoflife_stencil_mex(initialGrid); % Draw the grid after 100 generations imagesc(gridGPU); colormap([1 1 1;0 0.5 0]); title('Final Grid - CUDA MEX');

В этом примере код CUDA был сгенерирован для простой операции шаблона - "Игра Конуэя Жизни". Реализация была выполнена при помощи gpucoder.stencilKernel прагма. Этот метод, продемонстрированный в этом примере, может использоваться, чтобы реализовать область значений операций шаблона включая алгоритмы конечного элемента, свертки и фильтры.