[App 개발] CUDA, Supercomputing for the Masses (8)
본문
지난 회에서는 차세대 CUDA 하드웨어를 살펴보았습니다. 이번에는 하드웨어에서 소프트웨어로 주제를 약간 바꾸어서 CUDA 에서 라이브러리를 사용하는 것을 살펴보겠습니다.
최적화된 라이브러리는 응용프로그램의 성능을 향상시키는 쉬운 방법입니다. 큰 규모의 옛날 코드를 포팅할 때 라이브러리는 새 플랫폼에 최적화시키는 유일한 방법입니다. 왜냐하면 코드 변경에는 코드 점검 노력이 수반되어야 하기 때문입니다. 라이브러리는 코드 개발을 용이하게 할 뿐만 아니라 응용프로그램 성능을 향상시킵니다. 하지만 라이브러리를 무작정 사용할 수는 없습니다. 특별히 GPU 계열 라이브러리를 사용할 때에는 데이터 구조와 라이브러리 사용에 주의해야 합니다. 그렇지 않으면 성능 저하를 낳게 될 것입니다.
BLAS (Basic Linear Algebra Subprograms) 는 벡터나 매트릭스 연산같은 기초 선형 대수 연산을 지원하는 유용한 프로그래밍 인터페이스입니다. NVIDIA 는 GPU 기반 라이브러리인 CUBLAS 를 지원합니다. 그 외에도 NVIDIA 는 GPU 기반 고속 푸리에 변환을 지원하는 CUFFT 라이브러리도 제공합니다. 푸리에 변환은 과학 및 신호처리 분야에서 보편적으로 사용되는 방법입니다. 이것은 범용 프로세서에서 최적화된 FFT 패키지인 FFTW 이후에 설계되었습니다.
BLAS 는 세 개의 레벨로 이루어져 있습니다.
* Level 1 알고리듬에는 예를 들면 벡터의 inner product 혹은 상수 곱셈을 이용한 벡터 스케일링 등이 있습니다.
* Level 2 알고리듬에는 매트릭스-벡터 곱셈 혹은 매트릭스 해법.
* Level 3 알고리듬에는 매트릭스-매트릭스 곱셈이 들어있습니다.
만약 벡터 N 혹은 매트릭스 N * N 이 있을 때 Level 1, 2, 3 명령에 필요한 단밀도 실수 연산은 O(N), O(N2), O(N3) 입니다. (O 는 입력 인수의 차원이 시간이나 메모리 등 컴퓨팅 리소스를 얼마나 소비하는지를 표현하는 쉬운 방법입니다.)
응용프로그램이 CUBLAS 라이브러리를 이용한다면 매트릭스와 벡터를 GPU 메모리 공간에 생선한 후 데이터를 채워 넣고 CUBLAS 함수들을 호출한 후 결과물을 GPU 메모리에서 호스트 공간으로 되돌립니다. 이 작업을 위해서 CUBLAS 는 GPU 공간에 객체를 생성하고 없애는 기능과 데이터를 객체에 기록하거나 되갖고 올 수 있는 helper 함수를 제공합니다. C 와 C++ 응용프로그램은 CUBLAS 가 생성한 객체를 억세스하기 위한 매크로 혹은 인라인 함수를 이용해야 합니다.
데이터 전송은 CUBLAS (일반 BLAS 도 마찬가지) 이용에 있어서 중요한 요소입니다. 레벨당 BLAS 데이터 전송은 O(N), O(N2), O(N2) 이며, 전송된 데이터 당 실수 연산의 갯수는 O(1), O(1), O(N) 입니다. 이는 데이터를 GPU 내에 상주시키는 것이 얼마나 중요한지를 말해줍니다.
GPU 의 쓰레드 프로세서는 GPU 로컬 데이터에서만 동작하며, BLAS 연산에서 호스트 컴퓨터 메모리에 상주한 벡터나 매트릭스는 데이터 전송이 필요합니다. 그래픽 프로세서에서 데이터 전송 작업은 실수 연산보다 훨씬 오래 걸리며 (GPU 는 실수 연산을 데이터 전송보다 훨씬 빠르게 수행합니다) 가능하면 이것을 피하는 것이 병목 현상을 줄이는 길입니다.
이 현상을 설명하기 위해서, 벡터를 호스트에서 GPU 로 옮겨서, 상수와 곱셈을 한 후 다시 호스트로 결과를 돌려놓는 데 필요한 과정을 생각해 봅시다. 이 프로그램은 4N 바이트 데이터 (N 은 벡터 내 float의 갯수) 를 GPU 로 전송하며 N 번의 곱셈을 수행합니다 (상수와 벡터 곱셈). 이 프로그램의 가장 최적의 성능은 밴드폭에서 8 을 나눈 값 만큼 전송하는 것입니다 (32 비트 float 를 GPU 로 전송할 때의 바이트 수). 재수가 좋은 프로그램은 호스트와 GPU 전송에 초당 4GB 대역폭을 가질 경우 1 GFLOP (초당 십억 번의 실수 연산) 실수 연산 성능을 얻을 수 있습니다. 이 결과는 싸구려 NVIDIA GPU 의 성능에도 한참 못 미치는 실수 연산 성능입니다. 여러 명령을 순차적으로 동시에 수행하면 PCIe 버스의 양방향 통신 성능을 끌어내어 이 성능을 향상시킬 수도 있습니다.
결론적으로, Level 1, 2 의 BLAS 프로그램은 되도록 많은 데이터를 GPU 에 상주시킬 때 좋은 성능을 얻을 수 있습니다. 이것이 여의치 않다면 되도록 많은 라이브러리 호출을 한꺼번에 수행합니다.
Level 3 BLAS 프로그램은 매우 효율적인 성능을 얻을 수 있습니다. 표 1 은 다양한 아키텍쳐에서 SGEMM 벤치마크 를 수행한 결과를 정리하였습니다. 이 벤치마크 테스트는 고속 매트릭스 멱급수 연산을 사용하는 재무 관련 프로그램의 연산과 동일한 과정을 수행하며, 실제 상황의 성능을 반영하고 있기 때문에 중요합니다. 모든 결과는 GFLOP 단위입니다. CUBLAS 에서 "Thunking" 이라는 명칭은 메모리 할당, GPU 로 복사, 계산 수행, 결과 복사, 메모리 정리를 자동으로 수행하는 인터페이스입니다. 이것만으로도 BLAS 를 대체할 수 있습니다만, 데이터 전송에 따른 속도 저하가 확실히 보입니다. "GPU only" 로 표기된 줄은 데이터 할당/해제 와 전송을 프로그램 제작자가 맡은 것입니다. 이 경우 메모리는 한 번만 할당되고, 데이터가 전송된 후 다수의 SGEMM 호출이 이루어지며, 그 이후 결과를 돌려받습니다. 이 경우 데이터 전송에 드는 시간은 매우 적습니다. 표의 결과에는 다수의 N * N 매트릭스 연산을 테슬라 8, 10 시리즈와 쿼드 코어 CPU 에서 수행하였습니다. 매트릭스 크기가 작을 때에는 CPU 가 thunking 인터페이스에 비해 빠르지만, 프로그램 개발자가 데이터 관리를 직접 챙길 경우 GPU 속도가 현저하게 빠른 것을 볼 수 있습니다.
< 표 1 >
NVIDIA 기본 제공 라이브러리보다 더 나은 성능을 획득할 수도 있습니다. 예를 들어, LU, QR and Cholesky Factorizations using Vector Capabilities of GPUs 논문에서 Vasily Volkov 와 James Demmel 은 제작한 매트릭스-매트릭스 곱셈 루틴을 이용해서 G80 시리즈 GPU 의 최대 성능을 획득하였다고 보고하고 있습니다. 이 논문에는 GPU 메모리 시스템의 자세한 벤치마크 검사를 담고 있는데, 여기서 그들의 특별한 개선책을 사용하고 있습니다. 그 방법을 사용하여 대략 CUBLAS 1.1 보다 60% 정도 향상된 속도를 나타내었다고 보고하고 있습니다. 이러한 개선책은 이미 CUBLAS 2.0 에 반연되었으며, 위 표에 나타난 벤치마크 실험에 사용되었습니다. 이렇게 NVIDIA 는 하드웨어와 라이브러리 코드의 성능 향상을 위해 꾸준히 노력하고 있습니다.
GPU 를 이용하여 BLAS 의 놀라운 성능을 얻을 수 있습니다. 예를 들어, 포트란 프로그래머들은 최적화 상능 향상을 위한 GPU 디바이스 디스크립터를 추가하는 미들웨어 호출 레이어를 구현한 FLAGON 이라는 오픈 소스 라이브러리를 확인해 보십시오. 슈퍼컴퓨팅 2007 포스터에서 Nail A. Gumerov 와 Ramani Duraiswami 그리고 William D. Dorland 는 CUFFT 를 이용하여 인텔 QX6700 프로세서에 비해 25 배 빠른 속도를 획득하였다고 하였으며 radial basis function 을 분산 데이터에 학습시키는 반복 계산에서 직렬 코드에 비해 매우 뛰어난 성능을 얻을 수 있었다고 하였습니다.
물론 GPU 를 사용해서 전혀 속도 향상을 보지 못했다는 (혹은 속도 저하가 있었다는) 논문도 다수 있습니다. 앞서 말했듯이, 데이터 전송 문제가 결정 사항입니다. 예를 들어 CUFFT vs. FFTW (http://www.science.uwaterloo.ca/~hmerz/CUDA_benchFFT/) 에서 그 특성을 잘 정리하고 있습니다.
요악하면, NVIDIA CUFFT 와 CUBLAS 는 선형 대수와 고속 푸리에 번환을 사용할 수 있는 간편하고 잘 정돈된 방법을 제시하고 있습니다. 이런 라이브러리들은 대규모 프로젝트에서 그래픽 프로세서 활용을 용이하게 해 줍니다. 데이터 전송 최소화에 주의한다면 매우 뛰어난 성능을 획득할 수 있습니다. 라이브러리 호출을 한꺼번에 함으로써 속도 향상을 얻을 수 있습니다. CUDA 장치의 특성에 주의하면 놀라운 성능 향상을 얻을 수 있습니다. NVIDIA 는 하드웨어와 라이브러리의 성능 향상에 주력하고 있으므로, 지속적인 성능 향상을 기대할 수 있습니다.
최신글이 없습니다.
최신글이 없습니다.
댓글목록 2
쭈니어빠님의 댓글
번역 해주신거 너무 감사합니다.
이 연재물은 언젠가 꼭 읽으려고 했던거였습니다.
수고해 주신 보답으로 지금 진행중인 프로젝트에 CUDA를 성공적으로 적용시켜 보이겠습니다. ^^
hongjuny님의 댓글
관심 가져주셔서 대단히 감사합니다.
향후 번역물은 제 개인 블로그에 올릴 생각입니다. 케이머그에 애정이 식었거나 뭐 별다른 불만이 있어서 그런 것은 아니고요, 앞으로 번역물 외에도 샘플 소스코드 분석이나, 직접 샘플 코드 작성을 올릴 생각인데, 케이머그의 분위기 상 이런 깊쑤키~ 들어간 기술적인 내용은 별로 환영받지 못하는 것 같아서요.
일단은 애플에서 발행한 Grand Central Dispatch 개요 를 번역해 올렸고, 조금 더 심사숙고 후 앞으로의 방향을 결정할 생각입니다.