vextracti128
и vextractf128
имеют одинаковые функции, параметры и возвращаемые значения. Вдобавок один - это набор инструкций AVX, а другой - AVX2. В чем разница?
В чем разница между vextracti128 и vextractf128?
Ответы (2)
vextracti128
и vextractf128
имеют не только одинаковые функции, параметры и возвращаемые значения. У них одинаковая длина инструкций. И у них одинаковая пропускная способность (согласно руководствам по оптимизации Agner Fog).
Что не совсем понятно, так это их значения задержки (производительность в жестких циклах с цепочками зависимостей). Задержка самих инструкций составляет 3 цикла. Но после прочтения раздела 2.1.3 («Механизм выполнения») Руководства по оптимизации Intel мы можем подозревать, что vextracti128
должен получить дополнительную 1 тактовую задержку при работе с данными с плавающей запятой, а vextractf128
должен получить дополнительную 1 тактовую задержку при работе с целочисленными данными. Измерения показывают, что это не так, и задержка всегда остается ровно 3 цикла (по крайней мере, для процессоров Haswell). И, насколько мне известно, это нигде не задокументировано в Руководстве по оптимизации.
Тем не менее, набор инструкций - это только интерфейс для процессора. Haswell - единственная реализация этого интерфейса, содержащая обе эти инструкции (на данный момент). Мы могли бы проигнорировать тот факт, что реализации этих инструкций (скорее всего) идентичны. И используйте эти инструкции по назначению - vextracti128
для целочисленных данных и vextractf128
для данных FP. (Если нам нужно только переупорядочить данные без выполнения каких-либо операций int / FP, очевидный выбор - vextractf128
, поскольку он поддерживается несколькими более старыми процессорами). Также опыт показывает, что Intel иногда снижает производительность некоторых инструкций в процессорах следующих поколений, поэтому было бы разумно соблюдать схожесть этих инструкций, чтобы избежать возможного снижения скорости в будущем.
Поскольку руководство по оптимизации Intel не очень подробно описывает взаимосвязь между доменами int / FP для инструкций SIMD, я провел еще несколько измерений (на Haswell) и получил некоторые интересные результаты:
Инструкции по перемешиванию
Нет никакой дополнительной задержки для любых переходов между инструкциями SSE integer и shuffle. И нет никакой дополнительной задержки для любых переходов между SSE FP и инструкциями перемешивания. (Хотя я не проверял каждую инструкцию). Например, вы можете вставить такую «явно целочисленную» инструкцию как pshufb
между двумя инструкциями FP без дополнительной задержки. Вставка shufpd
в середину целочисленного кода также не дает дополнительной задержки.
Поскольку vextracti128
и vextractf128
выполняются модулем тасования, у них также есть это свойство «без задержки».
Это может быть полезно для оптимизации смешанного кода int + FP. Если вам нужно переинтерпретировать данные FP как целые числа и в то же время перемешать регистр, просто убедитесь, что все инструкции FP стоят перед перемешиванием, а все целочисленные инструкции находятся после него.
Логические инструкции FP
andps
и другие логические инструкции FP также имеют свойство игнорировать домены FP / int.
Если вы добавите целочисленную логическую инструкцию (например, pand
) в код FP, вы получите дополнительную задержку в 2 цикла (один для перехода в домен int, а другой для возврата в FP). Таким образом, очевидным выбором для кода SIMD FP является andps
. Тот же andps
можно использовать в середине целочисленного кода без каких-либо задержек. Еще лучше использовать такие инструкции прямо между инструкциями int и FP. Интересно, что логические инструкции FP используют тот же порт номер 5, что и все инструкции перемешивания.
Зарегистрируйтесь, чтобы получить доступ
В руководстве по оптимизации Intel описаны задержки в обходе между микрооперациями производителя и потребителя. Но он ничего не говорит о том, как микрооперации взаимодействуют с регистрами.
Этому фрагменту кода требуется всего 3 такта на итерацию (как того требует vaddps
):
vxorps ymm7, ymm7, ymm7
_benchloop:
vaddps ymm0, ymm0, ymm7
jmp _benchloop
Но для этого нужно 2 такта на итерацию (на 1 больше, чем нужно для vpaddd
):
vpxor ymm7, ymm7, ymm7
_benchloop:
vpaddd ymm0, ymm0, ymm7
jmp _benchloop
Единственная разница здесь - вычисления в целочисленной области, а не в FP-области. Чтобы получить 1 такт / итерацию, нам нужно добавить инструкцию:
vpxor ymm7, ymm7, ymm7
_benchloop:
vpand ymm6, ymm7, ymm7
vpaddd ymm0, ymm0, ymm6
jmp _benchloop
Это намекает на то, что (1) все значения, хранящиеся в регистрах SIMD, принадлежат домену FP, и (2) чтение из регистра SIMD увеличивает задержку целочисленной операции на единицу. (Разница между {ymm0, ymm6} и ymm7 здесь в том, что ymm7 хранится в некоторой временной памяти и работает как настоящий «регистр», тогда как ymm0 и ymm6 являются временными и представлены состоянием внутренних соединений ЦП, а не постоянным хранилищем, поэтому ymm0 и ymm6 не «читаются», а просто передаются между микрооперациями).
perf
для подсчета insns / цикл. Agner Fog указывает пропускную способность получателя jmp near
как 1-2c для Haswell, по сравнению с 2c для SnB, так что, возможно, вы сможете получить один цикл на итерацию на HSW.) Но я думаю. если любой из циклов равен 1c, оба не-FP-цикла равны. В противном случае хороший ответ.
- person Peter Cordes; 17.07.2015
dec ecx/jnz
(который микроплавлен в один муп, точно так же, как jmp
. Время от времени я пытался запустить 2 миллиарда итераций с повторными испытаниями с тех пор, как Я на шумной ВМ.)
- person Peter Cordes; 09.04.2017
ymm7
чем-то другим, кроме xor-zeroing, тоже ничего не меняет. (Я пробовал vcmpeqw same,same
получить все единицы, так как xor-zeroing является особенным). Это действительно озадачивает, так как вашему vpand
все равно нужно читать ymm7
из файла физического реестра, а не из сети пересылки. Однако это не часть цепочки зависимостей, переносимой циклом, что является очевидной разницей. Изменение VPADDD на логическое значение не имеет значения.
- person Peter Cordes; 09.04.2017
perf stat
в исходном цикле (с jmp
) и в моей версии с 2 миллиардами итераций показывают, что он выполняется каждый раз ровно с 1 итерацией за такт с точностью до 0,01%. нет такой проблемы.
- person Peter Cordes; 09.04.2017
Хороший вопрос - похоже, что инструкция AVX vextractf128
предназначена для любого типа вектора (int, float, double), а инструкция AVX2 vextracti128
предназначена только для вектора int. Я рекомендую использовать последний, когда у вас есть AVX2 и целочисленные векторы, если он обеспечивает лучшую производительность в некоторых случаях, в противном случае используйте первое.