이번 글에서는 CMake를 사용하여 CUDA 기반의 GPU 가속 응용 프로그램을 빌드하고 설정하는 방법을 알아보겠습니다. GPU 프로그래밍은 고성능 계산, 머신 러닝, 그래픽스 등 다양한 분야에서 중요한 역할을 합니다. CMake를 활용하여 CUDA 코드를 효율적으로 관리하고 빌드 시스템에 통합하는 방법을 살펴보겠습니다.
CUDA와 CMake의 통합
CUDA는 NVIDIA에서 개발한 병렬 컴퓨팅 플랫폼으로, GPU를 활용하여 계산을 가속화할 수 있습니다. CMake는 CUDA를 지원하기 위한 다양한 기능을 제공하며, 이를 통해 CUDA 코드와 C++ 코드를 함께 빌드할 수 있습니다.
CMake에서 CUDA 활성화
CMake에서 CUDA를 사용하기 위해서는 프로젝트 설정에서 LANGUAGES에 CUDA를 추가합니다.
cmake_minimum_required(VERSION 3.18)
project(MyCUDAProject LANGUAGES CXX CUDA)
- CMake 3.8 이상부터 CUDA를 언어로서 직접 지원합니다.
- CMake 3.17 이전 버전에서는 find_package(CUDA REQUIRED)를 사용해야 했습니다.
간단한 CUDA 프로젝트 구성
디렉토리 구조
my_cuda_project/
├── CMakeLists.txt
├── src/
│ ├── CMakeLists.txt
│ ├── main.cpp
│ └── kernel.cu
└── include/
└── kernel.h
최상위 CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(MyCUDAProject LANGUAGES CXX CUDA)
add_subdirectory(src)
src/CMakeLists.txt
add_executable(MyCUDAApp main.cpp kernel.cu)
# CUDA 아키텍처 설정 (필요에 따라 수정)
set_target_properties(MyCUDAApp PROPERTIES
CUDA_ARCHITECTURES 60 70 75 80)
# CUDA 표준 설정 (CUDA 11부터 지원)
set_target_properties(MyCUDAApp PROPERTIES
CUDA_STANDARD 14
CUDA_STANDARD_REQUIRED ON)
- CUDA_ARCHITECTURES: 타겟 GPU의 아키텍처를 지정합니다. 예를 들어, 60은 Pascal(6.0), 70은 Volta(7.0)를 의미합니다.
- CUDA_STANDARD: CUDA 코드에서 사용할 C++ 표준을 지정합니다.
kernel.cu 예제
#include "kernel.h"
#include <cuda_runtime.h>
__global__ void addKernel(int *c, const int *a, const int *b) {
int i = threadIdx.x;
c[i] = a[i] + b[i];
}
void addWithCUDA(int *c, const int *a, const int *b, size_t size) {
int *dev_a = nullptr;
int *dev_b = nullptr;
int *dev_c = nullptr;
cudaMalloc((void**)&dev_a, size * sizeof(int));
cudaMalloc((void**)&dev_b, size * sizeof(int));
cudaMalloc((void**)&dev_c, size * sizeof(int));
cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);
addKernel<<<1, size>>>(dev_c, dev_a, dev_b);
cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
}
kernel.h 예제
#pragma once
void addWithCUDA(int *c, const int *a, const int *b, size_t size);
main.cpp 예제
#include <iostream>
#include "kernel.h"
int main() {
const int arraySize = 5;
const int a[arraySize] = {1, 2, 3, 4, 5};
const int b[arraySize] = {10, 20, 30, 40, 50};
int c[arraySize] = {0};
addWithCUDA(c, a, b, arraySize);
std::cout << "Result: ";
for (int i = 0; i < arraySize; ++i) {
std::cout << c[i] << " ";
}
std::cout << std::endl;
return 0;
}
빌드 및 실행
mkdir build
cd build
cmake ..
make
./MyCUDAApp
- GPU 드라이버와 CUDA Toolkit이 설치되어 있어야 합니다.
- 실행 결과는 배열의 요소별 합계를 출력합니다.
CUDA 설정 옵션
CUDA 아키텍처 설정
CUDA_ARCHITECTURES를 설정하여 타겟 GPU 아키텍처를 지정합니다.
set_target_properties(MyCUDAApp PROPERTIES
CUDA_ARCHITECTURES 75)
- 컴파일 시간을 줄이기 위해 실제 사용하는 아키텍처만 지정하는 것이 좋습니다.
- 여러 아키텍처를 지원하려면 리스트로 지정합니다.
CUDA 컴파일 옵션
추가적인 컴파일 옵션을 설정할 수 있습니다.
target_compile_options(MyCUDAApp PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:
--use_fast_math
--expt-relaxed-constexpr
>)
- $<$<COMPILE_LANGUAGE:CUDA>:...>는 CUDA 소스 파일에만 옵션을 적용합니다.
- --use_fast_math: 빠른 수학 함수 사용
- --expt-relaxed-constexpr: CUDA에서 constexpr 지원 활성화
CUDA 런타임 라이브러리 설정
CUDA 런타임 라이브러리를 정적으로 또는 동적으로 링크할 수 있습니다.
set_target_properties(MyCUDAApp PROPERTIES
CUDA_RUNTIME_LIBRARY Static)
- Static: 정적 링크
- Shared: 동적 링크
CUDA와 C++ 혼합 프로젝트
CUDA 코드와 C++ 코드를 함께 사용하는 경우, 소스 파일의 컴파일 언어를 명시적으로 지정해야 할 수 있습니다.
set_source_files_properties(
kernel.cu
PROPERTIES
LANGUAGE CUDA
)
- CMake는 .cu 확장자를 자동으로 CUDA로 인식하지만, 필요 시 명시적으로 설정합니다.
CUDA 라이브러리 사용
cuBLAS, cuFFT 등 NVIDIA CUDA 라이브러리 사용
CUDA Toolkit에서 제공하는 라이브러리를 사용할 수 있습니다.
find_package(CUDAToolkit REQUIRED)
target_link_libraries(MyCUDAApp PRIVATE CUDA::cublas CUDA::cufft)
- find_package(CUDAToolkit REQUIRED): CUDA Toolkit을 찾습니다.
- CUDA::cublas, CUDA::cufft: cuBLAS와 cuFFT 라이브러리를 링크합니다.
CUDA와 모던 CMake 기능 결합
target_compile_features() 사용
CUDA 코드에서도 C++ 표준 기능을 사용할 수 있습니다.
target_compile_features(MyCUDAApp PRIVATE cxx_std_14)
- CUDA 11부터는 C++14 표준을 지원합니다.
통합 빌드 시스템 구축
CUDA 코드와 C++ 코드를 통합하여 하나의 빌드 시스템에서 관리할 수 있습니다.
add_library(MyLib STATIC mylib.cpp kernel.cu)
set_target_properties(MyLib PROPERTIES
CUDA_ARCHITECTURES 75
CUDA_SEPARABLE_COMPILATION ON
)
target_link_libraries(MyLib PUBLIC CUDA::cudart)
- CUDA_SEPARABLE_COMPILATION ON: CUDA의 분리 컴파일 기능 활성화
- 라이브러리를 다른 타겟에서 재사용할 수 있습니다.
주의사항
- CUDA 버전 호환성: 사용하는 CUDA Toolkit 버전과 GPU 드라이버의 호환성을 확인해야 합니다.
- 컴파일러 지원: CUDA는 특정 컴파일러 버전을 지원하므로, 컴파일러와의 호환성을 검토해야 합니다.
- 플랫폼 지원: CUDA는 NVIDIA GPU가 설치된 시스템에서만 사용할 수 있습니다.
참고 자료
- CMake 공식 문서: CUDA 언어 지원
- CMake 공식 문서: CUDA 아키텍처 지정
- CUDA Toolkit 공식 사이트
- CUDA 샘플 코드
- CUDA와 CMake 예제 프로젝트
- CUDA 프로그래밍 가이드
반응형
'개발 이야기 > CMake' 카테고리의 다른 글
[모던 CMake] 재사용 가능한 라이브러리를 위한 CMake 패키지 구성 (0) | 2024.12.12 |
---|---|
[모던 CMake] Qt 프로젝트 구성과 빌드 (1) | 2024.12.11 |
[모던 CMake] Python 바인딩 프로젝트 구성과 설정 (0) | 2024.12.09 |
[모던 CMake] 외부 프로젝트와의 통합 및 활용 (0) | 2024.12.08 |
[모던 CMake] 대규모 프로젝트에서의 베스트 프랙티스 (0) | 2024.12.07 |