AVX VMOVDQA медленнее, чем два SSE MOVDQA? - программирование
Подтвердить что ты не робот

AVX VMOVDQA медленнее, чем два SSE MOVDQA?

Пока я работал над своим быстрым циклом ADD (Ускорить цикл ADID ассемблера x64), я тестировал доступ к памяти с помощью инструкций SSE и AVX. Чтобы добавить, мне нужно прочитать два входа и произвести один вывод. Поэтому я написал манекенную процедуру, которая считывает два значения x64 в регистры и записывает их обратно в память без какой-либо операции. Это, конечно, бесполезно, я только делал это для бенчмаркинга.

Я использую развернутый цикл, который обрабатывает 64 байта за цикл. Он состоит из 8 блоков:

mov rax, QWORD PTR [rdx+r11*8-64]
mov r10, QWORD PTR [r8+r11*8-64]
mov QWORD PTR [rcx+r11*8-64], rax

Затем я обновил его до SSE2. Теперь я использую 4 блока следующим образом:

movdqa xmm0, XMMWORD PTR [rdx+r11*8-64]
movdqa xmm1, XMMWORD PTR [r8+r11*8-64]
movdqa XMMWORD PTR [rcx+r11*8-64], xmm0

И позже я использовал AVX (256 бит на регистр). У меня есть 2 блока:

vmovdqa ymm0, YMMWORD PTR [rdx+r11*8-64]
vmovdqa ymm1, YMMWORD PTR [r8+r11*8-64]
vmovdqa YMMWORD PTR [rcx+r11*8-64], ymm0

Пока, так не очень-очень-эффектно. Интересным является результат бенчмаркинга: когда я запускаю три разных подхода к 1k + 1k = 1k 64-битным словам (т.е. Два раза 8 kb ввода и один раз 8kb вывода), я получаю странные результаты. Каждый из следующих таймингов предназначен для обработки двухкратных 64 байтов ввода в 64 байта вывода.

  • Метод регистрации x64 работает примерно в 15 циклах /64 байта.
  • Метод SSE2 работает примерно в 8,5 циклах /64 байта.
  • Метод AVX работает примерно в 9 циклах /64 байта.

Мой вопрос: почему метод AVX работает медленнее (хотя и не много), чем метод SSE2? Я ожидал, что это будет хотя бы на уровне. Использует ли использование регистров YMM столько дополнительного времени? Память была выровнена (вы получаете GPF в противном случае).

Есть ли у кого есть объяснение?

4b9b3361

Ответ 1

В Sandybridge/Ivybridge 256b загрузок и хранилищ AVX разбиты на два 128b ops [как отмечает Питер Кордес, это не совсем μops, но для операции по очистке порта требуется два цикла) в загрузке/хранении так что нет причин ожидать, что версия, использующая эти инструкции, будет намного быстрее.

Почему он медленнее? Приходят в голову две возможности:

  • для адресации базы + индекс + смещение, латентность нагрузки 128b составляет 6 тактов, тогда как латентность нагрузки 256b составляет 7 циклов (таблица 2-8 в Руководстве по оптимизации Intel). Хотя ваш контрольный показатель должен быть привязан по скорости и не латентности, более длительная латентность означает, что процессор требует больше времени для восстановления от любых икота (пузырьков трубопровода или пропусков прогноза или обслуживания прерываний или...), что имеет некоторое влияние.

  • в 11.6.2 того же документа, Intel предполагает, что штраф за кеш-линию и пересечение страниц может быть больше для 256-бит нагрузок, чем для 128-битных нагрузок. Если ваши нагрузки не совпадают с 32 байтами, это также может объяснить замедление, которое вы наблюдаете при использовании операций загрузки/хранения 256b:

В примере 11-12 показаны две реализации для SAXPY с невыровненными адреса. Альтернатива 1 использует 32 байтовые нагрузки, а альтернативные 2 - 16 байтовых нагрузок. Эти образцы кода выполняются с двумя исходными буферами, src1, src2, с 4-байтным смещением от 32-байтового выравнивания и целевой буфер, DST, который выровнен по 32 байт. Использование двух 16-байтных операции памяти вместо 32-байтового доступа к памяти выполняются быстрее.