Paralelización y vectorización automáticas

El paralelizador automático y el vectorizador automático se han diseñado para proporcionar mejoras automáticas de rendimiento de los bucles en el código.

Paralelizador automático

El modificador del compilador /Qpar permite la paralelización automática de bucles en el código. Cuando se especifica este marcador sin cambiar el código existente, el compilador evalúa el código para buscar los bucles que podrían beneficiarse de la paralelización. Dado que podría encontrar bucles que no hacen mucho trabajo y, por tanto, no se beneficiarán de la paralelización, y debido a que cada paralelización innecesaria puede acaparar un grupo de subprocesos o producir sincronización adicional u otro procesamiento que tendería a disminuir el rendimiento en lugar de mejorarlo, el compilador es conservador en la selección de los bucles que ejecuta en paralelo. Por ejemplo, considere el siguiente ejemplo en el que el límite superior del bucle no se conoce en tiempo de compilación:

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

Dado que u puede ser un valor pequeño, el compilador no paralelizará automáticamente este bucle. Sin embargo, es posible que el usuario todavía desee paralelizarlo porque sabe que u siempre será grande. Para habilitar la paralelización automática, especifique #pragma loop(hint_parallel(n)), donde es el número de subprocesos en los que se va a paralelizar. En el ejemplo siguiente, el compilador intentará paralelizar el bucle entre 8 subprocesos.

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

Al igual que con todas las directivas pragma,también se admite la sintaxis pragma alternativa.

Hay algunos bucles que el compilador no puede paralelizar aunque lo desee. Veamos un ejemplo:

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

La función upper_bound() puede cambiar cada vez que se la llama. Dado que el límite superior no puede conocerse, el compilador puede emitir un mensaje de diagnóstico que explica por qué no se puede paralelizar este bucle. En el ejemplo siguiente se muestra un bucle que se puede paralelizar, un bucle que no se puede paralelizar, la sintaxis del compilador que se usa en el símbolo del sistema y la salida del compilador para cada opción de línea de comandos:

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;
    }
}

La compilación con este comando:

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

produce este resultado:

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

La compilación con este comando:

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

produce este resultado:

--- 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'

Observe la diferencia en la salida entre las dos opciones diferentes de /Qpar-report (Nivel de informes de paralelizador automático). /Qpar-report:1 genera mensajes del paralelizador solo para los bucles que se paralelizan correctamente. /Qpar-report:2 genera mensajes del paralelizador para las paralelizaciones de bucles correctas e incorrectas.

Para obtener más información sobre los códigos de motivo y los mensajes, vea Vectorizer and Parallelizer Messages.

Vectorizador automático

El vectorizador automático analiza los bucles del código y usa los registros y las instrucciones de vector en el equipo de destino para ejecutarlos si puede. Esto puede mejorar el rendimiento del código. El compilador tiene como destino las instrucciones SSE2, AVX y AVX2 en procesadores Intel o AMD, o las instrucciones NEON en procesadores ARM, según el modificador /arch.

El vectorizador automático puede generar instrucciones diferentes de las que especifica el modificador /arch. Estas instrucciones estarán protegidas por una comprobación en tiempo de ejecución para asegurarse de que código se ejecuta correctamente. Por ejemplo, cuando se compila /arch:SSE2, se pueden emitir instrucciones SSE4.2. Una comprobación en tiempo de ejecución comprueba que SSE4.2 está disponible en el procesador de destino y salta a una versión no SSE4.2 del bucle si el procesador no admite las instrucciones.

De forma predeterminada, se habilita el vectorizador automático. Si desea comparar el rendimiento del código en vectorización, puede usar #pragma loop(no_vector) para deshabilitar la vectorización de cualquier bucle determinado.

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

Al igual que con todas las directivas pragma,también se admite la sintaxis pragma alternativa.

Al igual que con el paralelizador automático, puede especificar la opción de línea de comandos /Qvec-report (Nivel de informes de vectorizador automático) para notificar solo bucles vectorizados correctamente ( o bucles vectorizados correcta e /Qvec-report:2 incorrectamente).

Para obtener más información sobre los códigos de motivo y los mensajes, vea Vectorizer and Parallelizer Messages.

Para ver un ejemplo en el que se muestra cómo funciona el vectorizador en la práctica, Project de La parte 2 de 6: Curling de página

Vea también

bucle
Programación paralela en código nativo
/Qpar (Paralelizador automático)
/Qpar-report (Nivel de informes de paralelizador automático)
/Qvec-report (Nivel de informes del vectorizador automático)
Mensajes de vectorizador y paralelizador