OpenMP 4.0 вводит новую конструкцию под названием «omp simd». В чем преимущество использования этой конструкции по сравнению со старой «параллелью для»? Когда каждый из них будет лучшим выбором по сравнению с другим?
РЕДАКТИРОВАТЬ:
Вот интересный бумага связанные с директивой SIMD.
Связанный со стандартом относительно ясен (стр. 13, строки 19 + 20)
Когда любой поток встречает конструкцию simd, итерации
цикл, связанный с конструкцией, может выполняться по линиям SIMD
которые доступны в теме.
SIMD
вещь подсистемы Чтобы сделать его более конкретным, на процессоре вы можете представить, используя simd
директивы специально запрашивать векторизации кусков итераций цикла, которые по отдельности принадлежат одному и тому же нить. Он раскрывает несколько уровней параллелизма, которые существуют в одном многоядерном процессоре, независимо от платформы. Смотрите, например, обсуждение (вместе с ускорителем) по этому вопросу. сообщение в блоге Intel.
Итак, в основном, вы хотите использовать omp parallel
распределять работу по разным потокам, которые затем могут мигрировать на несколько ядер; и вы захотите использовать omp simd
использовать векторные конвейеры (скажем) внутри каждого ядра. Обычно omp parallel
будет идти «снаружи», чтобы иметь дело с более грубым параллельным распределением работы и omp simd
будет обходить узкие петли внутри этого, чтобы использовать мелкозернистый параллелизм.
Простой ответ:
OpenMP используется только для использования нескольких потоков для нескольких ядер. Это новый simd
расширение позволяет явно использовать SIMD инструкции на современных процессорах, таких как Intel AVX / SSE и ARM NEON.
(Обратите внимание, что инструкция SIMD выполняется в дизайне в виде одного потока и одного ядра. Однако значение SIMD может быть достаточно расширено для GPGPU. Но, но я не думаю, что вам нужно учитывать GPGPU для OpenMP 4.0. )
Итак, когда вы знаете инструкции SIMD, вы можете использовать эту новую конструкцию.
В современном CPU примерно три типа параллелизма: (1) параллелизм на уровне команд (ILP), (2) параллелизм на уровне потоков (TLP) и (3) инструкции SIMD (можно сказать, что это векторный уровень) или так).
ILP выполняется автоматически вышедшими из строя процессорами или компиляторами. Вы можете использовать TLP, используя OpenMP parallel for
и другие библиотеки потоков. Итак, что насчет SIMD? Intrinsics были способом их использования (а также автоматической векторизацией компиляторов). OpenMP-х simd
это новый способ использования SIMD.
Возьмите очень простой пример:
for (int i = 0; i < N; ++i)
A[i] = B[i] + C[i];
Приведенный выше код вычисляет сумму двух N-мерных векторов. Как вы можете легко увидеть, нет (перенос данных) зависимость от данных на массиве A[]
, Этот цикл смущающе параллельно.
Там может быть несколько способов распараллелить этот цикл. Например, до OpenMP 4.0 это можно распараллелить, используя только parallel for
построить. Каждый поток будет выполнять N/#thread
итерации на нескольких ядрах.
Однако вы можете подумать, что использование нескольких потоков для такого простого добавления было бы излишним. Вот почему существует векторизация, которая в основном реализуется с помощью инструкций SIMD.
Использование SIMD будет выглядеть так:
for (int i = 0; i < N/8; ++i)
VECTOR_ADD(A + i, B + i, C + i);
Этот код предполагает, что (1) инструкция SIMD (VECTOR_ADD
) 256-битный или 8-канальный (8 * 32 бит); и (2) N
кратно 8.
8-канальная инструкция SIMD означает, что 8 элементов в векторе могут быть выполнены в одной машинной инструкции. Обратите внимание, что последняя версия Intel AVX обеспечивает такие 8-канальные (32-битные * 8 = 256 бит) векторные инструкции.
В SIMD вы все еще используете одно ядро (опять же, это только для обычных процессоров, а не для графических процессоров). Но вы можете использовать скрытый параллелизм в оборудовании. Современные процессоры выделяют аппаратные ресурсы для инструкций SIMD, где каждый SIMD полоса дороги может выполняться параллельно.
Вы можете использовать параллелизм на уровне потоков одновременно. Приведенный выше пример может быть дополнительно распараллелен parallel for
,
(Однако я сомневаюсь, сколько циклов можно реально преобразовать в циклы SIMDized. Спецификация OpenMP 4.0 кажется немного неясной в этом отношении. Таким образом, реальная производительность и практические ограничения будут зависеть от реализаций реальных компиляторов.)
Подвести итоги, simd
Конструкция позволяет использовать SIMD-инструкции, в свою очередь, можно использовать больше параллелизма и параллелизма на уровне потоков. Тем не менее, я думаю, что фактические реализации будут иметь значение.
Компиляторы не обязаны выполнять оптимизацию simd в параллельной области при наличии предложения simd. Компиляторы, с которыми я знаком, продолжают поддерживать вложенные циклы, параллельные внешние, векторные внутренние, так же, как и раньше.
В прошлом директивы OpenMP обычно использовались для предотвращения оптимизаций с переключением циклов, включающих внешний параллельный цикл (несколько циклов с предложением collapse). Это, кажется, изменилось в нескольких компиляторах.
OpenMP 4 открывает новые возможности, в том числе оптимизацию параллельного внешнего цикла с не-векторизуемым внутренним циклом, посредством своего рода анализа полосы, когда установлен режим omp parallel do [for] simd. ifort иногда сообщает об этом как о векторизации внешнего цикла, когда это делается без предложения simd. Затем его можно оптимизировать для меньшего числа потоков, чем для параллельной omp do simd, которая, кажется, требует большего количества потоков, чем ширина вектора simd, чтобы окупиться. Такое различие может быть выведено, так как без предложения simd компилятору неявно предлагается оптимизировать счетчик циклов, например 100 или 300, в то время как предложение simd запрашивает безусловную оптимизацию simd.
gcc 4.9 omp параллель для simd выглядела довольно эффектно, когда у меня была 24-ядерная платформа.