CUDA 이용하여 행렬 곱셈을 해보자 2018, Jul 03 CUDA 를 이용해 행렬의 곱셈을 해보자. kernel.cu #include "cuda_runtime.h" #include "device_launch_parameters.h" #include <Stdio.h> // 행렬 곱셈 커널 함수를 콜할 호스트 함수 cudaError_t multiWithCuda(float* c, float* a, float* b, unsigned int size); __global__ void multiKernel(float* c, float* a, float* b, unsigned int size) { int i = threadIdx.x; // block 갯수를 지정해 idx를 활용할 것이다. // (1차원 배열을 사용할 것이지만) // 행렬은 2차원이기 때문이다. int j = blockIdx.x; // 행렬의 곱셈을 구현한다. for(int x=0; x<size; x++) c[size*j + i] += a[size*j + x] * b[size*x + i]; } int main() { const int arraySize = 5; // 행렬 a,b,c 를 만든다. float a[arraySize*arraySize] = {0}; float b[arraySize*arraySize] = {0}; float c[arraySize*arraySize] = {0}; // 알맞은 값으로 초기화 한다. for(int i=0; i<arraySize*arraySize; i++) { a[i] = static_cast<float>(i); b[i] = static_cast<float>(i); } // 작업할 함수를 콜한다. cudaError_t cudaStatus = multiWithCuda(c, a, b, arraySize); if(cudaStatus != cudaSuccess) { fprintf(stderr, "multiWithCuda failed!"); return -1; } // 결과를 출력한다. for(int i=0; i<arraySize*arraySize; i++) { if(i % arraySize == 0) printf("\n"); printf("%8.1f ",c[i]); } printf("\n"); // 모든 작업이 완료되었으므로 // device 를 reset 한다. cudaStatus = cudaDeviceReset(); if(cudaStatus != cudaSuccess) { fprintf(stderr,"cudaDeviceReset, failed!"); return 1; } return 0; } // 커널함수 호출하는 헬퍼 함수 multiWithCuda를 정의하자 cudaError_t multiWithCuda(float* c, float* a, float* b, unsigned int size) { // gpu에 할당한 메모리 주소값을 저장할 변수를 선언한다. float* dev_a = 0; float* dev_b = 0; float* dev_c = 0; cudaError_t cudaStatus; cudaStatus = cudaSetDevice(0); if(cudaStatus != cudaSuccess) { fprintf(stderr, "CudaSetDevice failed! Do you have a CUDA-capable GPU installed?"); goto Error; } // GPU에 메모리를 할당한다. // 행렬 크기만큼 할당한다. cudaStatus = cudaMalloc((void**)&dev_c, size*size*sizeof(float)); if(cudaStatus != cudaSuccess) { fprintf(stderr,"cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void**)&dev_a, size*size*sizeof(float)); if(cudaStatus != cudaSuccess) { fprintf(stderr,"cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void**)&dev_b, size*size*sizeof(float)); if(cudaStatus != cudaSuccess) { fprintf(stderr,"cudaMalloc failed!"); goto Error; } // 호스트 메모리에 있는 값을 디바이스 메모리에 복사한다. cudaStatus = cudaMemcpy(dev_a, a, size*size*sizeof(float), cudaMemcpyHostToDevice); if(cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } cudaStatus = cudaMemcpy(dev_b, b, size*size*sizeof(float), cudaMemcpyHostToDevice); if(cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } // 커널 함수를 실행한다. multiKernel<<<size, size>>>(dev_c, dev_a, dev_b, size); // 커널 함수 실행후 에러가 있는지 확인 cudataStatus = cudaGetLastError(); if(cudaStatus != cudaSuccess) { fprintf(stderr, "multiKernel launch failed : %s\n", cudaGetErrorString(cudaStatus)); goto Error; } // 커널이 모두 종료되었는지 확인 cudaStatus = cudaDeviceSynchronize(); if(cudaStatus!= cudaSuccess) { fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus); goto Error; } // 결과를 호스트 메모리에 복사 cudaStatus = cudaMemcpy(c, dev_c, size*size*sizeof(float), cudaMemcpyDeviceToHost); if(cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } Error: // gpu에 할당한 메모리를 반환 cudaFree(dev_c); cudaFree(dev_a); cudaFree(dev_b); return cudaStatus; } 결과는 다음과 같다 150 160 170 180 190 400 435 470 505 540 650 710 770 830 890 900 985 1070 1155 1240 1150 1260 1370 1480 1590 Please enable JavaScript to view the comments powered by Disqus.