Язык программирования HPC, основанный на неявной векторизации

Существуют ли языки программирования или языковые расширения, которые основаны на неявной векторизации?

Мне понадобится что-то, что сделает агрессивные предположения для создания хорошего DLP/векторизованного кода для SSE4.1, AVX, AVX2 (с или без FMA3/4) с единственной/двойной точностью из скалярного кода C.

В течение последних 10 лет мне было весело, полагаясь на встроенные функции Intel, чтобы написать мои ядра HPC, явно векторизованные. В то же время меня постоянно разочаровывает качество DLP-кода, сгенерированного компиляторами C/С++ (GCC, clang, LLVM и т.д., Если вы спросите, я могу опубликовать конкретные примеры).

Из Руководство по использованию, ясно, что запись "вручную" ядер HPC с встроенными функциями для современных платформ уже не является устойчивым вариантом, если у меня нет армии программистов. Слишком много версий и комбинаций: SSE4.1, AVX, AVX2, AVX512 + вкусы, FMA, SP, DP, половина точности? Это просто неустойчиво, если мои целевые платформы, скажем, самые распространенные из них с 2012 года.

Недавно я попробовал компилятор Intel Offline для OpenCL (CPU). Я написал ядро ​​ "a la CUDA" (то есть скалярный код, неявная векторизация), и, к моему удивлению, сгенерированная сборка была очень хорошо векторизована! (Skylake, AVX2 + FMA в SP) Единственное ограничение, с которым я столкнулся, заключалось в отсутствии встроенных функций для сокращения данных/interworkitem-связи, не полагаясь на разделяемую память (что бы перевести на горизонтальные добавления процессора или перетасовать + мин/максимальные операции).

Как указано clemens и sschuberth, автономный компилятор на самом деле не является решением, если я не полностью охватываю OpenCL. Или я взломаю свой код вызывающего абонента, чтобы он соответствовал вызывающему соглашению сгенерированной сборки, которая включает в себя параметры, которые мне не нужны, например ndrange. Полностью охватывающий OpenCL для меня тоже не вариант, поскольку для TLP я полагаюсь на OpenMP и Pthreads (и для ILP я полагаюсь на аппаратное обеспечение).

Update

Во-первых, стоит вспомнить, что неявная векторизация и авторазвитие - это не одно и то же. Фактически, я потерял надежду на автовекторность (как упоминалось выше). Не в неявной векторизации.

В одном из приведенных ниже ответов вы найдете примеры кода. Здесь Я предоставляю пример кода ядра, реализующего схему поджига третьего порядка для конвекционного члена NSE на трехмерном структурированном блоке. Стоит упомянуть, что это представляет собой тривиальный пример, так как не требуется взаимодействие/связь между SIM-картами SIMD.

Ответы

Ответ 1

Компилятор программ Intel SPMD.

В настоящее время лучшим вариантом является Компилятор программ Intel SPMD. ISPC является компилятором с открытым исходным кодом, его модель программирования основана на неявной векторизации (термин, заимствованный из документации Intel OpenCL SDK) для вывода векторизованного кода сборки. ISPC сопоставляет исходные коды инструкциям SSE4.1, AVX, AVX2, KNC и KNL AVX512 для обоих SP/DP. Бэкэнд ISPC - LLVM.

Для ядер CFD он просто обеспечивает непревзойденную производительность. Для частей кода, которые должны быть скалярными, одно просто добавляет "равномерное" ключевое слово к связанным переменным. Существуют встроенные функции для межполосной связи, такие как перетасовка, трансляция и уменьшение_адда и т.д.

Почему ISPC так быстро по сравнению с другими компиляторами на С++? Я предполагаю, что из-за того, что компиляторы C/С++ предполагают, что ничто не может быть векторизовано, если нет четких доказательств обратного. ISPC предполагает, что каждая строка кода (независимо) выполняется всеми SIMD-полосами, если не указано иное.

