Ошибки и предупреждения Автоматический-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 (уровень отчетности автоматического векторизатора)