Upload
idana
View
40
Download
0
Embed Size (px)
DESCRIPTION
Introdução ao OpenMP. Prof. André Leon S. Gradvohl , Dr . [email protected]. Arquiteturas paralelas. Arquiteturas paralelas: Single Instruction Multiple Data Máquinas Vetoriais Multiple Instruction Multiple Data Memória distribuída Memória compartilhada. - PowerPoint PPT Presentation
Citation preview
INTRODUÇÃO AO OPENMP
PROF. ANDRÉ LEON S. GRADVOHL, [email protected]
2
ARQUITETURAS PARALELAS
Arquiteturas paralelas:• Single Instruction Multiple Data
• Máquinas Vetoriais• Multiple Instruction Multiple Data
• Memória distribuída• Memória compartilhada
Onde o OpenMP se encaixa
3
MODELOS DE PROGRAMAÇÃO PARALELA
Modelos de Programação Paralela
• Multiprocessamento• Fork/Join
• Passagem de Mensagens• Exemplo: PVM, MPI
• Multithread• Exemplo: OpenMP, POSIX-Threads
OpenMP (Open MultiProcessing):
• Interface de programação que suporta multiprocessamento em ambientes de memória compartilhada.
4
INTRODUÇÃO AO OPENMP
Estrutura de um programa OpenMP:
• Em Fortran:
PROGRAM HELLOINTEGER VAR1, VAR2, VAR3*** Código serial*** Início da seção paralela. “Fork” um grupo de “threads”.!$OMP PARALLEL PRIVATE(VAR1, VAR2) SHARED(VAR3)*** Seção paralela executada por todas as “threads”*** Todas as “threads” efetuam um “join” a thread mestre e finalizam!$OMP END PARALLEL*** Código serialEND
5
INTRODUÇÃO AO OPENMP
Estrutura de um programa OpenMP:
• Em C:
#include <omp.h>int main () {int var1, var2, var3;*** Código serial*** Início da seção paralela. “Fork” um grupo de “threads”.#pragma omp parallel private(var1, var2) shared(var3){*** Seção paralela executada por todas as “threads”*** Todas as “threads” efetuam um “join” a thread mestre e finalizam}*** Código serial}
6
INTRODUÇÃO AO OPENMP
ObservaçõesFork/Join:
• Quando uma thread chega a uma definição de região paralela, ela cria um conjunto de threads e passa a ser a thread mestre. A thread mestre faz parte do conjunto de threads e possui o número de identificação “0”.
• A partir do início da região paralela, o código é duplicado e todas as threads executarão esse código.
• Existe um ponto de sincronização (“barreira”) no final da região paralela, sincronizando o fim de execução de cada thread. Somente a thread mestre continua desse ponto.
BARR
7
INTRODUÇÃO AO OPENMP
Observações• O número de threads
• Em uma execução com o OpenMP, o número de “threads” é determinado pelos seguintes fatores, em ordem de precedência:1. Utilização da função omp_set_num_threads() no código
Fortran ou C/C++;2. Definindo a variável de ambiente OMP_NUM_THREADS,
antes da execução;3. Implementação padrão do ambiente: número de processadores
em um nó.• Restrições
• Não é permitido caminhar para dentro ou fora (”branch”) de uma estrutura de blocos definida por uma diretiva OpenMP e somente um IF é permitido.
EXEMPLO#include <stdio.h>
#include <omp.h>
int main ()
{ int nthreads, tid;
#pragma omp parallel private(nthreads, tid)
{
tid = omp_get_thread_num();
printf(“Ola Mundo do thread = %d\n”, tid);
if (tid == 0)
{
nthreads = omp_get_num_threads();
printf(“Numero de threads = %d\n”, nthreads);
}
}
}
Faz o fork dos threads e mantém suas próprias
cópias de variáveis.Obtém o número do Thread.
Se tid == 0, então é o thread mestre.
Obtém a quantidade de threads.
Região Paralela
9
CRIAÇÃO DE THREADS#include <stdio.h>
#include <omp.h>
int main()
{
double A[1000];
#pragma omp parallel num_threads(4)
{
int ID = omp_get_thread_num();
pooh(ID,A);
}
return 0;
}
Criação de 4 threads.
Obtém o número do
thread.
10
CRIAÇÃO DE THREADS – EXERCÍCIOSMatematicamente sabe-se que:
Portanto, é possível aproximar esta integral como um somatório:
Onde cada retângulo tem largura x e altura F(xi) no meio do intervalo i.
1
02 )1(
4 x
n
ii xxF
0
)(
11
CRIAÇÃO DE THREADS – EXERCÍCIOSSolução Serial:
static long num_steps = 100000;
double step;
int main ()
{
int i; double x, pi, sum = 0.0;
step = 1.0/(double) num_steps;
for (i=0;i< num_steps; i++){
x = (i+0.5)*step;
sum = sum + 4.0/(1.0+x*x);
}
pi = step * sum;
}
12
CRIAÇÃO DE THREADS – EXERCÍCIOSSolução Paralela
static long num_steps = 100000000;
double step;
int main ()
{
int i,j;
double pi, full_sum = 0.0;
double sum[MAX_THREADS];
step = 1.0/(double) num_steps;
13
CRIAÇÃO DE THREADS – EXERCÍCIOS omp_set_num_threads(MAX_THREADS);
full_sum=0.0;
#pragma omp parallel
{
int i;
int id = omp_get_thread_num();
int numthreads = omp_get_num_threads();
double x;
sum[id] = 0.0;
if (id == 0) printf(" num_threads = %d",numthreads);
for (i=id;i< num_steps; i+=numthreads){
x = (i+0.5)*step;
sum[id] = sum[id] + 4.0/(1.0+x*x);
}
}
Região Paralela
14
CRIAÇÃO DE THREADS – EXERCÍCIOS for(full_sum = 0.0, i=0;i< MAX_THREADS;i++)
full_sum += sum[i];
pi = step * full_sum;
}Agrupamento dos
resultados.(Redução)
15
DIRETIVA DO/FORA diretiva DO/for especifica que as iterações de um laço sejam distribuídas e executadas em paralelo pelo grupo de threads. A região paralela tem que ter sido identificada antes.
Com isso, o programador não precisa de preocupar com a divisão da carga de trabalho entre os threads
Exemplo:
#pragma omp parallel
{
#pragma omp for
for (I=0;I<N;I++)
Faca_algo(I);
}
Define uma região paralela
O comando for será dividido igualmente entre os threads.
Detalhe:a variável I é privativa.
16
DIRETIVA DO/FORAlternativamente, pode-se utilizar a seguinte sintaxe:
Exemplo:
#pragma omp parallel for
for (I=0;I<N;I++) Faca_algo(I);
Cuidado com o uso de outras variáveis dento de um “laço paralelo”!!
As variáveis do laço são privativas de cada thread.
Exemplo:int i, j, A[MAX];j = 5;for (i=0;i< MAX; i++) {
j = j+ 2*i;A[i] = big(j);
}
17
DIRETIVA DO/FOR - REDUÇÃOComo resolver o caso ao lado?
double ave=0.0, A[MAX]; int i;
for (i=0;i< MAX; i++) {
ave + = A[i];
}
ave = ave/MAX;
Resposta: usando uma redução !double ave=0.0, A[MAX]; int i;#pragma omp parallel for reduction (+:ave)for (i=0;i< MAX; i++) {
ave + = A[i];}ave = ave/MAX;
18
DIRETIVA DO/FOR – REDUÇÃO – MAIS DETALHESDentro de uma região paralela:
• É feita uma cópia local de cada variável e inicializada com um valor que depende do tipo de operação, e. g., na operação de + o valor inicial é zero.
• As cópias locais são reduzidas (somadas, multiplicadas etc) em um único valor que, posteriormente, são combinados em uma única variável comum.
Como fica o programa para calcular o com a diretiva for e a redução?
19
DIRETIVA DO/FOR – REDUÇÃO – MAIS DETALHESSolução Paralela
static long num_steps = 100000000;
double step;
int main ()
{
int i,j;
double x, pi, sum = 0.0;
double sum[MAX_THREADS];
step = 1.0/(double) num_steps;
20
DIRETIVA DO/FOR – REDUÇÃO – MAIS DETALHESomp_set_num_threads(MAX_THREADS); sum=0.0;
#pragma omp parallel for reduction (+:sum)
for (i=1;i< num_steps; i++){
x = (i-0.5)*step;
sum= sum + 4.0/(1.0+x*x);
}
pi = step * sum;
}
Região Paralela com redução
21
ATRIBUTOS DE VARIÁVEISAs variáveis no OpenMP podem ser compartilhadas ou não entre os threads. Esse controle é feito através de alguns atributos. São eles:
private: Declara que as variáveis listadas serão de uso específico de cada “thread”. Essas variáveis não são iniciadas.
shared (default) Declara que as variáveis listadas compartilharão o seu conteúdo com todas as threads de um grupo. As variáveis existem em apenas um endereço de memória, que pode ser lido e escrito por todas as threads do grupo.
22
ATRIBUTOS DE VARIÁVEIS
firstprivate: Define uma lista de variáveis com o atributo PRIVATE, mas sendo inicializadas automaticamente, de acordo com o valor que possuíam no thread antes de uma região paralela.
lastprivate: Define uma lista de variáveis com o atributo PRIVATE e copia o valor da última iteração de um laço da última thread que finalizou.
default: Permite que o programador defina o atributo “default” para as variáveis em uma região paralela (PRIVATE, SHARED ou NONE).
23
ATRIBUTOS DE VARIÁVEIS EXEMPLOS
void useless() {
int tmp = 0;
#pragma omp parallel for firstprivate(tmp)
for (int j = 0; j < 1000; ++j)
tmp += j;
printf(“%d\n”, tmp);
}
Cada thread possui sua própria cópia da variável tmp com o valor inicial zero.
24
ATRIBUTOS DE VARIÁVEIS EXEMPLOS
void useless() {
int tmp = 0;
#pragma omp parallel for firstprivate(tmp) lastprivate(tmp)
for (int j = 0; j < 1000; ++j)
tmp += j;
printf(“%d\n”, tmp);
}
A variável tmp termina com o valor do calculado pelo último thread a terminar.
25
SEÇÕESA diretiva sections divide o trabalho de forma não iterativa em seções separadas, aonde cada seção será executada por uma “thread” do grupo. Representa a implementação de paralelismo funcional, ou seja, por código.
Algumas observações:
1. A diretiva sections define a seção do código sequencial onde será definida as seções independentes, através da diretiva section;
2. Cada section é executada por uma thread do grupo;
3. Existe um ponto de sincronização implícita no final da diretiva section, a menos que se especifique o atributo nowait;
4. Se existirem mais threads do que seções, o OpenMP decidirá, quais threads executarão os blocos de section, e quais, não executarão.
26
SEÇÕES- EXEMPLO
#include <omp.h>
#define N 1000
int main () {
int i, n=N;
float a[N], b[N], c[N];
for (i=0; i < N; i++) a[i] = b[i] = i * 1.0;
#pragma omp parallel shared(a,b,c,n) private(i) {
#pragma omp sections nowait {
#pragma omp section
for (i=0; i < n/2; i++)
c[i] = a[i] + b[i];
#pragma omp section
for (i=n/2; i < n; i++)
c[i] = a[i] + b[i];
} /* fim seções*/
} /* fim parallel */
}
Definição de uma área de seções.
Primeira seção
Segunda seção
27
UNICIDADEA diretiva single determina que o código identificado seja executado por somente uma thread do grupo.
Os threads do grupo que não executam a diretiva single, esperam o fim do processamento da thread que executa a diretiva, a menos que se especifique o atributo nowait.
A diretiva ordered determina que as iterações do laço na região paralela, sejam executados na ordem sequêncial.
28
UNICIDADE- EXEMPLOS#pragma omp parallel
{
do_many_things();
#pragma omp single
{
exchange_boundaries();
}
do_many_other_things();
}
Apenas um thread vai executar esse trecho de código.
Detalhe: nesse caso todos os threads aguardarão até que o bloco single seja
executado.
29
UNICIDADE- EXEMPLOS#pragma omp parallel private (tmp)
#pragma omp for ordered reduction(+:res)
for (I=0;I<N;I++){
tmp = NEAT_STUFF(I);
#pragma ordered
res += consum(tmp);
}
Os threads executarão os trechos de código um de cada vez, de forma
sequencial.