2. OpenMP
● Origem;
● Visão Geral;
● Objetivos;
● Prós e Contras;
● Modelo de Memória e Execução;
● Serviços OpenMP;
● Variáveis de ambiente;
● Diretivas e Cláusulas.
3. Origem
● No início dos anos 90, fabricantes de máquinas com memória
compartilhada forneciam extensões para programação
paralela em Fortran;
● As implementações permitiam ao usuário inserir diretivas para
indicar onde loops deveriam ser paralelizados e os
compiladores eram responsáveis pela paralelização;
● Implementações funcionalmente parecidas, mas não portáveis
e começaram a divergir;
● ANSI X3H5 em 1994 foi a primeira tentativa de padronização.
4. Origem
● A especificação padrão OpenMP começou em 1997 partindo
do padrão X3H5 graças ao aparecimento de novas
arquiteturas de máquinas de memória compartilhada;
● Alguns parceiros na especificação:
○ Compaq, HP, Intel, IBM, Silicon, Sun
○ Absoft, GENIAS, Myrias, The Portland Group
○ ANSYS, Dash, ILOG CPLEX, Livermore, NAG
● A API para Fortran foi liberada em Outubro de 1997 e para
C/C++ no final de 1998.
6. Visão Geral
● Biblioteca de mais alto nível para programação paralela;
● Prevê memória compartilhada;
● Requer suporte do compilador;
● Exige biblioteca específica com implementações thread safe.
8. Objetivos OpenMP
● Prover um padrão para uma variedade de plataformas e
arquiteturas baseadas em memória compartilhada;
● Estabelecer um conjunto limitado e simples de diretivas para
programação utilizando memória compartilhada;
● Prover capacidade para paralelizar um programa de forma
incremental;
● Implementar paralelismo com granulosidade fina e grossa
● Suportar Fortran, C e C++.
9. Por que usar OpenMP?
● Facilidade de conversão de programas sequênciais em
paralelos;
● Maneira simples de explorar paralelismo;
● Fácil compreensão e uso das diretivas;
● Minimiza a interferência na estrutura do algoritmo;
● Compila e executa em ambientes paralelos e sequencial.
10. Por que não usar OpenMP?
● Requer um compilador que suporta OpenMP;
● A escalabilidade é limitada pela arquitetura de memória;
● Manipulação segura do erro está em falta;
● Carece de mecanismo refinado para controlar o
mapeamento thread-processor.
11. Modelo de Memória
➔ Memória distribuída
● Sistema computacional constituído de vários
processadores dotados de recursos
individuais;
● Este sistema se caracteriza pela troca de
mensagem entre os processadores;
● A troca de mensagem é feita por uma
biblioteca de comunicação (MPI).
Modelo de programação baseado em MPI
12. Modelo de Memória
➔ Memória compartilhada
● Sistema computacional constituído de vários
processadores que compartilham o mesmo
recurso de memória;
● É necessário a sincronização do acesso aos
dados na memória compartilhada pelos
processadores.
OpenMP, Threads, Posix Threads
14. Modelo de Execução Fork - Join
OpenMP usa o modelo fork-join para paralelizar a execução
FORK: A thread principal cria um grupo de threads paralelas;
JOIN: Quando grupo threads completa a região paralela, ele
sincroniza e finaliza, mantendo apenas a thread principal.
16. Serviços do OpenMP
● Biblioteca de serviços
○ Permite controlar e interagir com o ambiente de execução.
● Exemplos:
○ omp_get_thread_num()
○ omp_set_num_threads(nthreads)
○ omp_get _num_threads()
○ omp_set_num_threads()
○ omp_get_max_threads()
○ omp_set_nested()
17. Variáveis de ambiente
➢ OMP_NUM_THREADS
○ Identifica o número de atividades que serão executadas em paralelo;
○ (default: número de processadores).
➢ OMP_DYNAMIC
○ Indica se o número de atividades a serem executadas em paralelo
deve ou não ser ajustado dinamicamente;
○ (default:FALSE).
➢ OMP_NESTED
○ Indica se deve ser contemplado ativação de paralelismo aninhado;
○ (default: FALSE).
➢ OMP_SCHEDULE
○ Define esquema de escalonamento das atividades paralelas.
○ (default: estático).
18. Diretivas de compilação
➢ A maioria dos construtores em OpenMP são diretivas do compilador ou pragmas;
➢ Diretivas consiste em uma linha de código com significado “especial” para o
compilador;
➢ Para C e C++, a diretiva possui a seguinte forma:
○ #pragma omp construct [clause [clause] …]
○ Ex. #pragma omp parallel
➢ Para Fortran:
○ !$OMP PARALLEL
➢ Pragma Parallel
○ Define uma região paralelizável sobre um bloco estruturado de código;
○ As threads bloqueiam no fim da região;
○ Os dados são compartilhados (shared) entre as threads ao menos que seja
especificados de outra forma.
19. Um exemplo genérico
#include <omp.h>
main ( ){
//Código seqüencial (master)
#pragma omp parallel
{
// Código paralelo ….
}
// Código seqüencial (master)
}
Região Paralela
20. Hello World
#include <omp.h>
#include <stdio.h>
int main() {
int nthreads;
omp_set_num_threads(4); // Configura o número de treads
#pragma omp parallel{
printf("Hello World da thread %dn", omp_get_thread_num());
if ( omp_get_thread_num() == 0 ) {
nthreads = omp_get_num_threads();
printf("Existem %d threadsn",nthreads);
}
}// Final da Região Paralela
return 0;
}
22. Diretivas e Cláusulas
● Diretivas
○ Construtor Paralelo
#pragma omp parallel
○ Construtores de trabalho
#pragma omp for
#pragma omp single
#pragma omp sections
○ Construtores de sincronização
#pragma omp critical
#pragma omp master
#pragma omp atomic
#pragma omp barrier
#pragma omp flush
#pragma omp ordered
#pragma omp threadprivate
● Cláusulas
Definem o comportamento das
regiões e das variáveis aos quais
estão associadas
shared
private
firstprivate
lastprivate
num_threads
schedule
default
ordered
copyn
copyprivate
if
nowait
reduction
23. Diretiva / Construtor paralelo
● parallel
○ Informa ao compilador a existência de uma região que deve ser executada em
paralelo.
omp_set_num_threads(4);
#pragma omp parallel
{
int i;
printf(“n”);
for( i = 0; i< 2; i++)
printf(“Iteração = %dn”, i);
}
24. Diretiva / Construtor paralelo
● parallel Cláusula reduction
○ reduction(operador:variável), permite operar sobre o valor de uma variável;
○ Cada execução pode manipular sua cópia, como em private;
○ O valor local inicial é definido pela operação de redução;
○ No final uma operação de redução atualiza o dados na thread master.
int soma=100;
omp_set_num_threads(4);
#pragma omp parallel reduction(+:soma)
{
soma +=1;
}
//No retorno ao master a soma=104
25. Diretiva / Construtor de trabalho
● for / parallel for
○ Permite que os grupos de instruções definidas em um loop sejam
paralelizadas.
float dot_prod(float* a, float* b, int N){
float sum =0.0;
#pragma omp parallel for shared(sum)
for(int i=0;i<N;i++){
sum+=a[i]*b[i];
}
return sum;
}
26. Paralelismo aninhado
● Dentro de uma região paralela, quando as threads encontram outro construtor
paralelo, elas criam novos grupos de threads e tornam-se as threads mestre
desses novos grupos;
● Essas regiões são denominadas regiões paralelas aninhadas e por padrão são
executadas de forma sequêncial, ou seja, o novo grupo criado contém apenas uma
thread, que é a própria thread mestre do grupo.
#pragma omp parallel {
#pragma omp parallel for
for( int i = 0; i < n; i++ ){
#pragma omp parallel for
for( int i = 0; i < n; i++ )
c[i] = a[i]+b[i];
}
}
27. Diretiva / Construtor de trabalho
● single
○ Indica que em uma região paralela ou um trecho de código deve ser executado
apenas por uma única thread.
#pragma omp parallel num_threads(6)
{
#pragma omp single
printf(“ler a entrada”);//somente uma thread lê entrada
printf(“calcular resultado”);//Várias threads calculam o resultado
#pragma omp single
printf(“escreve na saida”); // somente uma thread escreve na saída
}
28. Diretiva / Construtor de trabalho
● single [nowait]
○ com nowait a barreira pode ser relaxada.
#pragma omp parallel
{
#pragma omp single
printf(“Serão %d threads n”, omp_get_num_threads())
taskA();
#pragma omp single nowait
printf(“A thread %d terminou n”, omp_get_thread_num());
}
29. Diretiva / Construtor de trabalho
● sections
○ Cria seções paralelas;
○ Cada seção será executada em uma thread diferente.
main (){
int x=2;
#pragma omp sections{
#pragma omp section
{ taskA(x); }
#pragma omp section
{ taskB(x); }
}
}
30. Diretiva / Construtor de sincronização
● critical[(nome)]
○ Permite que trechos de código sejam executados em regime de exclusão
mútua.
int prox_x, prox_y;
#pragma omp parallel shared(x,y) private (prox_x, prox_y)
{
#pragma omp critical(eixox)
prox_x = dequeue(x);
taskA(prox_x,x);
#pragma omp critical(eixoy)
prox_y = dequeue(y);
taskA(prox_y,y);
}
31. Diretiva / Construtor de sincronização
● master [nowait]
○ Indica que em uma região paralela ou um trecho de código deve ser executado
apenas pela thread master;
○ Representa uma barreira;
○ com nowait a barreira pode ser relaxada.
#pragma omp parallel
{
#pragma omp master
printf(“Serão %d threads n”, omp_get_num_threads());
foo();
#pragma omp master nowait
printf(“A thread master terminou n”);
}
32. Diretiva / Construtor de sincronização
● atomic [read, write, update e capture]
Especifica que uma posição de memória deve ser atualizada atomicamente.
#pragma omp atomic
● barrier
Quando esta directiva é alcançada por uma thread, este espera até que os
restantes chegem ao mesmo ponto.
#pragma omp barrier
● flush
Identifica um ponto de sincronização no qual é necessário providenciar uma
visão consistente memória.
#pragma omp flush
33. Cláusula - Schedule
● Cláusula: schedule
○ Afeta como as iterações do laço são mapeadas entre as threads
○ schedule(static [,chunk])
■ Blocos de iterações de tamanho “chunk”
■ Distribuição Round robin
○ schedule(dynamic [,chunk])
■ Iteração de tamanho “chunk”
■ Ao terminar as iterações, a thread requisita o próximo passo
○ schedule(guided [,chunk])
■ Agendamento dinâmico iniciado com um tamanho grande
■ O tamanho dos blocos diminui, não menor do que “chunk”
36. Cláusula - IF
● Cláusula: if(expressão lógica)
○ Se a expressão lógica for verdadeira a região paralela será executada por mais
de uma thread.
void test(int val){
#pragma omp parallel if (val==2)
if (omp_in_parallel()){
#pragma omp single
printf("val = %d, paralelizado com %d threadsn", val,
omp_get_num_threads());
}else {
printf("val = %d, serializadon", val);
}
}
Chamando:
test(0);
test(1);
test(2);
Saída:
val = 0, serializado
val = 1, serializado
val = 2, paralelizado com 2 threads
37. Cláusula - Private
● Cláusula: private
○ Especifica que cada thread deve ter sua própria instância de uma variável;
○ A variável não é inicializada;
○ Alterações de valor dentro da região paralela não são visíveis fora;
○ Utilizando firstprivate ou lastprivate o valor de i é inicializado com o valor
antes do início da região paralela.
int i=10;
#pragma omp parallel private(i)
{
printf("thread %d: i = %dn", omp_get_thread_num(), i);
i = 100 + omp_get_thread_num();
}
printf("i = %dn", i);
thread 0: i = 0
thread 3: i = 0
thread 1: i = 32696
thread 2: i = 0
i = 10
38. Mais sobre OpenMP
● Site oficial
http://openmp.org/
● OpenMP Forum
http://openmp.org/forum/
● The Community of OpenMP Users, Researchers, Tool Developers and Providers
http://www.compunity.org/
● C++ and OpenMP
http://www.compunity.org/events/pastevents/parco07/parco_cpp_openmp.pdf
● OpenMP C and C++ Application Program Interface
http://www.openmp.org/mp-documents/cspec20.pdf