Introdução ao Processamento Paralelo (4.2)

729 visualizações

Publicada em

Minicurso ofericido durante a III Semana de Inverno de Geofisica, IMECC/UNICAMP, 2012, por Jairo Panetta (ITA/ICE).

Publicada em: Educação
0 comentários
0 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Sem downloads
Visualizações
Visualizações totais
729
No SlideShare
0
A partir de incorporações
0
Número de incorporações
10
Ações
Compartilhamentos
0
Downloads
0
Comentários
0
Gostaram
0
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Introdução ao Processamento Paralelo (4.2)

  1. 1. OpenACC: um promissor standard para aceleração de códigos Pedro Pais LopesNVIDIA GPU Computing Developer Forum Curitiba, 17/07/2012
  2. 2. O que é OpenACC?• Diretivas de compilação, na forma de pragmas (C/C++) ou comentários (Fortran) de alto nível, que orientam o compilador a executar trechos de código em um acelerador• Esforço conjunto PGI + Cray + NVIDIA + CAPS, visando integrar padrão OpenMP• Vide padrão em www.openacc.org
  3. 3. Sintaxe• C: #pragma acc nome_diretiva [cláusula [,cláusula]…] bloco estruturado de código• Fortran: !$acc nome_diretiva [cláusula [,cláusula]…] bloco estruturado de código !$acc end nome_diretiva
  4. 4. Exemplo #1: Jacobi • Converge iterativamente para um valor a partir da média dos pontos vizinhos 0°C A(i+1,j) 0°C 0°CA(i-1,j) A(i,j) A(i+1,j) A(i,j-1) 100°C
  5. 5. Código Fortrando while ( err > tol .and. iter < iter_max ) err=0.0 do j=1,m do i=1,n Anew(i,j) = .25 * (A(i+1, j ) + A(i-1, j ) + & A(i , j-1) + A(i , j+1)) err = max(err, Anew(i,j) - A(i,j)) end do end do do j=1,m-2 do i=1,n-2 A(i,j) = Anew(i,j) end do end do iter = iter +1end do
  6. 6. Inserindo OpenMPdo while ( err > tol .and. iter < iter_max ) err=0.0!$omp parallel do private(i,j) reduction(max:err) do j=1,m do i=1,n Anew(i,j) = .25 * (A(i+1, j ) + A(i-1, j ) + & A(i , j-1) + A(i , j+1)) err = max(err, Anew(i,j) - A(i,j)) end do end do!$omp end parallel do!$omp parallel do private(i,j) do j=1,m-2 do i=1,n-2 A(i,j) = Anew(i,j) end do end do!$omp end parallel do iter = iter +1end do
  7. 7. Código em Fortran e OpenACC Um kernel por ninho de laçosdo while ( err > tol .and. iter < iter_max ) err=0.0!$acc kernels reduction(max:err) Trafego GPU-CPU gerado do j=1,m automaticamente pelo compilador do i=1,n Anew(i,j) = .25 * (A(i+1, j ) + A(i-1, j ) + & A(i , j-1) + A(i , j+1)) err = max(err, Anew(i,j) - A(i,j)) end do end do!$acc end kernels barreira!$acc kernels do j=1,m-2 Outro kernel do i=1,n-2 A(i,j) = Anew(i,j) end do end do!$acc end kernels iter = iter +1end do
  8. 8. Vantagens• Código CUDA gerado automaticamente• Mantém portabilidade entre o código sequencial e o código paralelo – Chave de compilação define se compilador gera código para GPU ou não• Trafego de dados entre a CPU e a GPU determinado “automaticamente” pelo compilador
  9. 9. CPU: Intel Xeon X5680 Desempenho GPU: NVIDIA Tesla M20706 Cores @ 3.33GHz (fonte: NVIDIA) Execução Tempo (s) Speedup CPU 1 OpenMP thread 69.80 -- CPU 2 OpenMP threads 44.76 1.56x CPU 4 OpenMP threads 39.59 1.76x CPU 6 OpenMP threads 39.71 1.76x OpenACC GPU 1 thread 162.16 0.43x OPA!
  10. 10. Compilador fez o melhor que pode• Mas ele NÃO pode desrespeitar o código1. Enquanto condicional do while for satisfeita…2. copia A para a placa3. Computa primeiro laço4. Copia Anew para CPU5. Copia Anew para placa6. Computa segundo laço7. Copia A para a CPU8. Volta para 1.
  11. 11. Código em Fortran e OpenACCdo while ( err > tol .and. iter < iter_max ) err=0.0!$acc kernels reduction(max:err) do j=1,m do i=1,n Anew(i,j) = .25 * (A(i+1, j ) + A(i-1, j ) + & A(i , j-1) + A(i , j+1)) err = max(err, Anew(i,j) - A(i,j)) end do end do!$acc end kernels!$acc kernels do j=1,m-2 do i=1,n-2 A(i,j) = Anew(i,j) end do end do!$acc end kernels iter = iter +1end do
  12. 12. Melhoria #1do while ( err > tol .and. iter < iter_max ) err=0.0!$acc kernels reduction(max:err) do j=1,m do i=1,n Anew(i,j) = .25 * (A(i+1, j ) + A(i-1, j ) + & A(i , j-1) + A(i , j+1)) err = max(err, Anew(i,j) - A(i,j)) end do end do Juntar os dois kernels em um elimina tráfego CPU/GPU de A e Anew entre os dois aninamentos do j=1,m-2 do i=1,n-2 A(i,j) = Anew(i,j) end do end do!$acc end kernels iter = iter +1end do
  13. 13. Podemos ir além (melhoria #2) Envie A da CPU para a GPU no início do laço e envie de volta ao final do laço!$acc data copy(A), create(Anew) Crie e mantenha Anew na GPUdo while ( err > tol .and. iter < iter_max ) err=0.0!$acc kernels reduction(max:err) do j=1,m do i=1,n Anew(i,j) = .25 * (A(i+1, j ) + A(i-1, j ) + & A(i , j-1) + A(i , j+1)) err = max(err, Anew(i,j) - A(i,j)) end do end do do j=1,m-2 do i=1,n-2 A(i,j) = Anew(i,j) end do end do!$acc end kernels iter = iter +1end do!$acc end data
  14. 14. CPU: Intel Xeon X5680 Desempenho GPU: NVIDIA Tesla M20706 Cores @ 3.33GHz (fonte: NVIDIA) Execução Tempo (s) Speedup CPU 1 OpenMP thread 69,80 -- CPU 2 OpenMP threads 44,76 1,56x CPU 4 OpenMP threads 39,59 1,76x CPU 6 OpenMP threads 39,71 1,76x 5,11x OpenACC GPU 13,65 BOM!
  15. 15. Resumo• Foram 3 linhas a mais para 5,11x de speedup – Inclusão de comentários: outros compiladores ignorarão esta linha e código segue inalterado• Uso de diretivas deve ter “precisão cirúrgica”• Corretude da computação: não somente se preocupar com “race conditions” mas também com gerenciamento de dados – Lembrar-se SEMPRE que temos cópia LOCAL e cópia REMOTA: memória não estará inicializada
  16. 16. Sumário• OpenACC é forma promissora de programar aceleradores inserindo diretivas no programa original• Como em OpenMP, é: – Incremental – Portátil• Muito mais simples e fácil que CUDA, preservando o investimento na codificação original

×