Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare uma empresa Scribd logo
Multiplicação de Matrizes em CUDADivino César SoaresPontifícia Universidade Católica de Goiás (CMP/PUC-GO)
O Problema Duas matrizes de entrada: A e B. Que são quadradas e possuem os mesmos valores para suas dimensões: LARGURA x LARGURA.
 Gerar uma matriz resultado C com as mesmas dimensões das matrizes A e B.
 Cada elemento (i, j) da matriz C é o produto (interno) da linha i de A pela coluna j de B.
 Para cada elemento (i, j) de C:for (k=1; k<=LARGURA; k++)	C[i][j] += (A[i][k] * B[k][j]);
Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4	i  = 1	j  = 1	k = 14123
Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4	i  = 1	j  = 1	k = 24123
Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4	i  = 1	j  = 1	k = 34123
Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4	i  = 1	j  = 1	k = 44123
Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4	i  = 1	j  = 2	k = 14123
Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4	i  = 1	j  = 2	k = 24123
Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4	i  = 1	j  = 2	k = 34123
Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4	i  = 1	j  = 2	k = 44123
Estrutura da SoluçãoAlocar memória na GPU.Copia dados de entrada. Da CPU para a GPU.Configura execução. Número de threads e blocos.Copia resultados. cudaMalloc((void **)&A_d, size_A);cudaMalloc((void**)&B_d, size_B);cudaMalloc((void**)&C_d, size_C);cudaMemcpy(A_d, A, size_A, cudaMemcpyHostToDevice);cudaMemcpy(B_d, B, size_B , cudaMemcpyHostToDevice);cudaMemcpy(C_d, C, size_C , cudaMemcpyHostToDevice);dim3 gride(X, Y)dim3 bloco(Z, W, K)meu_kernel<<<gride, bloco>>>(A, B, C);cudaMemcpy(C, C_d, size_C , cudaMemcpyDeviceToHost);
Primeira Abordagem
Kernel 1dim3 gride(1, 1)dim3 bloco(4, 4, 1)dim3 gride(2, 1)dim3 bloco(4, 4, 1)dim3 gride(1, 1)dim3 bloco(30, 30, 1)GrideGrideGride<< Launcherror >>>Bloco com 600 threadsBloco 0Bloco 0Bloco 1
Kernel 1dim3 gride(1, 1)dim3 bloco(LARGURA, LARGURA, 1)GrideLARGURALARGURABloco 0
Kernel 1dim3 gride(1, 1)dim3 bloco(LARGURA, LARGURA, 1)Gride__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}LARGURALARGURABloco 0Kernel 1: Multiplicação na GPU
Kernel 11Instante de tempo t=02__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 1: Multiplicação na GPU4123
Kernel 11Instante de tempo t=12__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 1: Multiplicação na GPU4123
Kernel 11Instante de tempo t=22__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 1: Multiplicação na GPU4123
Kernel 11Instante de tempo t=L2__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 1: Multiplicação na GPU4123
Vantagens/DesvantagensVantagem em relação a sequencial: cada elemento de C é calculado em paralelo. Desvantagens desta abordagem:Restrição do formato das matrizes. Elas devem ser quadradas. Restrição da quantidade de elementos em cada matriz. Menor que 512. Usa apenas a memória global da GPU. A memória global apresenta grande latência. Apenas um bloco de threads, com poucas threads. Tamanho do maior bloco 22 x 22. Os mesmos dados são buscados várias vezes da memória. Resultado: Subutilização dos recursos da GPU.
Segunda Abordagem
Kernel 2dim3 gride(2, 2)dim3 bloco(15, 15, 1)dim3 gride(1, 1)dim3 bloco(30, 30, 1)GrideGride<< Launcherror >>>Bloco com 600 threadsBloco 0, 0Bloco 0, 1Bloco 1, 0Bloco 1, 1
Kernel 2dim3 gride(2, 2)dim3 bloco(15, 15, 1)GrideBloco 0, 0Bloco 0, 1225 threads por bloco.Total de 900 threads.Bloco 1, 0Bloco 1, 1
Kernel 2dim3 gride(2, 2)dim3 bloco(15, 15, 1)Gride__global__void mulGpu2(int *A[], int *B[], int *C[]) {int i = blockIdx.x * SUB_LARGURA + threadIdx.x;int j = blockIdx.y * SUB_LARGURA + threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}Bloco 0, 0Bloco 0, 1Kernel 2: Multiplicação na GPUBloco 1, 0Bloco 1, 1
Kernel 212__global__void mulGpu2(int *A[], int *B[], int *C[]) {int i = blockIdx.x * SUB_LARGURA + threadIdx.x;int j = blockIdx.y * SUB_LARGURA + threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 2: Multiplicação na GPU4123
Kernel 212__global__void mulGpu2(int *A[], int *B[], int *C[]) {int i = blockIdx.x * SUB_LARGURA + threadIdx.x;int j = blockIdx.y * SUB_LARGURA + threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 2: Multiplicação na GPU4123
Kernel 212__global__void mulGpu2(int *A[], int *B[], int *C[]) {int i = blockIdx.x * SUB_LARGURA + threadIdx.x;int j = blockIdx.y * SUB_LARGURA + threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 2: Multiplicação na GPU4123

Mais conteúdo relacionado

Multiplicação de matrizes em cuda

  • 1. Multiplicação de Matrizes em CUDADivino César SoaresPontifícia Universidade Católica de Goiás (CMP/PUC-GO)
  • 2. O Problema Duas matrizes de entrada: A e B. Que são quadradas e possuem os mesmos valores para suas dimensões: LARGURA x LARGURA.
  • 3. Gerar uma matriz resultado C com as mesmas dimensões das matrizes A e B.
  • 4. Cada elemento (i, j) da matriz C é o produto (interno) da linha i de A pela coluna j de B.
  • 5. Para cada elemento (i, j) de C:for (k=1; k<=LARGURA; k++) C[i][j] += (A[i][k] * B[k][j]);
  • 6. Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4 i = 1 j = 1 k = 14123
  • 7. Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4 i = 1 j = 1 k = 24123
  • 8. Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4 i = 1 j = 1 k = 34123
  • 9. Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4 i = 1 j = 1 k = 44123
  • 10. Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4 i = 1 j = 2 k = 14123
  • 11. Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4 i = 1 j = 2 k = 24123
  • 12. Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4 i = 1 j = 2 k = 34123
  • 13. Implementação Sequencialvoid multiplica(int *A[], int *B[], int *C[]) {for (int i=1; i<=LARGURA; i++) {for (int j=1; j<=LARGURA; j++) {for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}}}1234 Variáveis:L = 4 i = 1 j = 2 k = 44123
  • 14. Estrutura da SoluçãoAlocar memória na GPU.Copia dados de entrada. Da CPU para a GPU.Configura execução. Número de threads e blocos.Copia resultados. cudaMalloc((void **)&A_d, size_A);cudaMalloc((void**)&B_d, size_B);cudaMalloc((void**)&C_d, size_C);cudaMemcpy(A_d, A, size_A, cudaMemcpyHostToDevice);cudaMemcpy(B_d, B, size_B , cudaMemcpyHostToDevice);cudaMemcpy(C_d, C, size_C , cudaMemcpyHostToDevice);dim3 gride(X, Y)dim3 bloco(Z, W, K)meu_kernel<<<gride, bloco>>>(A, B, C);cudaMemcpy(C, C_d, size_C , cudaMemcpyDeviceToHost);
  • 16. Kernel 1dim3 gride(1, 1)dim3 bloco(4, 4, 1)dim3 gride(2, 1)dim3 bloco(4, 4, 1)dim3 gride(1, 1)dim3 bloco(30, 30, 1)GrideGrideGride<< Launcherror >>>Bloco com 600 threadsBloco 0Bloco 0Bloco 1
  • 17. Kernel 1dim3 gride(1, 1)dim3 bloco(LARGURA, LARGURA, 1)GrideLARGURALARGURABloco 0
  • 18. Kernel 1dim3 gride(1, 1)dim3 bloco(LARGURA, LARGURA, 1)Gride__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}LARGURALARGURABloco 0Kernel 1: Multiplicação na GPU
  • 19. Kernel 11Instante de tempo t=02__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 1: Multiplicação na GPU4123
  • 20. Kernel 11Instante de tempo t=12__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 1: Multiplicação na GPU4123
  • 21. Kernel 11Instante de tempo t=22__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 1: Multiplicação na GPU4123
  • 22. Kernel 11Instante de tempo t=L2__global__voidmulGpu(int *A[], int *B[], int *C[]) {int i = threadIdx.x;int j = threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 1: Multiplicação na GPU4123
  • 23. Vantagens/DesvantagensVantagem em relação a sequencial: cada elemento de C é calculado em paralelo. Desvantagens desta abordagem:Restrição do formato das matrizes. Elas devem ser quadradas. Restrição da quantidade de elementos em cada matriz. Menor que 512. Usa apenas a memória global da GPU. A memória global apresenta grande latência. Apenas um bloco de threads, com poucas threads. Tamanho do maior bloco 22 x 22. Os mesmos dados são buscados várias vezes da memória. Resultado: Subutilização dos recursos da GPU.
  • 25. Kernel 2dim3 gride(2, 2)dim3 bloco(15, 15, 1)dim3 gride(1, 1)dim3 bloco(30, 30, 1)GrideGride<< Launcherror >>>Bloco com 600 threadsBloco 0, 0Bloco 0, 1Bloco 1, 0Bloco 1, 1
  • 26. Kernel 2dim3 gride(2, 2)dim3 bloco(15, 15, 1)GrideBloco 0, 0Bloco 0, 1225 threads por bloco.Total de 900 threads.Bloco 1, 0Bloco 1, 1
  • 27. Kernel 2dim3 gride(2, 2)dim3 bloco(15, 15, 1)Gride__global__void mulGpu2(int *A[], int *B[], int *C[]) {int i = blockIdx.x * SUB_LARGURA + threadIdx.x;int j = blockIdx.y * SUB_LARGURA + threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}Bloco 0, 0Bloco 0, 1Kernel 2: Multiplicação na GPUBloco 1, 0Bloco 1, 1
  • 28. Kernel 212__global__void mulGpu2(int *A[], int *B[], int *C[]) {int i = blockIdx.x * SUB_LARGURA + threadIdx.x;int j = blockIdx.y * SUB_LARGURA + threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 2: Multiplicação na GPU4123
  • 29. Kernel 212__global__void mulGpu2(int *A[], int *B[], int *C[]) {int i = blockIdx.x * SUB_LARGURA + threadIdx.x;int j = blockIdx.y * SUB_LARGURA + threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 2: Multiplicação na GPU4123
  • 30. Kernel 212__global__void mulGpu2(int *A[], int *B[], int *C[]) {int i = blockIdx.x * SUB_LARGURA + threadIdx.x;int j = blockIdx.y * SUB_LARGURA + threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 2: Multiplicação na GPU4123
  • 31. Kernel 21Instante de tempo t=L2__global__void mulGpu2(int *A[], int *B[], int *C[]) {int i = blockIdx.x * SUB_LARGURA + threadIdx.x;int j = blockIdx.y * SUB_LARGURA + threadIdx.y;for (int k=1; k<=LARGURA; k++) {C[i][j] += (A[i][k] * B[k][j]);}}34Kernel 2: Multiplicação na GPU4123
  • 32. Vantagens/DesvantagensVantagem em relação a sequencial: cada elemento de C é calculado em paralelo. Vantagens em relação a primeira abordagem: Matrizes de tamanho arbitrário.Quantidade maior de blocos, permite melhor utilização dos recursos da GPU.Desvantagens desta abordagem:Restrição do formato das matrizes. Elas devem ser quadradas.Usa apenas a memória global da GPU. A memória global apresenta grande latência.Os mesmos dados são buscados várias vezes da memória. Resultado: Muito tempo gasto esperando transferência de dados.