Começando com openmp
Compilação
Existem muitos compiladores que suportam diferentes versões da especificação OpenMP. O OpenMP mantém uma lista aqui com o compilador que o suporta e a versão suportada. Em geral, para compilar (e vincular) um aplicativo com suporte a OpenMP, você precisa apenas adicionar um sinalizador de compilação e, se usar a API OpenMP, precisará incluir o cabeçalho OpenMP (omp.h). Embora o arquivo de cabeçalho tenha um nome fixo, o sinalizador de compilação depende do compilador. A seguir está uma lista não exaustiva de compiladores e o sinalizador que habilita o OpenMP.
- GCC (incluindo gcc, g++ e gfortran):
-fopenmp
- LLVM: -fopenmp
- Suite de compiladores Intel (incluindo icc, icpc e ifort):
-qopenmp
(e-fopenmp
para compatibilidade com GCC/LLVM) - Conjunto de compiladores IBM XL (incluindo xlc, xlC e xlf):
-xlsmp=omp
- PGI compilador-suite (incluindo pgcc pgc++ pgfortran): ‘-mp’
Olá mundo paralelo usando OpenMP
#include <omp.h>
#include <stdio.h>
int main (int argc, char *argv[])
{
#pragma omp parallel
{
printf ("Hello world! I'm thread %d out of %d threads.\n",
omp_get_thread_num(), omp_get_num_threads());
}
return 0;
}
Este código simplesmente cria um time de threads (de acordo com a variável de ambiente OMP_NUM_THREADS
- e se não for definido criará um por núcleo lógico no sistema) e cada thread se identificará além de imprimir a típica mensagem Hello world.
Construção de Compartilhamento de Trabalho - Exemplo de loop For
double res[MAX]; int i;
#pragma omp parallel
{
#pragma omp for
for (i=0;i< MAX; i++) {
res[i] = huge();
}
}
O loop for será executado em paralelo. enorme() é algum método que pode demorar muito para ser executado. O OpenMP suporta um atalho para escrever o código acima como:
double res[MAX]; int i;
#pragma omp parallel for
for (i=0;i< MAX; i++) {
res[i] = huge();
}
Também podemos ter uma cláusula de agendamento que afeta como as iterações de loop são mapeadas para threads. Por exemplo:
#pragma omp parallel
#pragma omp for schedule(static)
for(i=0;I<N;i++) {
a[i] = a[i] + b[i];
}
Diferentes estilos de agendamento são:
horário(estático [,pedaço])
Distribua blocos de iterações de tamanho “pedaço” para cada encadeamento.
Se não for especificado: alocar o mais uniformemente possível para os threads disponíveis
horário(dinâmico[,pedaço])
Cada thread pega iterações “pedaços” de uma fila até que todas as iterações tenham sido tratadas.
horário(guiado[,pedaço])
Threads capturam dinamicamente blocos de iterações. O tamanho do bloco começa grande e diminui para o tamanho “pedaço” à medida que o cálculo prossegue.
programação (tempo de execução)
Agenda e tamanho do bloco retirados da variável de ambiente OMP_SCHEDULE.
Exemplo de redução
#include <omp.h>
void main ()
{
int i;
double ZZ, func(), res=0.0;
#pragma omp parallel for reduction(+:res) private(ZZ)
for (i=0; i< 1000; i++){
ZZ = func(I);
res = res + ZZ;
}
}
Na última linha: realmente adicionado a uma cópia privada, depois combinado após o loop. Compilador cuida dos detalhes.