성능 측정
프로그램의 성능을 측정하기 위해 소요 시간을 계산하는 방법
1. 소요시간 측정
- CPU 타이머 활용 (NVCC(CUDA compiler)가 Windows API를 간단하게 사용할 수 있는 환경이 아니므로 비추천)
- GPU 타이머 활용
//Measure the execution time of a program, unit : msec
#include <cutil.h> //CUDA utility tools
unsigned int timer;
cutCreateTimer(&timer); //Create a timer
cutStartTimer(timer); //Start
...
cutStopTimer(timer); //stop
double elapsed_time = cutGetTimerValue(timer);
CUDA 타이머 사용 시 호스트에서 커널 함수를 호출하면 비동기로 바로 전환되어 정확한 시간을 측정할 수 없으므로 커널 함수가 완료될 때까지 기다리기 위해서 cudaThreadSynchronize()함수를 추가하여 시간을 측정한다. 비동기 함수가 아닌 함수의 실행시간을 측정할 때에는 동기화 없이 바로 시간을 측정하면 된다.
- 이벤트 API의 활용
2. Device query
CUDA SDK 샘플 예제의 Device Query 프로젝트를 실행하여 GPU의 사양과 CUDA SDK의 버전 확인 가능.
3. Cubin File
CUDA 프로그램 컴파일 시 생성되는 .cubin 파일을 보면 레지스터의 사용량과 공유 메모리의 사용량 같은 정보를 얻을 수 있다. NVCC 컴파일러에 -cubin 옵션을 추가하면 '.cubin' 파일이 생성된다.
lmem - local memory 사용량 [byte]
smem - shared memory 사용량 [byte]
reg - 하나의 스레드에서 사용하는 레지스터 양 [개수]
액티브 블록
커널 함수에서 사용하는 레지스터와 공유 메모리의 사용량에 따라 SM(스트리밍 멀티 프로세서)이 관린하는 활성화된 블록이 많아진다. 동시에 관리하는 블록이 많다는 것은 GPU의 가동 효율이 좋다는 것을 의미한다.
cubin파일을 통해서 개별 스레드가 사용하는 레지스터의 수와 블록에서 사용하는 공유 메모리를 알 수 있다. 이 정보를 이용하여 GPU에서 동시에 관리되는 스레드와 워프, 블록의 개수를 알 수 있다.
- 레지스터 사용에 따른 활성화 블록, 워프 계산
1개의 스레드가 16개의 레지스터를 사용하고, 하나의 블록이 256개의 스레드로 구성된 프로그램에서
SM의 레지스터가 8192개 일 때 최대 8192/16 = 512개의 스레드를 구성할 수 있다.
1개의 블록은 256개의 스레드로 구성되었기 때문에 활성화 할 수 있는 블록의 수는 512/256 = 2개이다.
1개의 워프는 32개의 스레드로 구성되어 있기 때문에 활성화 워프의 수는 512/32 = 16개이다.
- 공유 메모리 사용에 따른 활성화 블록 계산
1개의 블록이 2KB의 공유 메모리를 사용하는 경우에서
SM의 공유 메모리 크기가 16KB일 때 블록은 16KB/2KB = 8개 활성화할 수 있다.
만약 위의 조건이 이어지면 사용할 수 있는 자원의 제한으로 활성화 할 수 있는 제한 조건은
Min(위의 레지스터에 의한 활성화 블록 수, 공유 메모리에 의한 활성화 블록 수) = 레지스터에 의한 활성화 블록 수 2개이다. CUDA SDK Toolkit은 이런 계산을 간단하게 지원해주는 CUDA GPU Occupancy Calculator를 제공한다.
4. CUDA GPU Occupancy Calculator
CUDA 점유 계산기는 블록의 스레드 개수, 스레드의 레지스터 사용량, 블록의 공유 메모리 사용량을 입력하면 활성화 블록의 수를 자동으로 계산해준다.
5. Visual Profiler
CUDA SDK Toolkit에 포함된 Visual profiler를 사용하면 구현한 프로그램의 성능을 측정할 수 있다. VIsual Profiler는 CUDA프로그램에서 글로벌 메모리의 액세스 성능과 스레드의 동작 상태, 모듈별 소요 시간 등의 정보를 제공하기 때문에 이를 가지고 튜닝해야 할 위치와 방법에 대한 단서를 얻을 수 있다.