Отсутствуют встроенные функции AVX-512 для масок?

Руководство Intel по внутренним функциям lists количество встроенных функций для инструкций маски AVX-512 K *, но, похоже, некоторых из них не хватает:

  • KSHIFT {L / R}
  • KADD
  • КТЕСТ

В руководстве разработчика Intel утверждается, что встроенные функции не нужны, поскольку они автоматически генерируются компилятором. Но как это сделать? Если это означает, что типы __mmask * можно рассматривать как обычные целые числа, это имело бы большой смысл, но тестирование чего-то вроде mask << 4, похоже, заставляет компилятор переместить маску в обычный регистр, сдвинуть ее, а затем вернуться к маске . Это было протестировано с использованием последней версии GCC и ICC от Godbolt с -O2 -mavx512bw.

Также интересно отметить, что встроенные функции имеют дело только с __mmask16, а не с другими типами. Я не много тестировал, но похоже, что ICC не возражает против использования неправильного типа, но GCC, похоже, пытается гарантировать, что в маске только 16 бит, если вы используете встроенные функции.

Я не смотрю мимо правильных встроенных функций для приведенных выше инструкций, а также других вариантов типа __mmask *, или есть другой способ добиться того же, не прибегая к встроенной сборке?


person zinga    schedule 18.07.2017    source источник
comment
Обратите внимание, что инструкции маски могут выполняться только на одном порте ALU на Skylake-avx512. Я не уверен, какой порт, но это один из портов, который конфликтует с векторными инструкциями. (kmov в / из целочисленных регистров, вероятно, также использует этот порт, поэтому переход к целочисленному и обратно за один сдвиг по-прежнему глуп для пропускной способности, если не для задержки).   -  person Peter Cordes    schedule 23.08.2017
comment
По крайней мере, для _1 _ / _ 2_ переход к целочисленному регистру вместо использования ktest позволяет объединить макрос test/jcc для -march=skylake-AVX512. Это просто тупо для -march=knl.   -  person Peter Cordes    schedule 23.08.2017
comment
Из интереса, стоит ли достижение слияния того, что требуется для дополнительных KMOV? То есть ktest+jcc vs kmov+test/jcc?   -  person zinga    schedule 25.08.2017
comment
Вероятно, это, по крайней мере, безубыточно для пропускной способности интерфейса, но хуже для размера кода. ktest + jcc - это 2 или 3 мопса. Надеюсь, ktest равно 1, но SSE / AVX ptest - 2 мупа (1 для теста, 1 для перемещения результата из векторного домена в целое число, тот же порт, что и movd). kmov + test/jcc почти наверняка всего 2 мупа.   -  person Peter Cordes    schedule 25.08.2017


Ответы (1)


Документация Intel, в которой говорится, что «не нужны, поскольку они автоматически генерируются компилятором», на самом деле верна. И все же это неудовлетворительно.

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


Причина, по которой состояние внутренних масок попало в беспорядок, в котором они сейчас находятся, вероятно, состоит в том, что AVX512 был «развернут» в несколько этапов без достаточного предварительного планирования до следующего этапа.

Этап 1. Приземление рыцарей

В Knights Landing добавлены 512-битные регистры, которые имеют только 32-битную и 64-битную детализацию данных. Следовательно, регистры маски никогда не должны быть шире 16 бит.

Когда Intel разрабатывала этот первый набор встроенных функций AVX512, они пошли дальше и добавили встроенные функции почти для всего, включая регистры маски. Вот почему внутренние функции маски, которые существуют, имеют всего 16 бит. И они охватывают только инструкции, существующие в Knights Landing. (хотя я не могу объяснить, почему отсутствует KSHIFT)

В Knights Landing операции с маской были быстрыми (2 цикла). Но перемещение данных между регистрами маски и регистрами общего назначения было очень медленным (5 циклов). Таким образом, имело значение, где выполняются операции с масками, и имело смысл дать пользователю более детальный контроль над перемещением материала назад и вперед между регистрами маски и георадаром.

Этап 2: Скайлейк Перли

Skylake Purley расширяет AVX512, чтобы покрыть полосы с побайтовым разбиением. И это увеличило ширину регистров маски до полных 64 бит. Во втором раунде также были добавлены KADD и KTEST, которых не было в Knights Landing.

Эти новые инструкции маски (KADD, KTEST и 64-битные расширения существующих) - это те, которые не имеют своих внутренних аналогов.


Хотя мы не знаем точно, почему они отсутствуют, есть веские доказательства в поддержку этого:

Компилятор / синтаксис:

В Knights Landing одинаковые внутренние свойства маски использовались как для 8-битных, так и для 16-битных масок. Их невозможно было различить. Расширение их до 32-битных и 64-битных усугубило беспорядок. Другими словами, Intel изначально неправильно спроектировала внутренние компоненты маски. И они решили отказаться от них полностью, а не исправлять.

Несоответствие производительности:

Инструкции по маске пересечения битов на Skylake Purley медленные. В то время как все побитовые инструкции являются однократными, KADD, KSHIFT, KUNPACK и т. Д. - все 4 цикла. Но переход между маской и георадаром составляет всего 2 цикла.

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

Если заставить компилятор принять это решение, это означает, что у компилятора должна быть такая логика. В настоящее время компилятор Intel генерирует kadd и семейство в определенных (редких) случаях. Но GCC этого не делает. В GCC все операции с масками, кроме самых простых, будут перенесены в GPR и будут выполняться там.


Последние мысли:

Перед выпуском Skylake Purley я лично написал много кода AVX512, который включает много кода маски AVX512. Они были написаны с определенными предположениями о производительности (задержка одного цикла), которые оказались ложными на Skylake Purley.

