В CUDA, что такое слияние памяти, и как это достигается?
Что "сливается" в глобальной транзакции памяти CUDA? Я не мог понять даже после прохождения моего руководства CUDA. Как это сделать? В Примере матрицы руководства по программированию CUDA доступ к матрице строка за строкой называется "coalesced" или col.. на седловине.. это называется коалесцировать? Что правильно и почему?
4 ответа:
вероятно, что эта информация применяется только для вычисления capabality 1.x, или cuda 2.0. Более поздние архитектуры и cuda 3.0 имеют более сложный глобальный доступ к памяти, и фактически "объединенные глобальные нагрузки" даже не профилируются для этих чипов.
кроме того, эта логика может быть применена к общей памяти, чтобы избежать конфликтов.
объединенное транзакционной памяти является та, в которой все потоки в варп открыть глобальная память в то же время. Это слишком просто, но правильный способ сделать это-просто иметь последовательные потоки доступа к последовательным адресам памяти.
Итак, если потоки 0, 1, 2 и 3 читают глобальную память 0x0, 0x4, 0x8 и 0xc, это должно быть объединенное чтение.
в Примере матрицы, имейте в виду, что вы хотите, чтобы ваша матрица проживать линейно в памяти. Вы можете сделать это, как вы хотите, и ваш доступ к памяти должен отражать, как ваша матрица выложена. Итак, матрица 3x4 ниже
0 1 2 3 4 5 6 7 8 9 a b
может быть сделано строка за строкой, как это, так что (r,c) карты в память (r*4 + c)
0 1 2 3 4 5 6 7 8 9 a b
Предположим, вам нужно получить доступ к элементу один раз, и сказать, что у вас есть четыре потока. Какие потоки будут использоваться для какого элемента? Вероятно, либо
thread 0: 0, 1, 2 thread 1: 3, 4, 5 thread 2: 6, 7, 8 thread 3: 9, a, b
или
thread 0: 0, 4, 8 thread 1: 1, 5, 9 thread 2: 2, 6, a thread 3: 3, 7, b
что лучше? Что приведет к Объединенным чтениям, а что нет?
в любом случае, каждый поток делает три доступов. Давайте посмотрим на первый доступ и посмотреть, если потоки обращаются к памяти последовательно. В первом варианте, первый выход равен 0, 3, 6, 9. Не последовательные, не сросшиеся. Второй вариант, это 0, 1, 2, 3. Подряд! Соединились! Ура!
лучший способ, вероятно, написать свое ядро, а затем профилировать его, чтобы увидеть, есть ли у вас несогласованные глобальные нагрузки и магазины.
объединение памяти-это метод, который позволяет оптимально использовать глобальную пропускную способность памяти. То есть, когда параллельные потоки выполняют одну и ту же инструкцию доступа к последовательным местоположениям в глобальной памяти, достигается наиболее благоприятный шаблон доступа.
пример на рисунке выше помогает объяснить срослись расположение:
На Фиг. (а), n векторов длины m хранятся в линейном мода. Элемент я вектор j обозначается vjя. Каждый поток в ядре GPU присваивается одному m-длина вектора. Потоки в CUDA сгруппированы в массив блоков, и каждый поток в GPU имеет уникальный идентификатор, который можно определить как
indx=bd*bx+tx
, гдеbd
представляет собой блок измерения,bx
обозначает индекс блока иtx
- это индекс потока в каждом блоке.вертикальная стрелки показывают случай, когда параллельные потоки обращаются к первым компонентам каждого вектора, т. е. адреса 0,m,2М... памяти. Как показано на фиг. (а), в этом случае доступ к памяти не подряд. При обнулении промежутка между этими адресами (красные стрелки показаны на рисунке выше) доступ к памяти становится Объединенным.
однако, проблема становится немного сложнее здесь, так как допустимый размер проживающих потоков на блок GPU является ограничено
bd
. Поэтому объединение данных может быть сделано путем хранения первых элементов первогоbd
векторы в последовательном порядке, за которыми следуют первые элементы вторых векторов bd и так далее. Остальные элементы векторов хранятся аналогичным образом, как показано на фиг. (си.) Если n (количество векторов) не является факторомbd
, необходимо дополнить оставшиеся данные в последнем блоке некоторым тривиальным значением, например 0.в линейных данных хранение на фиг. (a), компонент я (0 ≤ я m) вектора indx (0 ≤ indx n) решается
m × indx +i
; один и тот же компонент в укрупненными схема хранения на фиг. (б) рассматривается как
(m × bd) ixC + bd × ixB + ixA
,здесь
ixC = floor[(m.indx + j )/(m.bd)]= bx
,ixB = j
иixA = mod(indx,bd) = tx
.в общем, в Примере хранения ряда векторов с размером m линейные индексация сопоставляется с укрупненными индексации в соответствии с:
m.indx +i −→ m.bd.bx +i .bd +tx
эта перестановка данных может привести к значительному увеличению пропускной способности глобальной памяти GPU.
источник: "ускорение вычислений на основе GPU в нелинейном анализе деформации конечных элементов."Международный журнал для численных методов в биомедицинской инженерии (2013).
Если потоки в блоке обращаются к последовательным глобальным ячейкам памяти, то все обращения объединяются в один запрос(или объединяются) аппаратным обеспечением. В Примере с матрицей элементы матрицы в строке расположены линейно, за ними следует следующая строка и так далее. Например, для матрицы 2x2 и 2 потоков в блоке ячейки памяти расположены следующим образом:
(0,0) (0,1) (1,0) (1,1)
в доступе к строке thread1 обращается к (0,0) и (1,0), которые не могут быть объединены. В доступ к колонке, доступы thread1 (0,0) и (0,1), которые могут быть объединены, потому что они смежны.
критерии коалесценции хорошо документированы в CUDA 3.2 руководство по программированию, Раздел G. 3.2. Короткая версия выглядит следующим образом: потоки в warp должны последовательно обращаться к памяти, а слова, к которым обращаются, должны >=32 бита. Кроме того, базовый адрес, к которому обращается warp, должен быть выровнен по 64, 128 или 256 байтам для 32 -, 64-и 128-разрядных обращений соответственно.
оборудование Tesla2 и Fermi делает хорошую работу коалесцировать 8-и 16-битные доступы, но их лучше избегать, если вы хотите пиковую пропускную способность.
обратите внимание, что, несмотря на улучшения в аппаратных средствах Tesla2 и Fermi, Коалесценция никоим образом не устарела. Даже на аппаратном обеспечении класса Tesla2 или Fermi неспособность объединить глобальные транзакции памяти может привести к снижению производительности в 2 раза. (На аппаратном обеспечении класса Fermi это, кажется, верно только тогда, когда ECC включен. Непрерывные, но несвязанные транзакции памяти занимают около 20% от Ферми.)