Поделиться через


Ошибки и предупреждения Автоматический-Parallelization

Автоматический параллелизатор и автоматический векторизатор обеспечивают автоматическое повышение производительности циклов в коде.

Автоматический параллелизатор

Переключатель компилятора /Qpar включает автоматическую параллелизацию циклов в коде. Если установить этот флажок без изменения существующего кода, компилятор проанализирует код, чтобы выявить циклы, выполнение которых можно ускорить благодаря параллелизации. Компилятор может обнаружить циклы, которые не представляют большую нагрузку и по которым не получается выигрыш от параллелизации. Для организации параллелизации может потребоваться создание пула потоков, дополнительная синхронизация или другая обработка, которая вместо повышения производительности может привести к ее снижению. Поэтому компилятор строго оценивает возможность выигрыша при выборе циклов для параллелизации. Например, рассмотрим случай, в котором верхняя граница цикла неизвестна во время компиляции.

void loop_test(int u) {
   for (int i=0; i<u; ++i)
      A[i] = B[i] * C[i];
}

Поскольку значение u может быть маленьким, компилятор не будет выполнять автоматическую параллелизацию этого цикла. Допустим, вам известно, что значение u всегда будет большим и параллелизацию этого цикла желательно выполнить. Чтобы включить автоматическую параллелизацию, укажите #pragma loop(hint_parallel(n)), где n — количество потоков для сквозной параллелизации. В приведенном ниже примере компилятор попытается выполнить параллелизацию цикла по 8 потокам.

void loop_test(int u) {
#pragma loop(hint_parallel(8))
   for (int i=0; i<u; ++i)
      A[i] = B[i] * C[i];
}

Как и во всех директивах pragma, поддерживается также дополнительный синтаксис pragma __pragma(loop(hint_parallel(n))).

Существуют такие циклы, для которых компилятор не сможет выполнить параллелизацию, даже если вы захотите это сделать. Ниже приведен пример:

#pragma loop(hint_parallel(8))
for (int i=0; i<upper_bound(); ++i)
    A[i] = B[i] * C[i];

Функция upper_bound() может меняться при каждом вызове. Поскольку верхняя граница неизвестна, компилятор может вывести диагностическое сообщение, объясняющее, почему он не может выполнить параллелизацию этого цикла. В приведенном ниже примере демонстрируется цикл, в котором может выполняться параллелизация, цикл, в котором не может выполняться параллелизация, синтаксис компилятора для командной строки и выходные данные компилятора для каждого параметра командной строки:

int A[1000];
void test() {
#pragma loop(hint_parallel(0))
    for (int i=0; i<1000; ++i) {
        A[i] = A[i] + 1;
    }

    for (int i=1000; i<2000; ++i) {
        A[i] = A[i] + 1;
    }
}

При компиляции с помощью команды:

cl d:\myproject\mylooptest.cpp /O2 /Qpar /Qpar-report:1

получаются следующие выходные данные:

--- Analyzing function: void __cdecl test(void)
d:\myproject\mytest.cpp(4) : loop parallelized

При компиляции с помощью команды:

cl d:\myproject\mylooptest.cpp /O2 /Qpar /Qpar-report:2

получаются следующие выходные данные:

--- Analyzing function: void __cdecl test(void)
d:\myproject\mytest.cpp(4) : loop parallelized
d:\myproject\mytest.cpp(4) : loop not parallelized due to reason '1008'

Обратите внимание на различие в выходных данных для двух различных параметров /Qpar-report (уровень отчетности автоматического параллелизатора). /Qpar-report:1 выводит сообщения параллелизатора только для тех циклов, параллелизация которых успешно выполнена. /Qpar-report:2 выводит сообщения параллелизатора как для выполненных, так и для невыполненных параллелизаций цикла.

Дополнительные сведения о кодах причин и сообщениях см. в разделе Сообщения векторизатора и параллелизатора.

Автоматический векторизатор

Автоматический векторизатор анализирует циклы в коде и использует векторные регистры и инструкции на целевом компьютере для их выполнения, если это возможно. Это может повысить производительность кода. Компилятор реализует инструкции SSE2, AVX и AVX2 в процессорах Intel и AMD или инструкции NEON в процессорах ARM в соответствии с переключателем /arch.

Автоматический векторизатор может создавать инструкции, отличные от указанных в переключателе /arch. Эти инструкции защищены проверкой среды выполнения, гарантирующей, что код все еще работает правильно. Например, при компиляции /arch:SSE2 могут быть выданы инструкции SSE4.2. При проверке среды выполнения проверяется, что инструкция SSE4.2 доступна на целевом процессоре, и осуществляется переход к версии цикла, отличной от SSE4.2, если процессор не поддерживает эти инструкции.

По умолчанию автоматический векторизатор включен. Если вы хотите сравнить производительность векторизированного кода, можно использовать #pragma loop(no_vector) для отключения векторизации любого цикла.

#pragma loop(no_vector)
for (int i = 0; i < 1000; ++i)
   A[i] = B[i] + C[i];

Как и во всех директивах pragma, поддерживается также дополнительный синтаксис pragma __pragma(loop(no_vector)).

Как и в случае с автоматическим параллелизатором, вы можете указать параметр командной строки /Qvec-report (уровень отчетности автоматического векторизатора), чтобы получать отчет только о циклах с успешно выполненной векторизацией (/Qvec-report:1) или о циклах как с выполненной, так и с невыполненной векторизацией (/Qvec-report:2).

Дополнительные сведения о кодах причин и сообщениях см. в разделе Сообщения векторизатора и параллелизатора.

Пример, в котором показано, как векторизатор работает на практике, см. в разделе Project Austin (часть 2 из 6): изгиб страницы.

См. также

Ссылки

цикл

/Qpar (автоматический параллелизатор)

/Qpar-report (уровень отчетности автоматического параллелизатора)

/Qvec-report (уровень отчетности автоматического векторизатора)

Другие ресурсы

Параллельное программирование с помощью собственного кода

Сообщения векторизатора и параллелизатора