Оптимальная последовательность команд для сбора 4D-векторов AVX512

Используя инструкции AVX512, я могу использовать индексный вектор для сбора 16 значений одинарной точности из массива. Однако такие операции сбора не так эффективны и на моей машине выполняются со скоростью всего 2 скалярных загрузки/цикл.

В одном из моих приложений мне всегда нужно собрать четыре смежных float элемента. В скалярном псевдокоде:

for (int i = 0; i < 16; ++i) {
    result.x[i] = source[offset[i]*4 + 0];
    result.y[i] = source[offset[i]*4 + 1];
    result.z[i] = source[offset[i]*4 + 2];
    result.w[i] = source[offset[i]*4 + 3];
}

Графические процессоры NVIDIA могут делать что-то с помощью одной инструкции ld.global.v4.f32. Что касается процессора, то также кажется, что можно использовать эту смежность, чтобы получить результат лучше, чем 4 сейсмограммы шириной 16. Кто-нибудь здесь знает более быструю последовательность инструкций AVX512, которая улучшила бы наивную стратегию? Можно предположить произвольное выравнивание.

Я бы, наверное, просто загрузил 4 __m128 вектора и объединил их с помощью инструкций вставки. Вы также можете попробовать инструкцию vgatherdpd (с некоторым приведением типов) — она должна быть примерно в два раза быстрее эквивалентной vgatherdps.

chtz 23.04.2024 13:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
86
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сборщики на процессорах Intel и AMD не могут использовать преимущества соседства исходных элементов друг с другом; они обращаются к кешу отдельно для каждого скалярного элемента. (https://uops.info/ - обратите внимание, что несмотря на то, что количество мопов портов 2/3 на последних моделях Intel низкое, пропускная способность соответствует узкому месту чтения кэша 2/такт или 3/такт).

Кроме того, на Intel от Skylake до Tiger Lake пропускная способность инструкций теперь является мусором из-за смягчения микрокода для GDS (https://downfall.page/#faq). А сборка AMD никогда не была очень быстрой.

Как говорит chtz, вам следует вручную выполнять 128-битную загрузку SIMD, поскольку ваша схема доступа проста.


Но тогда я думаю, вам нужно перетасовать 4 таких вектора, чтобы они были x[i + 0..3] смежными для 128-битного хранилища и так далее, поскольку вы распределяете результаты в выходные данные Struct-of-Arrays.

Вы можете создать две пары vmovups XMM / vinsertf128 YMM, m128, а затем перемешать их вместе с помощью vpermt2ps, чтобы получить один 512-битный вектор со всеми четырьмя смежными значениями x, затем со всеми четырьмя смежными значениями y и т. д. (В C++ с внутренними функциями используйте _mm512_castps256_ps512 чтобы переосмыслить __m256 как __m512, верхняя половина которого представляет собой неопределенный мусор.)

Это устанавливает vextractf32x4 в память для двух старших, vextractf128 для дорожки 1 и vmovups для дорожки 0. Надеюсь, компилятор оптимизирует таким образом, если вы сделаете 4x _mm_store_ps(&result.x[i], _mm512_extractf32x4_ps(v, 0) ) и т. д., но вы можете использовать вручную

  __m512 v = _mm512_permutex2var_ps(_mm512_castps256_ps512(first_2_loads),
                                    _mm512_castps256_ps512(second_2_loads),
                                    shuffle_constant);

  _mm_store_ps(&result.x[i],  _mm512_castps512_ps128(v) );  // vmovups
  _mm_store_ps(&result.y[i],  _mm256_extractf128_ps( _mm512_castps512_ps256(v), 1) );   // vextractf128 mem, ymm, 1
  _mm_store_ps(&result.z[i],  _mm512_extractf32x4_ps(v, 2) );  // vextractf32x4 mem, zmm, 2
  _mm_store_ps(&result.w[i],  _mm512_extractf32x4_ps(v, 3) );

Или избегайте 512-битных векторов и делайте два отдельных 256-битных вектора vpermt2ps, , если остальная часть вашего кода не использует 512-битные векторы .

(Если бы вы делали больше итераций, вы могли бы перетасовать по-другому, чтобы настроить еще более широкие магазины, например, 256 или, может быть, даже 512, если стоит так сильно перетасовать.)


У AVX-512 есть инструкции разброса, но они неэффективны даже на Intel и намного хуже на AMD Zen 4. Вы можете просто vinsertf128 / vinsert32x4 и т. д. и выполнить на их основе разброс со смещениями, которые включают расстояние между началами x и y векторы, предполагая, что они распределены в пределах 2 ГБ друг от друга, поэтому может достигать 32-битного смещения. Но это было бы намного медленнее, я думаю, что даже не получится получить одно 32-битное хранилище за такт (или 2 на Ice Lake и более поздних версиях). Но фиксация из буфера хранилища в L1d составляет только 1 за такт, если только не используются два последовательных хранилища. в одну и ту же строку кэша, тогда они смогут объединиться https://travisdowns.github.io/blog/2019/06/11/speed-limits.html#memory-related-limits)

Спасибо за подробный ответ! Я не знал, что сборки сейчас микрокодируются 🤯. Есть ли у вас информация о пропускной способности/задержке этой операции после этого «улучшения»?

Wenzel Jakob 24.04.2024 12:26

@WenzelJakob: phoronix.com/review/intel-downfall-benchmarks содержит некоторые (немикро) тесты (целых приложений, в которых есть некоторые функции, использующие сборку). В нем также говорится, что Intel сообщает о замедлении работы до 50% в «крайних случаях». Я не думаю, что uops.info был перезапущен с обновленным микрокодом. (Кстати, я не говорил, что сама инструкция имеет микрокод, хотя это было бы так, если бы она теперь декодировалась в какие-либо дополнительные мопы. Это 4 на SKL без смягчения микрокода. Обновления «микрокода» Intel могут изменить вещи, кроме ПЗУ ucode, например, отключение буфера цикла в Skylake.)

Peter Cordes 24.04.2024 21:11

Но хороший вопрос, кто-то должен его задать, каковы именно детали производительности сборок сейчас на затронутых процессорах с включенным смягчением.

Peter Cordes 24.04.2024 21:12

В моем приложении все делается регистрами AVX512. В итоге я выполнил 16 выровненных 4 x float32 загрузок, которые я добавлял друг к другу, чтобы сформировать 4 регистра ZMM. Далее я использую последовательность unpacklo/unpackhi/movehl/movelh, которую обычно используют для транспонирования матрицы, хранящейся в регистрах 4xXMM. Эти инструкции также существуют в вариантах ZMM, где они работают с блоками шириной 4, что правильно. Вам это кажется разумным? Есть ли преимущество у упомянутой вами стратегии vpermt2ps?

Wenzel Jakob 28.04.2024 16:16

@WenzelJakob: Я думаю, что запутался с циклом i < 16, связанным с вопросом, и подумал, что он обрабатывает всего 16 чисел с плавающей запятой. Но на самом деле это один фрагмент из 16 x чисел с плавающей точкой, 16 y чисел с плавающей запятой и т. д., так что вы можете перетасовать 512-битные хранилища, как я предложил. То, что вы делаете, звучит разумно.

Peter Cordes 29.04.2024 04:23

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