Paralelização automática e vetorização automática
A paralelização automática e a vetorização automática foram projetadas para fornecer ganhos automáticos de desempenho para loops no seu código.
Paralelizador automático
O comutador do compilador /Qpar permite a paralelização automática de loops no seu código. Quando você especifica esse sinalizador sem alterar o código existente, o compilador avalia o código para localizar loops que podem se beneficiar da paralelização. Como ele pode encontrar loops que não têm muita atividade e, portanto, não se beneficiarão da paralelização, e como toda paralelização desnecessária pode provocar a geração de um pool de threads, sincronização extra ou outro processamento que tende a diminuir o desempenho em vez de melhorá-lo, o compilador é conservador ao selecionar os loops que paraleliza. Por exemplo, considere o exemplo a seguir no qual o limite superior do loop não é conhecido no tempo de compilação:
void loop_test(int u) {
for (int i=0; i<u; ++i)
A[i] = B[i] * C[i];
}
Como u
pode ser um valor pequeno, o compilador não paralelizará automaticamente esse loop. No entanto, talvez você ainda queira paralelizar porque sabe que u
sempre será grande. Para habilitar a paralelização automática, especifique #pragma loop(hint_parallel(n)), em que n
é o número de threads a serem paralelizados. No exemplo a seguir, o compilador tentará paralelizar o loop em 8 threads.
void loop_test(int u) {
#pragma loop(hint_parallel(8))
for (int i=0; i<u; ++i)
A[i] = B[i] * C[i];
}
Assim como acontece com todas as diretivas de pragma, também há suporte para a sintaxe __pragma(loop(hint_parallel(n)))
de pragma alternativa.
Existem alguns loops que o compilador não pode paralelizar, mesmo se você quiser. Veja um exemplo:
#pragma loop(hint_parallel(8))
for (int i=0; i<upper_bound(); ++i)
A[i] = B[i] * C[i];
A função upper_bound()
pode mudar sempre que for chamada. Como o limite superior não pode ser conhecido, o compilador pode emitir uma mensagem de diagnóstico que explica por que ele não pode paralelizar esse loop. O exemplo a seguir demonstra um loop que pode ser paralelizado, um loop que não pode ser paralelizado, a sintaxe do compilador a ser usada no prompt de comando e a saída do compilador para cada opção de linha de comando:
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;
}
}
Compilar usando este comando:
cl d:\myproject\mylooptest.cpp /O2 /Qpar /Qpar-report:1
produz esta saída:
--- Analyzing function: void __cdecl test(void)
d:\myproject\mytest.cpp(4) : loop parallelized
Compilar usando este comando:
cl d:\myproject\mylooptest.cpp /O2 /Qpar /Qpar-report:2
produz esta saída:
--- 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 a diferença na saída entre as duas opções diferentes de /relatório Qpar (Nível de relatório do paralelizador automático). /Qpar-report:1
gera mensagens do paralelizador somente para loops que são paralelizados com êxito. /Qpar-report:2
gera mensagens paralelizadores para paralelizações de loop bem-sucedidas e malsucedidas.
Para obter mais informações sobre códigos de motivos e mensagens, confira Mensagens do vetorizador e paralelizador.
Vetorizador automático
O vetorizador automático analisa loops no seu código e usa os registros e instruções de vetor no computador de destino para executá-los, se possível. Isso pode ajudar a melhorar o desempenho do código. O compilador tem como alvo as instruções SSE2, AVX e AVX2 em processadores Intel ou AMD, ou as instruções NEON em processadores ARM, de acordo com o comutador /arch.
O vetorizador automático pode gerar instruções diferentes das especificadas pelo comutador /arch
. Essas instruções são protegidas por uma verificação de runtime para garantir que o código ainda seja executado corretamente. Por exemplo, quando você compila /arch:SSE2
, as instruções SSE4.2 podem ser emitidas. Uma verificação de runtime verifica se o SSE4.2 está disponível no processador de destino e salta para uma versão não SSE4.2 do loop se o processador não oferecer suporte a essas instruções.
Por padrão, o vetorizador automático está habilitado. Se quiser comparar o desempenho do código sob vetorização, você pode usar #pragma loop(no_vector) para desabilitar a vetorização de algum loop específico.
#pragma loop(no_vector)
for (int i = 0; i < 1000; ++i)
A[i] = B[i] + C[i];
Assim como acontece com todas as diretivas de pragma, também há suporte para a sintaxe __pragma(loop(no_vector))
de pragma alternativa.
Assim como acontece com o paralelizador automático, você pode especificar a opção de linha de comando Relatório /Qvec (Nível de relatório do vetorizador automático) para relatar somente loops vetorizados com êxito /Qvec-report:1
, ou loops vetorizados com e sem sucesso /Qvec-report:2
.
Para obter mais informações sobre códigos de motivos e mensagens, confira Mensagens do vetorizador e paralelizador.
Para obter um exemplo mostrando como o vetorizador funciona na prática, consulte Projeto Austin Parte 2 de 6: Enrolamento de página
Confira também
loop
Programação paralela em código nativo
/Qpar (paralelizador automático)
/Qpar-report (nível de relatórios do paralelizador automático)
/Qvec-report (nível de relatórios do vetorizador automático)
Mensagens do vetorizador e do paralelizador