Комментарии 16
Хорошая статья, просто доступно и понятно. Жаль что не для всех компиляторов и языков.
Не хватает сравнения с существующими решениями и планируемым std::simd.
Как у вас с поддержкой масштабируемых векторных расширений (когда размер регистра неизвестен во время компиляции)?
Тут стало непонятно. Компилируем же на конкретную платформу или размер SIMD регистра имеет .. переменную длину? )
Компилируем под конкретный набор инструкций (например SVE), но при этом код может исполняться на разных моделях процессоров с разным размером векторных регистров и ожидается, что он автоматически будет их полностью использовать. Вот тут, например, популярно излагается.
это avx инструкции а у них размер вектора известен изначально), и еще либа SIMDe помогает компилировать под конкретную архитектуру
С AVX всё понятно, вопрос с поддержкой других архитектур и расширений. Скажем, как вы преобразуете AVX512 интринсик в SVE инструкции, где размер регистра может быть от 128 до 2048 бит (и нет отдельных инструкций для разных размеров регистра, как в SSE/AVX/AVX512)?
SIMDe это слой совместимости, а не прямой транслятор один в один. То есть если мы вызываем AVX-512 интринсик на архитектуре с SVE, библиотека использует циклы или несколько инструкций SVE, чтобы заполнить требуемый объем данных
подробнее лучше прочитать на официальном GitHub(я закрепил вроде)
Выглядит так, что на каждый AVX512 интринсик придётся генерировать цикл (чтобы работало на железке со 128/256 битными векторами), при этом процессор с векторами больше 512бит выигрыша не даст. Проблема тут скорее в том, что нормальное использование масштабируемых расширений требует специфического паттерна для циклов, в которых обрабатываются массивы (чтобы за итерацию обработать столько элементов, сколько позволяет железо, отсекая ненужные элементы на последней итерации) и перевод на уровне отдельных интринсиков/инструкций с "интеловского языка" вряд ли можно сделать эффективным. Хотя в принципе именно на AVX 512 с масками код можно писать похоже и как то (полу)автоматически адаптировать его к произвольному размеру регистра.
За всё надо платить. Режим КЭП-Очевидность выключен. )
Вопрос в самом подходе - насколько хорошо писать на интринсиках для конкретной архитектуры и потом генерировать из них код под другие по сравнению с более абстрактным интерфейсом.
Я бы переформулировал иначе: если задача настолько число-молотильная, что требует интринсиков, то стоит ли её переносить на, скажем, неродные ей архитектуры? Согласитесь, что нет смысла обучать ИИ на каком-нибудь 16-битном AVR (или чего проще) .. процессоры делают под задачи, а не наоборот..
Да, для специфических задач типа ИИ имеет смысл заводить отдельное железо. Но и обычные алгоритмы типа поиска подстроки в строке вполне себе ускоряются с помощью SIMD расширений на обычных процессорах (навскидку здесь библиотечка), и тут вопрос как проще написать код с поддержкой разных архитектур.
на самом деле я слышал что при использовании AVX-512 падает частота процессора, но насколько правда сказать не могу(собственно по этому я использую в основном AVX-256)
но я советую еще использовать на всякий Atomic, через либу stdatomic.h, тогда race condition не будет(если сделать через ring buffering и очереди степени двойки). Но это не относится к вашему вопросу :)
С переходом на simd начинается веселье типа:
как быстро удалить элементы из x[], y[], z[] массивов
ни в коем случае не использовать скаляры, иначе производительность падает в 5 раз
как сделать ветвление: сгруппировать по типам или использовать маски
как выбрать определенные элементы из массива и плотно упаковать их не переходя на скаляры
как разместить иерархию в памяти: проще когда по 16 нод цепляется, но такого не бывает и нужно заполнить например один simd регистр из 3х родителей и второй simd из 16 их детей и не потерять на этом производительность

SIMDe, дополнение к DOD архитектуре