Невыровненная нагрузка обычно используется чаще. Разработчик должен использовать выровненную загрузку SIMD, когда адрес уже выровнен. Поэтому я начал задаваться вопросом, есть ли какая-то разница в производительности между этими двумя вызовами функций по уже выровненному адресу. Интуитивное предположение состоит в том, что выровненная загрузка быстрее, чем невыровненная загрузка.
Я знаю, что этот вопрос может быть очень аппаратно-зависимым. Еще одна мотивация заключается в том, что Zen4 — это первая микроархитектура AMD, предлагающая AVX-512, поэтому я хочу попробовать AVX-512 на Zen4 и посмотреть результаты.
Код: https://godbolt.org/z/W3qvcjGWs
Я оцениваю два случая:
data
, имеет размер меньше, чем кэш L1. Так что у меня нет промахов кеша; поэтому не привязан к памяти.vmovdqa64
и vmovdqu64
.Мой эксперимент проводился на AMD Zen4. Я тестировал вызов функции десять раз. Результат непротиворечив, и оказывается, что эти два вызова функций одинаково быстры. Это противоречит моей интуиции. Если это правда, то нет варианта использования фактической выровненной нагрузки, которая имеет минимальный сценарий и приводит к seg-fault на невыровненном адресе.
Если память выровнена (чтобы load
могла работать, а не выдавать ошибку), производительность идентична. Процессоры Intel и AMD были такими со времен Nehalem и K10. (Или бульдозер для movdqu
хранилищ также работает так же, как требуется выравнивание, когда данные выровнены.)
Это не изменилось с 512-битными векторами, _mm512_loadu_si512
быстро работает с выровненными данными.
Если ваши данные обычно выровнены, невыровненные загрузки — отличный выбор; нет дополнительных инструкций, проверяющих выравнивание для общего случая, и аппаратное обеспечение справляется с этим не так уж ужасно в редких случаях. Если вы хотите с шумом обнаружить, что данные когда-либо смещены, используйте выровненные загрузки (и компилируйте с помощью GCC или clang, а не MSVC или ICC, которые никогда не используют требуемые для выравнивания загрузки/сохранения в asm).
Чтобы фактически протестировать несовпадение, вам может потребоваться отключить оптимизацию (при очень высокой производительности кода), если компилятор складывает ваши встроенные функции загрузки в операнды источника памяти для других инструкций. Проверка ожиданий выравнивания — это прецедент для vmovdqa64
и друзей.
Если ваши данные на самом деле большую часть времени смещены, для 256-битных векторов все еще может быть нормально, чтобы ЦП обрабатывал их. (Остерегайтесь Почему gcc не разрешает _mm256_loadu_pd как одиночный vmovupd? с настройкой GCC по умолчанию до GCC11). Возможно, стоит иметь дополнительный код, который должен запускаться каждый раз, когда проверяется выравнивание и, возможно, делает невыровненный первый вектор, возможно, перекрывающийся с первым выровненным вектором, если с вашей операцией SIMD все в порядке.
Интересная особенность 512-битных векторов заключается в том, что любое несовпадение обязательно означает разделение строки кэша, невозможное смещение, но все же содержащееся в одной 64-байтовой строке кэша, как для 16-байтовых и 32-байтовых векторов. (В этих случаях Intel, начиная с Haswell, и AMD, начиная с Zen 2 или 3, я думаю (?) по-прежнему имеют полную производительность для невыровненной загрузки/сохранения.) См. https://uops.info/ и https:// agner.org/оптимизировать/
По крайней мере, для процессоров Intel выравнивание ваших данных весьма полезно для AVX-512, даже если ваш код ограничивает пропускную способность DRAM; явно невыровненные 64-байтовые загрузки, которые на самом деле смещаются во время выполнения, приводят к снижению пропускной способности памяти на ядро, примерно на 15%, по сравнению с всего парой процентов для кода, использующего 256-битные векторы, если это так.
64-байтовые невыровненные загрузки обычно () выполняются с одной загрузкой за цикл на процессорах SKX/CLX — эффективно используя оба интерфейса чтения 64-байтного кэша L1D для захвата последовательных строк кэша, а затем сдвиг/объединение результатов в 512-битный пункт назначения регистр. По причинам, которые не совсем ясны, даже этот штраф в 1/2 цикла приводит к значительному падению пропускной способности для данных, расположенных дальше в иерархии памяти... () Существует больший штраф за невыровненные загрузки, которые пересекают страницу. граница.