본문 바로가기

Library/C/C++

CUDA 2.3 Build Environment Setup

CUDA 프로그래밍은 시작부터 험난하다. 가장 큰 이유는, NVIDIA의 GPU가 계속해서 변하고 있기 때문이다. 그래서 CUDA에 대해 체계적으로 설명한 문서가 없고, 그나마 대부분 CUDA 2.2에 대해서 설명되어 있다. 그래도, CUDA를 사용하기로 마음 먹었다면, 무엇보다 NVIDIA에서 지원하는 문서들을 모두 읽어보기 바란다. 다른 경우라면 흔히 넘어가는 릴리즈 노트도 매우 중요하다.

CUDA 프로그래밍을 하려면, 자신의 GPU가 CUDA를 지원하는지 여부를 알아보고 CUDA Toolkit과 SDK를 설치해야 한다. CUDA 2.3 SDK를 설치하면 비스타 이상에서는 ProgramData 폴더 밑에 설치되는데, 이것은 시스템 폴더라 일반적인 경우 접근하기 쉽지 않다는 문제가 있다. CUDA SDK는 그것 자체만으로 완전하게 하나의 프로그램을 빌드할 수 없고, 반드시 CUDA Toolkit의 헤더, 라이브러리가 있어야 한다. 즉, CUDA SDK는 상식과 달리 Toolkit을 바탕으로 좀 더 개발을 쉽게 할 수 있도록 도와주는 부가적인 유틸리티들의 집합인 셈인데, 아직도 CUDA 개발툴들은 좀 더 정리가 필요하다는 느낌이 든다. CUDA SDK를 사용해야 하는 경우가 많으므로, 될 수 있으면 디폴트 값 대신 Program Files와 같은, 접근이 쉬운 폴더에 설치하는 것이 좋을 것이다. 이외에도 SDK에는 도움이 될만한 샘플 코드를 많이 존재한다. SDK를 설치했다면, C / bin / Release 폴더 밑에 bandwidthtest.exe라는 프로그램을 실행시켜보자. 해당 NVIDIA GPU의 CUDA 지원 능력을 파악할 수 있다.




CUDA 빌드 환경을 맞추는 것은 결과적으로 말한다면 어렵지 않지만, 설정 과정이 약간 생소해서 복잡하게 느껴질 것이다. 즉, CUDA 코드를 작성했다면 이 코드는 Toolkit의 nvcc라는 NVIDIA에서 제공하는 C 컴파일러에 의해 컴파일되고, 이 결과가 Visual C++ 컴파일러인 cl.exe에게 처리가 넘어가서 오브젝트 코드를 생성하게 된다. 보통 CUDA 코드들은 .cu 확장자를 가지는데, 이런 코드들은 Visual C++ 컴파일러인 cl.exe보다 nvcc.exe가 먼저 처리하도록 하는게 CUDA 빌드 환경을 설정하는데 핵심 요소이다.

Visual Studio IDE는 특별한 처리를 하지 않았다면 .cu 파일을 어떻게 처리해야 할지 알 수 없기 때문에, 다음 두 가지 방법 중 하나를 선택하여 컴파일되도록 해야 한다.

1. 솔루션 탐색기에서 해당 .cu 파일의 속성을 열어 커스텀 빌드를 설정한다. CUDA SDK에 포함된 샘플 프로그램을 열어보면, .cu 파일이 어떻게 설정되는지 알 수 있을 것이다. 보통 다음처럼 설정된다.

"$(CUDA_BIN_PATH)\nvcc.exe" -ccbin "$(VCInstallDir)bin" -c -D_DEBUG -DWIN32 -D_CONSOLE -D_MBCS -Xcompiler /EHsc,/W3,/nologo,/Wp64,/Od,/Zi,/MTd -I"$(CUDA_INC_PATH)" -I./ -o $(ConfigurationName)\example1.obj example1.cu




CUDA_BIN_PATH는 nvcc가 설치되어 있는 폴더의 경로이고, VCInstallDir은 Visual C++ 컴파일러인 cl.exe가 위치한 폴더이다. -I 옵션 뒤에는 포함될 헤더 파일들의 경로를 적어주는데, CUDA_INC_PATH는 CUDA Toolkit의 헤더 파일들이 위치한 폴더이다. 보통, 이것 외에도 CUDA SDK의 헤더 파일들을 지정해야 하는데, NVIDIA Corporation / NVIDIA GPU Computing SDK / C / common / inc이다. 위의 예에서는 이 부분이 빠져있는데, 필요하면 추가하면 된다. 대부분의 옵션들은 cl.exe에게 넘겨주는 옵션들이다. 위의 컴파일 옵션들은, 이미 Visual C++ 컴파일러에 익숙한 개발자라면 친숙할 것이다. 원한다면 마음대로 설정해도 좋다. CUDA_INC_PATH, CUDA_LIB_PATH, CUDA_BIN_PATH와 같은 환경 변수들은 CUDA Toolkit을 설치하면 자동으로 추가된다. 만약 커맨드 프롬프트에서 환경 변수를 사용하고자 한다면 %Variables%을 사용하고, Visual Studio에서 사용하고자 한다면 $(Variables) 형식으로 사용하면 된다.

