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.