Выравнивание доступа к памяти GPU ядра свертки изображения (OpenCL/CUDA)

Чтобы понять, как убедиться, что требования к выравниванию выполнены, я читал следующий отрывок из книги "Неоднородные вычисления с OpenCL p.no: 157" несколько раз. Это показывает, как добавить дополнение к проблеме в свертку изображений (при условии, что размер рабочей группы 16 x 16).

Выравнивание для доступа к памяти

Производительность графических процессоров NVIDIA и AMD выигрывает от выравнивания данных в глобальной памяти. В частности, для NVIDIA выравнивание доступа по 128-байтовым границам и доступ к 128-байтовым сегментам идеально отразится на аппаратном обеспечении памяти. Однако в этом примере рабочие группы 16-го уровня будут иметь доступ только к 64-байтным сегментам, поэтому данные должны быть выровнены на 64-байтные адреса. Это означает, что первый столбец, к которому обращаются каждая рабочая группа, должен начинаться с 64-байтового выровненного адреса. В этом примере выбор того, чтобы пиксельные пиксели не выдавали значения, определяет, что смещение для всех рабочих групп будет кратно размеру рабочей группы (т.е. Для рабочей группы 16 x 16 рабочая группа начнет доступ к данным на столбец N * 16). Чтобы обеспечить соответствие каждой рабочей группы должным образом, единственным требованием является заполнение входных данных дополнительными столбцами, так что его ширина становится кратной X-размерности рабочей группы.

1. Может ли кто-нибудь помочь мне понять, как после заполнения первого столбца, который каждый доступ к рабочей группе начинается с 64-байтного выровненного адреса (требование, упомянутое в приведенном выше отрывке, верно?)?

2. Кроме того, по правилу правильная инструкция: для рабочей группы 16 x 16 рабочая группа начнет доступ к данным в столбце N * 16.

если это правильно, рабочая группа 1,2, как показано на рисунке, должна начать доступ к данным в столбце 1x16 вопреки тому, что показано на рисунке. Я совершенно смущен!!: (

Update: Q-2 теперь мне понятен. Фактически рабочая группа, показанная на рисунке, равна 2,1 (в соглашении opencl, сначала в столбце), поэтому она совершенно правильная: 2x16 = 32, а не 1x16, как я думал.

Но вопрос №. 1 все еще остается без ответа.

enter image description here

Ответ 1

Для ядра свертки каждая область (например, область (0,1) или область (2,1) и т.д.) также должна включать в себя "ореол" данных вокруг него, так что когда ядро ​​свертки работает на элемент данных на краю области, он имеет подходящий набор соседей этого элемента данных для вычисления свертки в этой точке данных. Это означает, что для области (0,0), которая имеет элемент данных (0,0) в верхнем левом углу, мне нужны элементы (-1, 0), (-2, 0) и т.д., Чтобы вычислить свертку на элементе (0,0).

Теперь, если я обычно храню изображение, так что элемент (0,0) находится в ячейке памяти 0 (или другом другом выровненном по 64 байтам адресе), тогда, когда я обращаюсь к элементам до этой точки свертки, Я получаю доступ к данным за пределами моего 64-байтового выровненного региона. Поэтому мы можем "вставить" крайний левый столбец изображения с дополнительными элементами данных "влево", то есть до адресата, так что ядро ​​свертки подбирает значения, которые находятся в пределах 64-байтовой выровненной области, и я не охватывая 64-байтовую границу. Вместо того, чтобы запускать хранилище изображений в ячейке памяти 0, мы запускаем хранилище ореола в нулевой ячейке памяти, а первый элемент данных изображения начинается с местоположения 0 + ширина гало. Это дополнение также может влиять на выравнивание галограничной границы других областей, о чем свидетельствует пересечение красных пунктирных линий на изображении, предполагая, что размеры x и y области кратно размерам рабочих групп x и y, как показано на диаграмме.

Теперь предположим также, что изображение представляет собой некоторую ширину без изменения ширины (например, 1920 пикселей в ширину для HD-изображения). Если бы мы просто включили гало-ширину в качестве дополнения в правой части изображения (т.е. В конце строки пикселя), а затем мы запустили область ореола следующей строки пикселей сразу после этого, мы бы также вряд ли иметь правильно выровненную область, начинающуюся со следующего ряда пикселей (включая ореол). Поэтому мы помещаем дополнительное дополнение в конце каждой строки (которое не затрагивается какой-либо операцией свертки, это просто пустое пространство), так что, когда мы начинаем область ореола следующей строки пикселя, она начинается с правильно выровненного адреса.

Это обсуждение и метод (и, я полагаю, вопрос) действительно сосредоточены только на том, чтобы выровнять начальный адрес каждого доступа к данным рабочей группы. Пока начальный адрес первой рабочей группы выровнен (через подходящее заполнение и настройку хранения изображений в памяти), а рабочие группы имеют соответствующие размеры (например, 16 в ширину, с 4 байтами на одного рабочего), тогда начальный адрес следующая рабочая группа также будет выровнена. Разумеется, будет частично перекрываться доступ данных к смежным рабочим группам, поскольку область ореола для смежных рабочих групп перекрывается.

Alignment, поскольку я использую его здесь, имеет довольно простое определение. Адрес в памяти равен 2 ** n байтам, если наименьшие значащие n бит адреса равны нулю. Поэтому 64-байтовая выровненная область имеет начальный адрес с 6 наименьшими значащими битами, равными нулю. Это обычно полезно для этих архитектур, чтобы удовлетворить требования к загрузке и хранению памяти в архитектуре и, в частности, к подсистемам DRAM, которые они содержат. Современные обращения банка памяти DRAM всегда возвращают несколько байтов, и поэтому мы можем наилучшим образом использовать передачу, если мы используем все эти байты в одно и то же время, в том же место в коде. Для дополнительного охвата при выравнивании и эффекта, который он оказывает на объединение и улучшение доступа к данным, вас может заинтересовать этот веб-семинарслайды) из веб-страницы nvidia. Для быстрого просмотра слайды 26-33 эта презентация охватывают основные идеи.