Кривые когерентности, локальности и заполнения пространства CUDA / OpenCL

Я работаю над приложением CUDA, которое использует всю доступную оперативную память на карте, и пытаюсь найти разные способы уменьшить потери кеша.

Проблемная область состоит из большой 2- или 3-мерной сетки, в зависимости от типа решаемой проблемы. (Для тех, кто заинтересован, это симулятор FDTD). Каждый элемент зависит от двух или четырех элементов в "параллельных" массивах (то есть другого массива с почти одинаковыми размерами), поэтому ядра должны иметь доступ к трем или шести различным массивам.

Эта проблема

* Надеюсь, это не "слишком локализовано". Не стесняйтесь редактировать вопрос

Отношения между тремя массивами могут быть визуализированы как (извиняюсь за посредственное искусство ASCII)

  A[0,0] -C[0,0]- A ---- C ---- A ---- C ---- A
    |             |             |             |
    |             |             |             |
  B[0,0]          B             B             B
    |             |             |             |
    |             |             |             |
    A ---- C ---- A ---- C ---- A ---- C ---- A
    |             |             |             |
    |             |             |             |
    B             B             B             B
    |             |             |             |
    |             |             |             |
    A ---- C ---- A ---- C ---- A ---- C ---- A
    |             |             |             |
    |             |             |             |
    B             B             B             B[3,2]
    |             |             |             |
    |             |             |             |
    A ---- C ---- A ---- C ---- A ---- C ---- A[3,3]
                                      [2,3]

Элементы, соединенные линиями, связаны между собой. Как видно выше, A[] зависит от обоих B[] а также C[], в то время как B[] зависит только от A[], так же как и C[], Все A[] обновляется в первом ядре, и все B[] а также C[] обновляются во втором проходе.

Если я объявлю эти массивы простыми 2D-массивами, я получу расширенный доступ к памяти. Для очень большого размера домена (3x3 +- 1 в сетке выше) это приводит к дефициту занятости и производительности.

Итак, я подумал о перестановке массива в виде кривой Z-порядка:

Кривая заполнения пространства Z-порядка

Кроме того, было бы довольно тривиально чередовать их в один массив, что должно улучшить производительность выборки, поскольку (в зависимости от порядка чередования), по крайней мере, половина элементов, требуемых для данного обновления ячейки, будет близка друг к другу. Однако мне не ясно, использует ли GPU несколько указателей данных при доступе к нескольким массивам. Если это так, то это воображаемое преимущество может стать помехой.

Вопросы

Я читал, что NVidia делает это автоматически за кулисами, используя текстурную память, или cudaArray, Если это не так, следует ли ожидать увеличения задержки при пересечении больших промежутков (когда кривая Z переходит сверху вниз влево на высоком уровне подразделения), чтобы исключить преимущество местоположения в меньших сетках?

  1. Разделение сетки на более мелкие блоки, которые могут поместиться в разделяемой памяти, безусловно, должно помочь, и порядок Z делает это довольно тривиальным. Должен ли я иметь отдельный проход ядра, который обновляет границы между блоками? Будут ли значительными затраты на запуск другого ядра по сравнению с ожидаемой экономией?

  2. Есть ли реальная выгода от использования 2D против 1D массива? Я ожидаю, что память будет линейной, но не уверен, есть ли какое-то реальное значение для метафоры макета 2D-памяти, которая часто используется в литературе CUDA.

Ух ты - длинный вопрос. Спасибо за чтение и ответы на все / все это.

0 ответов

Просто чтобы убрать это из списка неотвеченных:

После большого количества тестов и экспериментов с различными компоновками, самый быстрый подход, который я нашел, состоял в том, чтобы чередовать массивы в z-порядке, чтобы большинство значений, требуемых потоком, располагались в ОЗУ рядом друг с другом. Это улучшило поведение кеша (и, следовательно, производительность). Очевидно, есть много случаев, когда Z-порядок не может удерживать требуемые значения близко друг к другу. Интересно, уменьшает ли вращение квадрантов "расстояние" между концом Z и следующим квадрантом, но я этого не пробовал.

Всем спасибо за советы.

Другие вопросы по тегам