Интересно, почему ISPC пока не получила широкого распространения. Возможно, это из-за его ювенильного этапа, но он показал уже большие возможности (Embree, OSPray) в сообществе CG/Scientific Visualization. ISPC - хороший вариант для написания ядер HPC, поскольку он, по-видимому, прекрасно сочетает разрыв производительности и производительности.

Benchmark

Для тривиального примера ядра, упомянутого в вопросе, были получены следующие результаты с использованием GCC 4.9.X и ISPC 1.8.2. Производительность сообщается в терминах FLOP за цикл.

введите описание изображения здесь

Результаты ICC здесь не сообщаются (с точки зрения доступности, на 100% честно сообщать ICC о компиляторах с открытым и открытым исходным кодом?). Тем не менее максимальный прирост ICC по отчетности GCC в этом случае составил около 4X, поэтому не ставил под угрозу превосходство ISPC.

Ответ 2

Обратите внимание, что без математического или кодового примера трудно понять, какой лучший ответ здесь. Если вы предоставите пример кода, я попытаюсь реализовать его на некоторых диалектах, указанных ниже.

Fortran 90

Обозначение дробления Fortran 90+ - отличный способ реализовать неявную вектозацию, хотя я подозреваю, что Fortran не является тем, что вы готовы использовать, если вы программист C intrinsics.

Одним из разумных источников информации по этой теме является fortran90.org.

OpenMP 4.0

OpenMP 4.0 представил ключевое слово SIMD, которое заставляет компилятор векторизовать код. Вы должны изучить это как альтернативу внутренним.

Есть много примеров OpenMP 4.0 pragma omp simd онлайн, но очень простой - Включение SIMD в программе с использованием OpenMP4.0.

Очевидно, что окончательный авторитет в OpenMP является последним спецификацией: Интерфейс программирования API OpenMP версии 4.5.

CilkPlus

Поскольку вы уже указали, что готовы писать код, не соответствующий стандарту ISO, вы можете использовать расширения CilkPlus для C/С++, поддерживаемые компилятором Intel и GCC (и возможным Clang/LLVM, но я не проверял).

См. Рекомендации по использованию Intel® Cilk ™ Plus и Домашняя страница CilkPlus для деталей.

OpenCL

OpenCL - еще один хороший вариант в теории, но на практике это кажется менее убедительным. Я сам не являюсь пользователем OpenCL, но я работаю с автором OpenCL Programming Guide, который я считаю надежным источником.

Автовекторизация

Если все остальное не удается, компилятор Intel 16 делает довольно хорошую работу по автогенерации, но вы должны читать отчеты об отчетах, во многих случаях использовать restrict и __assume_aligned.

Лучшее место для начала автообсечения с помощью Intel C/С++ - это вариант -qopt-report компилятора. Это, как правило, говорит вам, что такое векторизация, а не почему. Возможно, вам придется использовать другой распределитель (Зачем использовать _mm_malloc? (В отличие от _aligned_malloc, alligned_alloc или posix_memalign) перечисляет соответствующие параметры), а затем используйте __assume_aligned в вашем ядре. Векторные зависимости могут быть сложнее смягчить, хотя инструкции AVX-512CDI могут помочь, если вы используете процессор Intel Xeon Phi второго поколения (он же Knights Landing) или другой продукт, который их поддерживает.

Компилятор Cray также автогенерирует достаточно хорошо, но ограничивается пользователями, имеющими доступ к суперкомпьютеру Cray.

Для любопытных мой оптимизм в отношении этих компиляторов основан на результатах, полученных с помощью ядер NWChem. Наилучшие результаты получены с помощью Fortran 77, OpenMP 3/4 и использования других директив компилятора, но по крайней мере там нет кода, специфичного для процессора. И ядра C99 достаточно хорошо прорисовывают.

Отказ

Я работаю в области исследований/поиска путей в Intel. Я не работаю ни на одном из наших программных продуктов, но время от времени я получаю от экспертов в команде компилятора.