2. 위의 방법은 해당 .cu 파일마다 모두 설정해야 하기 때문에 불편하다. 이것보다 좀 더 근본적인 해결 방법은, Visual Studio IDE에게 .cu 파일을 어떻게 처리해야 할지 알려주는 것이다. CUDA SDK를 살펴보면 common 폴더 밑에 Cuda.Rules 파일이 있는데, 이것을 등록해주면 일일이 파일마다 커스텀 빌드를 설정하지 않아도 .cu 파일에 대해서 위의 과정을 자동으로 처리해준다. (커스텀 빌드 규칙이라고 한다)




F10 메뉴의 Project 항목이 아니라, 솔루션 탐색기를 오른쪽 클릭하면 나타나는 컨텍스트 메뉴에서 Custom Build Rules를 선택하고, Find Existing - Cuda.Rules를 선택한다. 그리고 옆의 체크 항목을 선택하면, 이후 Visual Studio는 해당 프로젝트에서 .cu 파일을 이 규칙에 따라 처리하게 된다. 앞으로 .cu 파일을 프로젝트에 추가하면 자동으로 커스텀 빌드가 설정된다.




그리고, 필요한 라이브러리를 링크해야 하는데, 많은 사이트에서 이야기하는 cutil32d.lib는 사실 그렇게까지 필요하지는 않다. 핵심적인 라이브러리는 cuda.lib, cudart.lib이며, 이 두 라이브러리는 반드시 포함해야 한다. CUDA Toolkit과 SDK를 다운 받을 때 32비트 환경인지 64비트 환경인지에 따라 다르게 다운 받았을텐데, 자신의 환경에 맞춰 라이브러리 폴더와 라이브러리를 설정하면 된다. 즉, 64비트 버전이라면 lib64 폴더를 선택하고, SDK는 lib 폴더에 cutil64d.lib, cutil64.lib가 있을 것이다. (관례대로, d는 디버깅 심벌을 포함하고 있는지 여부를 나타낸다)

여기까지 설정을 했다면, 실제로 .cu 파일을 컴파일 할 수 있게 된다. 그러나, .cu 파일들은 Visual Studio IDE 환경에서 syntax highlighting이 되지 않기 때문에 보기에 조금 불편하다. CUDA의 문법은 C와 거의 동일하기 때문에, C/C++ 스타일의 syntax highlighting이 지원되면 좋을 것이다. Tools - Options - Text Editor 항목에서 .cu 파일을 Visual C++ 형식으로 등록해주면, Visual Studio IDE는 .cu 파일에 대해 C/C++과 동일한 syntax highlighting, 들여쓰기를 적용해준다.




컴파일 모형은, 전통적인 C 방식을 따라가면 된다. .cu 파일에서 제공할 함수들은 .h를 통해 외부로 노출하고, .cu 파일은 구현을 제공하며, 이 함수들을 사용할 외부 코드들은 헤더 파일을 통해 접근하면 된다. (extern "C"를 사용하여) 함수를 호출할 때는 호스트에서도 호출 가능한 것인지, 디바이스(GPU)에서만 호출 가능한 것인지(.cu 파일에서만) 잘 구별해야 한다. 디바이스에서 호출되는 함수는 속성을 명확하게 지정해야 CUDA built-in 변수들이 제대로 인식된다. 함수 호출이나 내장 형식에 관한 자세한 자료는 문서를 참조하라.  함수 호출이나 속성에 관한 부분은 자세히 읽어 봐야 할 것이다.

마지막으로, 자신의 프로젝트 역시 CUDA 라이브러리와 맞추어야 한다. 64비트 버전을 받았다면 자신의 프로젝트 역시 x64나 Win64 플랫폼을 설정해야 링크 에러가 발생하지 않는다. 또, 2.2 버전의 cudaMalloc()와 같은 함수는 2.3 버전에서 cuMemAlloc()로 대체되었으니, 모든 설정을 정확하게 했음에도 컴파일 에러가 발생했다고 끔찍한 CUDA 빌드 설정을 다시 하지 않길 바란다. 다시 말하지만, CUDA는 MSDN에 비해 지원이 아직 미약한 편이기 때문에 NVIDIA에서 릴리즈 하는 문서는 모두 꼼꼼하게 읽어볼 필요가 있다.


Enjoy horrible CUDA!