OpenMP Day 2

797 views
740 views

Published on

Training/Presentation (in Portuguese) about OpenMP an API to support shared memory multiprocessing.
Day 2.

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
797
On SlideShare
0
From Embeds
0
Number of Embeds
11
Actions
Shares
0
Downloads
0
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

OpenMP Day 2

  1. 1. OpenMPDia 2 <br />André Leon S. Gradvohl, Dr.<br />andre.gradvohl@gmail.com<br />
  2. 2. Plano de Apresentação Dia – 2<br />Esta apresentação trata da criação de Threads e algumas técnicas de sincronização usando OpenMP.<br />
  3. 3. Criação de Threads<br />Criação de 4 threads.<br />#include <stdio.h><br />#include <omp.h><br />int main()<br />{<br />double A[1000];<br />#pragma omp parallel num_threads(4)<br /> {<br /> int ID = omp_get_thread_num();<br /> pooh(ID,A);<br /> }<br /> return 0;<br />}<br />Obtém o número do thread.<br />
  4. 4. Criação de Threads<br />Especifica a criação de 4 threads.<br />#include <stdio.h><br />#include <omp.h><br />int main()<br />{<br />double A[1000];<br />omp_set_num_threads(4);<br />#pragma omp parallel<br /> {<br /> int ID = omp_get_thread_num();<br /> pooh(ID,A);<br /> }<br /> return 0;<br />}<br />Obtém o número do thread.<br />
  5. 5. Criação de Threads – Exercícios<br />Matematicamente sabe-se que:<br />Portanto, é possível aproximar esta integral como um somatório:<br />Onde cada retângulo tem largura x e altura F(xi) no meio do intervalo i.<br />
  6. 6. Criação de Threads – Exercícios<br />Solução Serial:<br />static long num_steps = 100000;<br />double step;<br />int main ()<br />{ <br /> int i; double x, pi, sum = 0.0;<br /> step = 1.0/(double) num_steps;<br /> for (i=0;i< num_steps; i++){<br /> x = (i+0.5)*step;<br /> sum = sum + 4.0/(1.0+x*x);<br /> }<br /> pi = step * sum;<br />}<br />
  7. 7. Criação de Threads – Exercícios<br />Solução Paralela<br />static long num_steps = 100000000;<br />double step;<br />int main ()<br />{<br />inti,j;<br /> double pi, full_sum = 0.0;<br /> double sum[MAX_THREADS];<br /> step = 1.0/(double) num_steps;<br />
  8. 8. Criação de Threads – Exercícios<br /> omp_set_num_threads(MAX_THREADS);<br /> full_sum=0.0; <br />#pragma omp parallel<br /> {<br /> int i;<br /> int id = omp_get_thread_num();<br /> int numthreads = omp_get_num_threads();<br /> double x;<br /> sum[id] = 0.0;<br /> if (id == 0) printf(" num_threads = %d",numthreads);<br /> for (i=id;i< num_steps; i+=numthreads){<br /> x = (i+0.5)*step;<br /> sum[id] = sum[id] + 4.0/(1.0+x*x);<br /> }<br />}<br />Região Paralela<br />
  9. 9. Criação de Threads – Exercícios<br />Agrupamento dos resultados.<br />(Redução)<br />for(full_sum = 0.0, i=0;i<MAX_THREADS;i++)<br />full_sum += sum[i];<br /> pi = step * full_sum;<br />}<br />
  10. 10. Diretiva DO/for<br />A 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.<br />Com isso, o programador não precisa de preocupar com a divisão da carga de trabalho entre os threads<br />Exemplo:<br />#pragma omp parallel<br />{<br /> #pragma omp for<br /> for (I=0;I<N;I++) {<br /> Faca_algo(I);<br /> }<br />}<br />Define uma região paralela<br />O comando for será dividido igualmente entre os threads. Detalhe:a variável I é privativa.<br />
  11. 11. Diretiva DO/for<br />Alternativamente, pode-se utilizar a seguinte sintaxe:<br />Exemplo:<br />#pragma omp parallel for <br /> for (I=0;I<N;I++) {<br /> Faca_algo(I);<br /> }<br />Cuidado com o uso de outras variáveis dento de um “laço paralelo”!!<br />As variáveis do laço são privativas de cada thread.<br /><ul><li>Exemplo:</li></ul>int i, j, A[MAX];<br />j = 5;<br />for (i=0;i< MAX; i++) {<br /> j = j+ 2*i;<br /> A[i] = big(j);<br />}<br />
  12. 12. Diretiva DO/for - Redução<br />Como resolver o caso ao lado?<br />double ave=0.0, A[MAX]; int i;<br />for (i=0;i< MAX; i++) {<br />ave + = A[i];<br />}<br />ave = ave/MAX;<br />Resposta: usando uma redução !<br />double ave=0.0, A[MAX]; int i;<br />#pragma omp parallel for reduction (+:ave)<br />for (i=0;i< MAX; i++) {<br /> ave + = A[i];<br />}<br />ave = ave/MAX;<br />
  13. 13. Diretiva DO/for – Redução – mais detalhes<br />Dentro de uma região paralela:<br /><ul><li> É 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.
  14. 14. 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.</li></ul>Como fica o programa para calcular o  com a diretiva for e a redução?<br />
  15. 15. Diretiva DO/for – Redução – mais detalhes<br />Solução Paralela<br />static long num_steps = 100000000;<br />double step;<br />int main ()<br />{<br />inti,j;<br /> double x, pi, sum = 0.0;<br /> double sum[MAX_THREADS];<br /> step = 1.0/(double) num_steps;<br />
  16. 16. Diretiva DO/for – Redução – mais detalhes<br />omp_set_num_threads(MAX_THREADS); sum=0.0; <br />#pragma omp parallel for reduction (+:sum)<br /> for (i=1;i< num_steps; i++){<br /> x = (i-0.5)*step;<br /> sum= sum + 4.0/(1.0+x*x);<br /> }<br /> pi = step * sum;<br /> }<br />Região Paralela com redução<br />
  17. 17. Atributos de variáveis<br /><ul><li>As variáveis no OpenMP podem ser compartilhadas ou não entre os threads. Esse controle é feito através de alguns atributos. São eles:
  18. 18. private: Declara que as variáveis listadas serão de uso específico de cada “thread”. Essas variáveis não são iniciadas.
  19. 19. 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.</li></li></ul><li>Atributos de variáveis<br /><ul><li>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.
  20. 20. 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.
  21. 21. default: Permite que o programador defina o atributo “default” para as variáveis em uma região paralela (PRIVATE, SHARED ou NONE).</li></li></ul><li>Atributos de variáveis exemplos<br />void useless() {<br />int tmp = 0;<br />#pragma omp for firstprivate(tmp)<br />for (int j = 0; j < 1000; ++j)<br /> tmp += j;<br />printf(“%d ”, tmp);<br />}<br />Cada thread possui sua própria cópia da variável tmp com o valor inicial zero.<br />
  22. 22. Atributos de variáveis exemplos<br />void useless() {<br />int tmp = 0;<br />#pragma omp for firstprivate(tmp) lastprivate(tmp)<br />for (int j = 0; j < 1000; ++j)<br /> tmp += j;<br />printf(“%d ”, tmp);<br />}<br />A variável tmp termina com o valor do calculado pelo último thread a terminar.<br />
  23. 23. Escalonamento<br />O escalonamento (schedule) descreve como as iterações do laço serão divididas por entre os threads. Os escalonamentos possíveis são:<br /><ul><li>static: o laçoserá dividido em pedaços de tamanho “chunk” e distribuído estaticamente para cada thread (por ordem de thread); Se o parâmetro “chunk” não for definido, o compilador irá dividir o laço de maneira contínua e em partes iguais (quando possível), para cada thread.
  24. 24. dynamic: O laço será dividido em pedaços de tamanho “chunk” e distribuído dinamicamente para cada thread (pela thread disponível); Quando uma thread finaliza um “chunk”, outra é atribuída para processamento. O tamanho pa drão de “chunk”, neste caso, é 1.
  25. 25. guided: – O número de iterações para cada thread variará, começando com um valor grande e sendo reduzido exponencialmente, a medida que é enviado o tamanho do laço para cada “thread”. Neste caso, o valor de “chunk” é o tamanho mínimo permitido para o número de iterações, se não for especificado, será de 1.</li></li></ul><li>Escalonamento - Exemplo<br />#include <omp.h><br />#define CHUNK 100<br />#define N 1000<br />int main ()<br />{<br />int i, n = N, chunk = CHUNK;<br />float a[N], b[N], c[N];<br />for (i=0; i < N; i++)<br /> a[i] = b[i] = i * 1.0;<br />#pragmaomp parallel shared(a,b,c,n,chunk) private(i) {<br />#pragmaomp for schedule(dynamic,chunk) nowait<br />for (i=0; i < n; i++)<br /> c[i] = a[i] + b[i];<br /> }<br />}<br />As variáveis a,b,c,n e chunk são compartilhadas. A variável i é privativa.<br />Será adotado o escalonamento dinâmico.<br />Detalhe: o atributo nowait evita a barreira no final.<br />
  26. 26. Seções<br />A 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. <br />Algumas observações:<br />A diretiva sections define a seção do código sequêncial aonde será definida as seções independentes, através da diretiva section;<br />Cada sections é executada por uma thread do grupo;<br />Existe um ponto de sincronização implícita no final da diretiva sections, a menos que se especifique o atributo nowait;<br />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.<br />
  27. 27. Seções- Exemplo<br />#include <omp.h><br />#define N 1000<br />int main () {<br />int i, n=N;<br />float a[N], b[N], c[N];<br />for (i=0; i < N; i++) a[i] = b[i] = i * 1.0;<br />#pragma omp parallel shared(a,b,c,n) private(i) {<br />#pragma omp sections nowait {<br />#pragma omp section<br />for (i=0; i < n/2; i++)<br /> c[i] = a[i] + b[i];<br />#pragma omp section<br />for (i=n/2; i < n; i++)<br /> c[i] = a[i] + b[i];<br />} /* fim seções*/<br />} /* fim parallel */<br />}<br />Definição de uma área de seções.<br />Primeira seção<br />Segunda seção<br />
  28. 28. Unicidade<br />A diretiva single determina que o código identificado seja executado por somente uma thread do grupo.<br />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.<br />A diretiva ordered determina que as iterações do laço na região paralela, sejam executados na ordem sequêncial. <br />
  29. 29. Unicidade- Exemplos<br />#pragmaomp parallel<br />{<br />do_many_things();<br />#pragmaomp single<br />{ <br />exchange_boundaries(); <br />}<br />do_many_other_things();<br />}<br />Apenas um thread vai executar esse trecho de código.<br />Detalhe: nesse caso todos os threads aguardarão até que o bloco single seja executado.<br />
  30. 30. Unicidade- Exemplos<br />#pragma omp parallel private (tmp)<br />#pragma omp for ordered reduction(+:res)<br />for (I=0;I<N;I++){<br />tmp = NEAT_STUFF(I);<br />#pragma ordered<br />res += consum(tmp);<br />}<br />Os threads executarão os trechos de código um de cada vez, de forma sequencial.<br />

×