Судя по моему собственному тестированию на Skylake X, некоторые из моих встроенных в маску кодов, которые полагались на операции пересечения битов, оказались медленнее, чем версии, созданные компилятором, которые переместили их в GPR и обратно. Причина, конечно, в том, что KADD и KSHIFT были 4 цикла вместо 1.

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


Обновление:

Неясно, когда это произошло, но в последней версии Intel Intrinsics Guide есть новый набор встроенных масок с новым соглашением об именах, которое охватывает все инструкции и ширину. Эти новые внутренние свойства заменяют старые.

Так что это решает всю проблему. Хотя степень поддержки компилятора все еще неизвестна.

Примеры:

  • _kadd_mask64()
  • _kshiftri_mask32()
  • _cvtmask16_u32() заменяет _mm512_mask2int()
person Mysticial    schedule 18.07.2017
comment
Спасибо за очень подробный ответ! медленные операции маски на самом деле довольно удивительны и объясняют поведение. У меня нет реального процессора для тестирования, но если перемещение между маской / георадаром стоит 2 цикла, разве KSHIFT (4 цикла) не будет быстрее, чем перемещение + сдвиг + перемещение (5 циклов), не говоря уже о снятие давления на интерфейс? Также ~mask, похоже, вызывает последовательность kmov + not + kmov как в GCC, так и в ICC, поэтому кажется, что внутренняя функция - единственный способ справиться с этим должным образом ...? - person zinga; 19.07.2017
comment
Если вы выполняете только одну инструкцию по маске, то да, дешевле просто сделать это с помощью инструкции по маске. Это те случаи, когда я могу иногда заставить ICC их сгенерировать. Но если вы делаете что-то вроде KADD, KSHIFT, KUNPACK, скорее всего, вы выполняете несколько инструкций по маске. Не нужно много времени, прежде чем станет дешевле перейти на георадар и обратно. Также обратите внимание, что инструкции маски имеют пропускную способность только 1 / цикл, тогда как целочисленные инструкции GPR обычно составляют 2-4 / цикл. - person Mysticial; 19.07.2017
comment
Что касается компиляторов, не генерирующих оптимальную последовательность, AVX512 все еще нов, и оптимизаторы все еще незрелы по отношению к ним. В конце концов, если вам нужен полный контроль, вам понадобится встроенная сборка. И даже тогда в ICC есть определенные ошибки, которые делают это менее полезным. - person Mysticial; 19.07.2017
comment
Честно говоря, будем надеяться, что тогда ситуация улучшится. Еще раз спасибо за объяснение! - person zinga; 19.07.2017
comment
На каком порту выполняются инструкции маски на SKL-X? Это порт 0 или 5, не так ли? И это включает kmov в / из георадара, верно? Таким образом, одиночный kshift имеет половину влияния на пропускную способность векторных инструкций по сравнению с kmov на GPR и обратно, если это правильно. (shl может работать на порту 6.) Это также в 3 раза больше интерфейсных мопов. Но если вы делаете несколько вещей с данными маски, то да, переход на георадары должен быть намного лучше на SKL-X. - person Peter Cordes; 23.08.2017
comment
@PeterCordes, я не знаю. Я не тестировал его, и Агнер еще не опубликовал цифры. - person Mysticial; 23.08.2017
comment
@Mysticial: если у вас будет возможность, вы можете проверить порты без использования счетчиков производительности, проверив конфликты ресурсов с другими инструкциями, которые выполняются на известных портах. например проверьте p5 с пропускной способностью shuffle + kshift. p1 с пропускной способностью imul + kshift. p0 с пропускной способностью movd eax, xmm0 или pmovmskb + kshift. (Или я предполагаю, что с инструкциями 512b, закрывающими p1 для векторных операций, многие вещи работают только на p0, например pmullw.) - person Peter Cordes; 23.08.2017
comment
@PeterCordes Похоже, кто-то опередил Агнера: - person Mysticial; 13.09.2017
comment
@Mysticial: о, похоже, они получили данные от IACA. В этом есть смысл, я забыл, что у него были данные о порте. В нем говорится, что большинство k инструкций выполняются на P0, но kshift и kunpck выполняются на p5. ktest и kortest являются однокомпонентными, в отличие от SSE / AVX PTEST. kmov* r32, k - это P0, kmov* k, r32 - это P5. К сожалению, P1 не используется k инструкциями: / - person Peter Cordes; 14.09.2017
comment
@PeterCordes В последней версии руководства Intel по внутренним функциям есть новый набор встроенных масок, которые охватывают все. У него новое соглашение об именах, которое заменяет старые! - person Mysticial; 01.04.2019
comment
@PeterCordes Похоже, это GCC 7, ICC 18 и Clang 8. Пока нет поддержки в MSVC. - person Mysticial; 01.04.2019
comment
Интересно; Я посмотрел на заголовки GCC, и у него действительно есть встроенные функции, такие как __builtin_ia32_kaddsi, а не просто оболочки вокруг оператора +, которые позволили бы коду компилироваться без предоставления желаемой функциональности. - person Peter Cordes; 02.04.2019
comment
@PeterCordes Сами типы масок определяются как обычные целые числа. Так что вы в любом случае можете использовать их как обычные целые числа. В конце концов, компилятор выбирает, использовать ли GPR или маскировать регистры. И они почти всегда предпочитают георадары, потому что они быстрее. Очень сложно заставить какой-либо компилятор использовать регистры масок для арифметики без встроенных кодов. - person Mysticial; 02.04.2019