dev_AI_framework
GPU, CPU 실행 시간 차이 확인...
명징직조지훈
2024. 10. 29. 09:18
#include <cuda_runtime.h>
#include <iostream>
#include <chrono>
__global__ void multiplyByTwoGPU(int *a, int size) {
int idx = threadIdx.x + blockDim.x * blockIdx.x;
if (idx < size) {
a[idx] *= 2;
}
}
void multiplyByTwoCPU(int *a, int size) {
for (int i = 0; i < size; i++) {
a[i] *= 2;
}
}
int main() {
const int size = 1000000; // 데이터 크기 증가
int *h_a = new int[size];
for (int i = 0; i < size; i++) {
h_a[i] = i;
}
// GPU 연산 시간 측정
int *d_a;
cudaMalloc(&d_a, size * sizeof(int));
cudaMemcpy(d_a, h_a, size * sizeof(int), cudaMemcpyHostToDevice);
auto start_gpu = std::chrono::high_resolution_clock::now();
int blockSize = 256;
int numBlocks = (size + blockSize - 1) / blockSize;
multiplyByTwoGPU<<<numBlocks, blockSize>>>(d_a, size);
cudaDeviceSynchronize(); // 커널 실행이 끝날 때까지 대기
auto end_gpu = std::chrono::high_resolution_clock::now();
std::chrono::duration<float, std::milli> gpu_duration = end_gpu - start_gpu;
cudaMemcpy(h_a, d_a, size * sizeof(int), cudaMemcpyDeviceToHost);
cudaFree(d_a);
// CPU 연산 시간 측정
auto start_cpu = std::chrono::high_resolution_clock::now();
multiplyByTwoCPU(h_a, size);
auto end_cpu = std::chrono::high_resolution_clock::now();
std::chrono::duration<float, std::milli> cpu_duration = end_cpu - start_cpu;
// 결과 출력
std::cout << "GPU 실행 시간: " << gpu_duration.count() << " ms" << std::endl;
std::cout << "CPU 실행 시간: " << cpu_duration.count() << " ms" << std::endl;
delete[] h_a;
return 0;
}
CUDA 를 사용하여 GPU 연산과 일반 CPU 연산 간의 실행 시간을 측정할 수 있는 코드 예제,
각 배열 요소를 두 배로 곱하는 작업,
- multiplyByTwoGPU : GPU 에서 각 요소를 두 배로 만드는 커널 함수
- multiplyByTwoCPU : CPU 에서 배열의 각 요소를 두 배로 만드는 함수
- main() 함수
- h_a 배열을 생성, 초기화
- GPU 연산 : cudaMalloc 으로 GPU 메모리를 할당하고 데이터 복사,
처음 배열의 크기가 작을 땐 CPU 의 실행 시간이 GPU 의 실행시간보다 약 10 배 정도 빠르게 나왔음, 이는 데이터 크기가 작았고
GPU 로 데이터를 보내고 받는 데 소요되는 시간이 계산 시간보다 더 많이 걸릴 수 있다. - GPU 연산을 여러 번 반복하거나, 전송 비용을 한 번으로 줄일 수 있도록 여러 연산을 병합한다.
blockSize, numBlocks 의 조절
또는 커널 함수에서 연산이 단순하여 GPU 의 강점을 발휘하지 못하는 것일 수 있음, 복잡한 연산일수록 GPU 의 성능이 더 잘 발휘된다.
CUDA 초기화 시간
첫 번째 CUDA 호출에는 초기화 시간이 포함되어 더 많은 시간이 소요될 수 있다.
GPU 연산을 반복하여 초기화 시간이 결과에 미치는 영향을 줄일 수 있다.
대규모 행렬 곱셉 연산 코드에서의 확인
#include <cuda_runtime.h>
#include <iostream>
#include <chrono>
#define N 512 // 행렬 크기 (N x N)
// GPU에서 실행되는 커널 함수
__global__ void matrixMultiply(const float *A, const float *B, float *C, int n) {
int row = blockIdx.y * blockDim.y + threadIdx.y;
int col = blockIdx.x * blockDim.x + threadIdx.x;
if (row < n && col < n) {
float sum = 0;
for (int k = 0; k < n; k++) {
sum += A[row * n + k] * B[k * n + col];
}
C[row * n + col] = sum;
}
}
// CPU에서 실행되는 행렬 곱셈 함수 (비교용)
void matrixMultiplyCPU(const float *A, const float *B, float *C, int n) {
for (int row = 0; row < n; row++) {
for (int col = 0; col < n; col++) {
float sum = 0;
for (int k = 0; k < n; k++) {
sum += A[row * n + k] * B[k * n + col];
}
C[row * n + col] = sum;
}
}
}
int main() {
int size = N * N;
int bytes = size * sizeof(float);
// 호스트 메모리 할당
float *h_A = new float[size];
float *h_B = new float[size];
float *h_C = new float[size];
float *h_C_CPU = new float[size];
// 행렬 초기화
for (int i = 0; i < size; i++) {
h_A[i] = 1.0f;
h_B[i] = 1.0f;
}
// GPU 메모리 할당
float *d_A, *d_B, *d_C;
cudaMalloc(&d_A, bytes);
cudaMalloc(&d_B, bytes);
cudaMalloc(&d_C, bytes);
// 호스트에서 GPU로 데이터 복사
cudaMemcpy(d_A, h_A, bytes, cudaMemcpyHostToDevice);
cudaMemcpy(d_B, h_B, bytes, cudaMemcpyHostToDevice);
// 블록과 그리드 차원 설정
dim3 blockSize(16, 16); // 16x16 스레드
dim3 gridSize((N + blockSize.x - 1) / blockSize.x, (N + blockSize.y - 1) / blockSize.y);
// GPU에서 행렬 곱 연산 및 시간 측정
auto start_gpu = std::chrono::high_resolution_clock::now();
matrixMultiply<<<gridSize, blockSize>>>(d_A, d_B, d_C, N);
cudaDeviceSynchronize(); // 커널이 완료될 때까지 대기
auto end_gpu = std::chrono::high_resolution_clock::now();
std::chrono::duration<float, std::milli> gpu_duration = end_gpu - start_gpu;
// GPU에서 호스트로 결과 복사
cudaMemcpy(h_C, d_C, bytes, cudaMemcpyDeviceToHost);
// CPU에서 행렬 곱 연산 및 시간 측정
auto start_cpu = std::chrono::high_resolution_clock::now();
matrixMultiplyCPU(h_A, h_B, h_C_CPU, N);
auto end_cpu = std::chrono::high_resolution_clock::now();
std::chrono::duration<float, std::milli> cpu_duration = end_cpu - start_cpu;
// 결과 비교
bool correct = true;
for (int i = 0; i < size; i++) {
if (abs(h_C[i] - h_C_CPU[i]) > 1e-4) {
correct = false;
break;
}
}
// 결과 출력
if (correct) {
std::cout << "결과가 정확합니다." << std::endl;
} else {
std::cout << "결과가 정확하지 않습니다." << std::endl;
}
std::cout << "GPU time: " << gpu_duration.count() << " ms" << std::endl;
std::cout << "CPU time: " << cpu_duration.count() << " ms" << std::endl;
// 메모리 해제
delete[] h_A;
delete[] h_B;
delete[] h_C;
delete[] h_C_CPU;
cudaFree(d_A);
cudaFree(d_B);
cudaFree(d_C);
return 0;
}
행렬 크기 설정 : 512 X 512 행렬 곱셈 GPU 병렬 처리 효과를 확인하기 위해
커널 함수 matrixMultiply
CPU 함수
16 * 16 크기의 스레드 블록 사용,
행렬 곱 연산 시 더 빠른 속도 차이 확인 가능