CUDA 메모리 구조(3)

제가 CUDA관련한 글을 쓰는건 David박사가 했던 대학강의와 NVIDIA에서 나온 CUDA 문서를 참고로 하고 있습니다. 그래서 문서에 나온 내용도 정리 하겠습니다.
그나저나 NVIDIA 코리아에서는 CUDA 그렇게 밀면서 문서 한글화는 안해주네요.ㅡㅡ;
그것만 해줘도 CUDA하기 수월할텐데 말이죠.

CUDA 프로세서 구조는 SIMT(single-instruction, multiple-thread) 구조입니다. 기존에 있던 병렬프로그래밍으로 따지자면 OpenMP와 같은 성격인 것입니다. OpenMP는 CPU갯수만큼의 병렬화를 지원하지만 CUDA는 GPU안의 계산 유닛갯수만큼을 지원하는 것이 차이입니다.

SIMT 유닛은  32개의 병렬 스레드의 그룹을 만드는데 이것들을 warps 라고 부릅니다.
device에서 계산을 시작하게 되면 SIMT 유닛은 warps안에 각각의 스레드를 분해해서 넣습니다. 여기서 첫번째 warp는 Thread ID 0을 가지게 되는 겁니다.

그리고 각 Multiprocessor는 아래와 같은 구조를 가지면서 실행되게 됩니다.

사용자 삽입 이미지

위의 그림에 나와있는 각 Multiprocessor들은 다음의 4가지 형태의 메모리들을 가지게 됩니다.

1. Processor당 32비트 register들의 세트 하나.
2. Multiprocessor안의 모든 processor 코어들이 공유하는 Shared memory
3. 모든 Processor 코어들에 공유되고 constant memory space의 읽기속도를 향상시켜주는, 읽기전용인 constant cache
4. 모든 Processor 코어들에 공유되고 texture memory space의 읽기속도를 향상시켜주는, 읽기전용인 texture chche. 각각의 Multiprocessor들은 texture unit을 통해서 texture cache를 액세스합니다.

위에 내용들이 중요한 내용들입니다. 앞 포스팅에 있던 Grid, Block, Thread와 위에 있는 메모리들이 어떻게 매치되는지를 지정해주어야 에러없이 프로그램이 실행됩니다.
이게 제대로 관리안되면 에러가 나게 되는 겁니다. 여기서부터는 상세한 설명이 없어서 스스로의 많은 삽질이 필요하게 되는 부분입니다^^;

그리고 SLI를 이용해서 GPU를 여러개 꼽아서 사용할수도 있다고 나와있군요. 하나도 제대로 쓰기 어렵구만..;;

여기까지 했으니까 다음부터는 직접 코드를 작성하면서 삽질모드로 들어가야겠군요.^^;
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 아리수

2009/03/19 21:10 2009/03/19 21:10
Response
No Trackback , 1 Comment
RSS :
http://arisu.mireene.com/rss/response/143

Comments List

  1. garu 2009/04/30 14:44 # M/D Reply Permalink

    유용한 정보 감사합니다 ^^

Leave a comment

CUDA 메모리 구조(2)

CUDA 연산의 개념은 아래 그림과 같은 구조로 되어 있습니다.

사용자 삽입 이미지

여기서 Thread라고 되어 있는 것들이 CUDA연산에서 가장 작은 단위인 것입니다.
이 Thread들은 Block의 하위에 있고 Block들은 다시 Grid의 하위에 있습니다.
그래서 프로그래머가 연산을 하려면

'몇번Grid의 몇번Block의 몇번Thread를 사용하여 계산하겠다'

를 지정해 주어야 합니다.

여기서 각 Thread는 자신만의 local memory를 가지게 됩니다.
각 Thread 간에 data 공유를 위한 shared memory는 따로 있습니다.
그리고 Block들의 집합인 Grid간에 data 공유를 위한 Global memory가 있습니다.
구조는 아래와 같습니다.

사용자 삽입 이미지


이 memory들을 어떻게 사용하느냐에 따라서 같은 연산을 하는 CUDA프로그램이라 하더라도 큰 성능차이를 내게 됩니다.
memory간의 data를 이동시키는 비용이 꽤 크기 때문에 적절한 알고리즘을 작성하지 않는다면 계산하는데서 단축한 시간을 data 이동시키는데서 다 까먹을 수 있게 됩니다.
각 memory들의 속도 또한 차이가 있어서 이런 여러가지 요소를 고려하기 시작하면 복잡해지기 시작하는 겁니다.
결국 CUDA 프로그래밍의 핵심은 각 memory들의 특성을 파악해서 최대한 효율적인 알고리즘을 만드는데 있습니다.

아래 그림은 Grid를 이용해 계산한다는 것이 코드로는 어떻게 표현되는지를 나타냅니다.
사용자 삽입 이미지

결국 template project에서 보았던 kernel을 실행시키는 부분이 kernel에 해당하는 Grid를 실행시킨다는 것을 알 수 있습니다.
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 아리수

2009/02/11 20:32 2009/02/11 20:32
, ,
Response
No Trackback , 9 Comments
RSS :
http://arisu.mireene.com/rss/response/137

Comments List

  1. MESL 2009/02/16 03:40 # M/D Reply Permalink

    정말 깔끔하게 잘 정리 해 두셧습니다.

    저도 CUDA에 대해 공부하고있는데...

    사실 logical한 부분만 다루고있고...

    곧있으면 output을 내야 하는 상황이라...;; 걱정이 많네요.ㅠ

    많은 도움 부탁드립니다.ㅠㅠ

    1. 아리수 2009/02/17 09:22 # M/D Permalink

      실제 코딩도 같이 해보시는게 이해하시는데 도움이 많이 되실거예요.
      저도 그리 많이 아는건 아니라서요..^^;

  2. MESL 2009/02/27 13:40 # M/D Reply Permalink

    질문 있습니다.
    제가 하고있는 플젝의 데이터가 float형이 4000*400개를 적분연산 해야하는데,
    커널수행명령어.. 즉

    testkernel <<< >>>
    이부분에서 오류가 나는군요..
    컴파일은 다 되구요.
    invalid configuration argument라는데... 뭘 고쳐야될지-ㅅ-
    조언부탁드립니다.

    1. 아리수 2009/02/27 18:01 # M/D Permalink

      소스가 없어서 무어라 답변드리기 애매하네요. 에러내용만 보면 device에서 사용할 변수를 할당하고 device 메모리에 변수를 할당하는 과정에 원인이 있는 것 같습니다.

  3. MESL 2009/03/02 21:10 # M/D Reply Permalink

    음... 소스를 보내드려볼까요??;
    혹 메일주소가 어떻게 되시는지..ㅠ

    교수님은 아웃풋을 원하시고.. 전 진행이 안되고..
    답답해 죽겟습니다..ㅠ

    1. 아리수 2009/03/02 22:13 # M/D Permalink

      리눅스용인가요? 윈도우용인가요?
      제 메일은 arisu1000@gmail.com 입니다.
      보내주신다고해서 꼭 해결되리라는 확답은 못드리지만 살펴보고 회신 드리겠습니다.

  4. stylidy 2009/03/17 22:59 # M/D Reply Permalink

    정리 해놓으신 포스트들 많은 도움이 되었습니다.
    Visual Studio 2005에서 CUDA를 이용해 새로운 프로젝트를 생성해서 작업을 하려고 합니다. 혹시 release note에 있는 template프로젝트를 이용하는 방법 말고, 새로운 프로젝트를 생성하는 방법을 알고 계시면 도움을 주시면 감사하겠습니다. Visual studio 프로젝트 환경 설정에서 애를 먹고 있어서,,;;;;
    그리고 원래 생성되어 있는 프로젝트를 CUDA환경으로 변환(?)할 수 있는 방법을 알고 계신지,,,;;;;
    코딩에서 에러가 있어서 진행이 안되면 그나마 디버깅이라도 해볼 수 있겠는데,, 프로젝트 환경설정이 안되서 애를 먹고 있으니 너무 답답하네요,,;;;;
    조언좀 해주시면 감사하겠습니다.
    아,, 제 메일 주소는 stylidy@metq.com입니다.
    아리수님 블로그 번창하시길 바랍니다.

    1. 아리수 2009/03/19 20:06 # M/D Permalink

      제가 원래 CUDA프로그래밍을 리눅스에서 많이 했었기 때문에 질문주신 윈도우에서 새로운 프로젝트 환경 설정하는 방법은 해본적이 없습니다.
      그리고 CUDA 디버깅은 Visual Studio 로는 어려운 부분이 있습니다. Visual Studio는 메인보드와 CPU상에서 일어나는 부분만 디버깅 가능하기 때문에 GPU상에서 어떻게 연산이 진행되는지에 관한 정보는 알기가 어렵습니다.

  5. stylidy 2009/03/20 16:02 # M/D Reply Permalink

    그렇군요,, 답답하네요,,,;;;;;
    이놈의 링크에러,,, 어흑
    답변해주셔서 감사합니다~

Leave a comment

CUDA 메모리 구조(1)

오랜만에 쓰네요. 여기는 CUDA관련해서 들어오시는 분들이 제일 많군요..;;
잠깐 검색해봤는데 해가 지났는데 아직 CUDA관련한 한글자료는 잘 없는 편이군요.
국내에 어느정도 보급은 된거 같은데 정보공유는 어떻게들 하시는지 모르겠습니다.
nvidia싸이트 가봐도 그다지 활성화되어 있는거 같지는 않구요.

이번 글은 CUDA 메모리 구조 관련한 정리 입니다.
2.0은 안봐서 모르겠는데 이전버전에서의 CUDA는 메모리 구조를 숙지하고 있었어야 했기 때문에 그냥 그럴거라 생각하고 메모리구조에 대한 정리부터 이어갑니다.

우리가 CUDA를 쓰려고하는 이유는 GPU를 사용하여 연산속도의 향상을 얻기 위함입니다.
GPU가 CPU연산보다 빠른 이유가 CPU보다 많은 ALU를 보유하고 있기 때문입니다.
 

사용자 삽입 이미지
위 그림에서 보시면 GPU가 CPU보다 월등히 많은 ALU를 가지고 있다는 것을 알 수 있습니다.
저 ALU를 어떻게 잘 사용하느냐가 속도향상의 관건입니다.
CPU에서는 특정 ALU를 이용하는걸 프로그래머가 지정해주지 않지만 CUDA에서는 저 ALU하나하나를 모두 프로그래머가 제어해 주어야 합니다. 여기에 CUDA프로그래밍의 어려움이 있는 것입니다.
저 ALU구성은 큰 구조는 같지만, 하드웨어에 따라서 전체 ALU의 개수나 ALU에서 사용하는 GPU의 내장메모리 용량이 틀려지기 때문에 그러한 사항들을 감안해서 프로그래밍을 해주어야 속도향상이라는 결과를 얻을 수 있습니다.
그렇기 때문에 GPU 메모리 구조에 대한 이해가 수반되어야 하는 겁니다.

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 아리수

2009/02/11 19:13 2009/02/11 19:13
, ,
Response
No Trackback , No Comment
RSS :
http://arisu.mireene.com/rss/response/101

Leave a comment

cuda template project(2)

여기부터는 template_kernel.cu 에 관한 내용입니다. 첫번째 포스트쓰고 이래저래 딴짓하느라 그 사이 CUDA2.0 이 나왔네요.

template_kernel.cu는 실제 GPU연산을 담당하는 함수가 들어가 있습니다.

__global__ void
testKernel( float* g_idata, float* g_odata)
{
  // shared memory
  // the size is determined by the host application
  extern  __shared__  float sdata[];

  // access thread id
  const unsigned int tid = threadIdx.x;
  // access number of threads in this block
  const unsigned int num_threads = blockDim.x;

  // read in input data from global memory
  // use the bank checker macro to check for bank conflicts during host
  // emulation
  SDATA(tid) = g_idata[tid];
  __syncthreads();

  // perform some computations
  SDATA(tid) = (float) num_threads * SDATA( tid);
  __syncthreads();

  // write data to global memory
  g_odata[tid] = SDATA(tid);
}


 여기서 void라는 것은 다른 프로그래밍 언어를 보아왔다면 많이들 보셨을 반환값이 없다는 그 뜻입니다. 그런데 여기에 __global__라는 구문이 붙어 있는데 이건 그래픽카드에 있는 여러가지 메모리종류중에서 global 메모리를 사용하겠다는 뜻입니다. CUDA프로그래밍 중에서는 상황에 따라서 어떤 메모리를 사용하느냐가 속도에 상당히 큰 영향을 미칩니다. 우선은 __global__이 들어가는 부분이 어떤종류의 메모리를 사용한다를 선언한다는 정도만 알고 넘어갑니다.

  // shared memory
  // the size is determined by the host application
  extern  __shared__  float sdata[];
여기서도 마찬가지로 __shared__는 어떤 메모리를 사용할까를 지정하는 것입니다.

  // access thread id
  const unsigned int tid = threadIdx.x;
  // access number of threads in this block
  const unsigned int num_threads = blockDim.x;
스레드아이디와 블럭아이디를 얻어옵니다. 이건 CUDA 병렬화와 관계가 있는데 CUDA는 데이터를 병렬로 처리하는데서 계산속도의 큰 향상을 얻습니다. 그러기 위해서 물리적으로 여러개의 계산 유닛이 그래픽카드안에 구조를 가지고 자리를 잡게 됩니다. 이러한 구조도 나중에 살펴보겠지만 위에 나오는 구문은 그 구조중에서 어떤부분을 사용할지를 얻어온다고 생각하면 되겠습니다. 예를 들어 for문을 돌려서 루프를 계산할때 1부터 10까지의 계산을 순차적으로 한다고 하면 1번 계산하고나서 2번 계산하고 그 다음에 3번 계산하고 이런식으로 진행이 되지만 CUDA에서는 그 각각의 계산들이 한꺼번에 동시에 진행이 되기 때문에 계산속도가 10분의 1로 줄어들게 됩니다. 물론, 그렇게 계산을 수행하기 위해서는 for문 안에서 돌아가는 계산들이 각각 의존적이지 않고 독립적으로 돌아가야 정상적으로 계산을 수행하게 됩니다.


  // read in input data from global memory
  // use the bank checker macro to check for bank conflicts during host
  // emulation
  SDATA(tid) = g_idata[tid];
  __syncthreads();
GPU메모리에 있는 데이터를 읽어와서 bank를 체크한다는데 이부분은 아직 메뉴얼을 봐도 정확히 잘 모르겠네요. nvidia의 데이비드 아저씨가 강의한 파워포인트 자료를 봐도 이부분은 헷갈리는 부분입니다. 영어가 짧아서 듣기는 안되고 강의자료만 보려니 그렇네요..ㅡㅡ;


  // perform some computations
  SDATA(tid) = (float) num_threads * SDATA( tid);
  __syncthreads();
GPU에서 실제 계산을 수행합니다. 여기서   __syncthreads(); 이 부분이 있어야 전체 데이터들이 엉키지 않고 정상적으로 처리가 됩니다. 병렬화를 위해서 쪼개어져 계산되었던 값들이 모두 계산을 끝낼때까지 기다린다음에 값을 취합하는 겁니다. 만약 이 부분이 없다면 계산이 모두 끝나지 않았는데도 다음 구문으로 넘어가게 되니 계산 결과에 심각한 에러를 초래할 수 있습니다.

  // write data to global memory
  g_odata[tid] = SDATA(tid);
그 다음에 사용했던 데이터를 global 메모리로 옮깁니다. 이건 GPU상에 존재하는 여러가지 메모리중 global로 값을 옮겨서 계산이 끝난 결과값에 CPU에서 접근이 가능하도록 만드는 겁니다

이 정도면 대략적으로 CUDA에 포함되어 있는 template project의 소스는 살펴본 것 같습니다. 지루한 개념공부보다는 일단 뭐라도 코드를 한번 돌려보는게 어떨까 싶어서 이걸 제일 먼저 다뤘습니다. 다음부터는 CUDA 프로그래밍에 필요한 개념정리와 디버깅 방법에 대해 정리해 볼까 합니다.

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 아리수

2008/05/20 22:03 2008/05/20 22:03
,
Response
No Trackback , 11 Comments
RSS :
http://arisu.mireene.com/rss/response/99

Comments List

  1. 이동환 2008/06/18 13:54 # M/D Reply Permalink

    안녕하세요 CUDA를 처음 배우고있는 학부생입니다

    님의 블로그에서 많은것 배워갑니다~

    앞으로도 계속해서 부탁드릴게요^^감사합니다

    1. 아리수 2008/06/19 14:12 # M/D Permalink

      그냥 혼자 정리하는 의미에서 포스팅하느라 정신없고 체계적이지도 않은데 보시는 분이 있으시군요..^^; 감사합니다.

  2. 윤한빈 2008/07/12 14:47 # M/D Reply Permalink

    ㅎㅎ 저역시 열심히 공부하고 있는 학생입니다.

    대충 CUFFT, CUBLAS 이런것들 만지면서 끄적거리고 있네요..^^

    좋은포스트 갑사합니다~언젠가 도움을 요청할지도..ㅜㅜ^

  3. 아리수 2008/07/13 21:29 # M/D Reply Permalink

    CUFFT, CUBLAS 둘 다 아직 float 형만 지원해서 실제로 사용하는데 제약이 있는 상황이죠. 그래도 기본적인 FFT, BLAS함수들은 지원하는지라 공부용으로는 괜찮은거 같아요.^^

  4. 키이임 2008/07/24 11:13 # M/D Reply Permalink

    안녕하세요-글 잘봤습니다....

    많은 도움이 됐어요^^

    앞으로도 계속 부탁드려요~ㅋ

  5. 아리수 2008/07/27 22:02 # M/D Reply Permalink

    CUDA 관련해서 들어오시는 분들이 꽤 있네요. 게을러서 잊고 있었는데 정리하는거 마저 해야겠다는 압박이..ㅋㅋ

  6. 06 2009/01/08 13:27 # M/D Reply Permalink

    글 잘읽었습니다~

  7. 시우 2009/01/15 15:19 # M/D Reply Permalink

    글 잘 읽었습니다. ㅋㅋ 압박을 즐기심이 ㅋㅋ

    1. 아리수 2009/01/19 15:17 # M/D Permalink

      이제 저도 많이 까먹어서 글쓰려면 다시 공부해야해요..;; 저때는 포트란이랑 C언어간 연동이랑 nvcc구조도 보고 했었는데 많이 까먹었네요.;;

  8. MESL 2009/02/11 13:38 # M/D Reply Permalink

    이런 좋은 글이 있을줄이야...
    많이 질문드려야겟어요!!
    너무 고마워요.ㅠㅠ

    1. 아리수 2009/02/11 18:25 # M/D Permalink

      감사합니다~

Leave a comment

cuda template project

cuda를 설치하고 나면 기본적으로 제공되는 예제들 중에 template에 관해서 살펴보겠습니다.

뭐 시작하기전에 메모리 종류라던가 커널이라던가 이것저것 알아야 할 것들이 많지만 일단 돌려보고 그런건 차차 하면서 알아 나가는게 좋지 않을까 합니다.

이 카테고리는 제가 공부하고 정리하는 의미가 있기 때문에 크게 순서에 얽매이지 않고 그냥 생각나는대로 쓰고 있음을 밝혀둡니다.;;

그럼 우선 한번 실행 시켜보도록 하죠.
Visual C++을 열고 C:\Program Files\NVIDIA Corporation\NVIDIA CUDA SDK\projects 폴더로 가면 예제들이 쭉 있습니다. 한 50개 좀 넘는군요..
이 중에서 template라는 폴더로 가서 솔루션을 엽니다.

그 다음 F5를 눌러 프로그램을 실행시켜 봅니다.
별 문제 없이 CUDA환경이 설정되었다면 아래와 같은 화면이 나올 겁니다.

사용자 삽입 이미지
시간은 머신마다 틀리게 나올거고 저렇게 나오면 정상적으로 돌아간 겁니다.

그럼 이제 저 화면이 어떻게 출력되었나를 template프로젝트의 소스를 보면서 알아보도록 하겠습니다.

우선 visual C++의 솔루션탐색기에서  src를 보면 3개의 파일이 존재함을 알 수 있습니다.
template.cu, template_gold.cpp, template_kernel.cu 이것들이 CUDA 프로그래밍을 하기 위한 기본적인 파일들인 것입니다.

이 파일들의 관계를 제대로 알아야지 CUDA프로그래밍을 할 수 있습니다.
NVIDIA에서는 쉽다고 말하면서 예제로 matrix연산 하는걸 메뉴얼에 올려놨는데 쉽기는...ㅡㅡ;
메뉴얼만 보면 쉽네? 하고 생각할 수 있겠지만 저같은 평민은 그 뒤에 감춰진 kernel이라던가 cu파일들 보면 어렵기만 하더군요.

우선적으로 template_gold.cpp를 보면 computeGold라는 함수에서 reference를 계산하는걸 볼 수 있습니다.
void
computeGold( float* reference, float* idata, const unsigned int len)
{
    const float f_len = static_cast<float>( len);
    for( unsigned int i = 0; i < len; ++i)
    {
        reference[i] = idata[i] * f_len;
    }
}

reference를 계산하는 목적은 GPU를 이용해서 계산한 값이 CPU와 이용한 값과 같은지를 비교하기 위해서 CPU를 이용해서 참조용 결과를 만드는 겁니다. 물론, 이건 예제이기에 저런 부분이 들어가는 것이고 GPU결과 검증을 위해서 필요한 부분이지만 실제로 프로그램을 작성할때는 저 부분은 빼주어도 cuda프로그래밍에 문제가 되지는 않습니다.

실제 CUDA프로그램은 template.cu, template_kernel.cu 라는 두 파일을 통해서 이루어 집니다. 이중에 template_kernel.cu는 실제 GPU상에서 연산이 이루어지는 내용을 포함합니다. 그리고 template.cu는 template_kernel.cu에 있는 testKernel이라는 함수를 돌리기 위한 준비과정과 돌리고 난후의 후처리를 담당합니다. 나중에 되면 굳이 파일을 2개로 분리할 필요없이 template.cu와 template_kernel.cu를 합쳐서 돌려도 별 문제없이 잘 돌아가는걸 확인할 수 있습니다. 일단, 개념 정립을 위해서는 template.cu는 GPU연산을 위한 준비와 후처리, kernel은 실제 GPU연산 수행 정도로 알아두면 될 것 같습니다.

template.cu를 보면 runTest라는 함수를 확인 할 수 있습니다.

void
runTest( int argc, char** argv)
{

    CUT_DEVICE_INIT();

    unsigned int timer = 0;
    CUT_SAFE_CALL( cutCreateTimer( &timer));
    CUT_SAFE_CALL( cutStartTimer( timer));

    unsigned int num_threads = 32;
    unsigned int mem_size = sizeof( float) * num_threads;

    // allocate host memory
    float* h_idata = (float*) malloc( mem_size);
    // initalize the memory
    for( unsigned int i = 0; i < num_threads; ++i)
    {
        h_idata[i] = (float) i;
    }

    // allocate device memory
    float* d_idata;
    CUDA_SAFE_CALL( cudaMalloc( (void**) &d_idata, mem_size));
    // copy host memory to device
    CUDA_SAFE_CALL( cudaMemcpy( d_idata, h_idata, mem_size,
                                cudaMemcpyHostToDevice) );

    // allocate device memory for result
    float* d_odata;
    CUDA_SAFE_CALL( cudaMalloc( (void**) &d_odata, mem_size));

    // setup execution parameters
    dim3  grid( 1, 1, 1);
    dim3  threads( num_threads, 1, 1);

    // execute the kernel
    testKernel<<< grid, threads, mem_size >>>( d_idata, d_odata);

    // check if kernel execution generated and error
    CUT_CHECK_ERROR("Kernel execution failed");

    // allocate mem for the result on host side
    float* h_odata = (float*) malloc( mem_size);
    // copy result from device to host
    CUDA_SAFE_CALL( cudaMemcpy( h_odata, d_odata, sizeof( float) * num_threads,
                                cudaMemcpyDeviceToHost) );

    CUT_SAFE_CALL( cutStopTimer( timer));
    printf( "Processing time: %f (ms)\n", cutGetTimerValue( timer));
    CUT_SAFE_CALL( cutDeleteTimer( timer));

    // compute reference solution
    float* reference = (float*) malloc( mem_size);
    computeGold( reference, h_idata, num_threads);

    // check result
    if( cutCheckCmdLineFlag( argc, (const char**) argv, "regression"))
    {
        // write file for regression test
        CUT_SAFE_CALL( cutWriteFilef( "./data/regression.dat",
                                      h_odata, num_threads, 0.0));
    }
    else
    {
        // custom output handling when no regression test running
        // in this case check if the result is equivalent to the expected soluion
        CUTBoolean res = cutComparef( reference, h_odata, num_threads);
        printf( "Test %s\n", (1 == res) ? "PASSED" : "FAILED");
    }

    // cleanup memory
    free( h_idata);
    free( h_odata);
    free( reference);
    CUDA_SAFE_CALL(cudaFree(d_idata));
    CUDA_SAFE_CALL(cudaFree(d_odata));
}

우선 CUT_DEVICE_INIT(); 를 호출하여 GPU를 사용할 준비를 합니다.
그 다음라인에서 수행시간을 측정하기 위한 변수를 할당하고 초기화 합니다.
     unsigned int timer = 0;
    CUT_SAFE_CALL( cutCreateTimer( &timer));
    CUT_SAFE_CALL( cutStartTimer( timer));

그리고 몇 개의 쓰레드를 돌릴 것인지 지정하고 거기에 맞는 메모리 크기를 지정합니다.
여기서 중요한게 쓰레드의 갯수를 몇개로 지정할 것인가인데 나중에 이부분이 계산 수행속도에 큰 영향을 미치게 됩니다.
    unsigned int num_threads = 32;
    unsigned int mem_size = sizeof( float) * num_threads;

그 다음 호스트와 디바이스에 각각 메모리를 할당하는 부분이 나오는데 호스트는 일반적인 CPU가 사용하는 ram을 말하는 것이고 디바이스 메모리할당은 그래픽카드에 있는 메모리를 사용하기 위해 할당하는 것입니다.
이때, cudaMalloc라는 함수를 이용해서 디바이스 메모리를 할당하고 cudaMemcpy라는 함수를 이용하여 호스트메모리에 있는 내용을 디바이스 메모리로 가져옵니다.
    // allocate host memory
    float* h_idata = (float*) malloc( mem_size);
    // initalize the memory
    for( unsigned int i = 0; i < num_threads; ++i)
    {
        h_idata[i] = (float) i;
    }

    // allocate device memory
    float* d_idata;
    CUDA_SAFE_CALL( cudaMalloc( (void**) &d_idata, mem_size));
    // copy host memory to device
    CUDA_SAFE_CALL( cudaMemcpy( d_idata, h_idata, mem_size,
                                cudaMemcpyHostToDevice) );

그리고 계산결과를 저장할 디바이스 메모리를 할당합니다.
    // allocate device memory for result
    float* d_odata;
    CUDA_SAFE_CALL( cudaMalloc( (void**) &d_odata, mem_size));

그 다음 CUDA에 존재하는 built-in 변수인 dim3형으로 그리드와 쓰레드를 지정해 줍니다. 이 부분은 nVidia 그래픽카드의 메모리구조를 알아야 이해할 수 있는 부분인데 그냥 아까 지정했던 갯수만큼 사용할 쓰레드를 지정한다고 생각하면 될 듯 합니다.(이 부분에 대한 정확한 내용은 아직 잘 모르겠습니다. 좀 더 공부 필요..근데 이런게 쉽다고하다니...메뉴얼 어디에도 설명이 없는데..-_-+)
    // setup execution parameters
    dim3  grid( 1, 1, 1);
    dim3  threads( num_threads, 1, 1);

그 다음 드디어 kernel을 실행시킵니다.
    // execute the kernel
    testKernel<<< grid, threads, mem_size >>>( d_idata, d_odata);

커널을 실행한 다음에 문제없이 잘 실행됐는지 확인을 합니다.
    // check if kernel execution generated and error
    CUT_CHECK_ERROR("Kernel execution failed");

호스트메모리에 디바이스에 저장되어 있는 결과를 가져올 메모리를 할당한 다음 디바이스에 있는 메모리의 결과정보를 호스트 메모리로 가져옵니다.
   // allocate mem for the result on host side
    float* h_odata = (float*) malloc( mem_size);
    // copy result from device to host
    CUDA_SAFE_CALL( cudaMemcpy( h_odata, d_odata, sizeof( float) * num_threads, cudaMemcpyDeviceToHost) );

그 다음 수행시간을 측정해서 화면에 출력합니다. 제일처음에 보았던 시간 출력이 이 부분입니다.
    CUT_SAFE_CALL( cutStopTimer( timer));
    printf( "Processing time: %f (ms)\n", cutGetTimerValue( timer));
    CUT_SAFE_CALL( cutDeleteTimer( timer));

reference용으로 쓸 결과를 CPU에서 계산 합니다.
    // compute reference solution
    float* reference = (float*) malloc( mem_size);
    computeGold( reference, h_idata, num_threads);

GPU에서 계산되어진 결과와 CPU에서 계산되어진 결과가 일치하는지 비교합니다.
    // check result
    if( cutCheckCmdLineFlag( argc, (const char**) argv, "regression"))
    {
        // write file for regression test
        CUT_SAFE_CALL( cutWriteFilef( "./data/regression.dat",
                                      h_odata, num_threads, 0.0));
    }
    else
    {
        // custom output handling when no regression test running
        // in this case check if the result is equivalent to the expected soluion
        CUTBoolean res = cutComparef( reference, h_odata, num_threads);
        printf( "Test %s\n", (1 == res) ? "PASSED" : "FAILED");
    }

할당되었던 메모리를 해제합니다.
    // cleanup memory
    free( h_idata);
    free( h_odata);
    free( reference);
    CUDA_SAFE_CALL(cudaFree(d_idata));
    CUDA_SAFE_CALL(cudaFree(d_odata));

이상이 기본적인 template.cu의 구조입니다.

쓰다보니 그냥 주석을 한글로 옮기는 정도밖에는 안되는군요..;;
글이 길어져서 template_kernel.cu는 다음 포스트로 넘어갑니다.

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 아리수

2008/05/02 23:30 2008/05/02 23:30
,
Response
No Trackback , 1 Comment
RSS :
http://arisu.mireene.com/rss/response/97

Comments List

  1. 시우 2009/01/15 15:19 # M/D Reply Permalink

    좋은 정보 감사드립니다~
    다음 편을 기대하겠습니다.

Leave a comment

CUDA 프로그래밍 기본개념

CUDA는 일반적인 CPU연산이 아닌 GPU연산을 합니다. 그래서 일반적인 코딩을 할때보다 신경써주어야 할 부분들이 더 있습니다.

여러가지가 있는데 그 중에서 우선 GPU연산을 위해서는 CPU에 있는 데이터를 GPU용으로 바꾸어야 합니다.

메인보드 ram에 있는 데이터를 GPU ram으로 옮기는 거죠.

이때 메모리에 데이터를 어떻게 할당을 하고, GPU에는 여러가지 종류의 메모리가 있는데 그 중에서 어떤 메모리를 활용 하느냐에 따라서 성능차이가 많이 나게 됩니다.
메모리를 잘못 사용하면 CPU보다 느린 성능을 낼수도 있습니다.;;

그런 다음에 그 데이터를 이용해서 GPU상에서 계산을 합니다.
계산한 결과는 GPU에 있기 때문에 GPU에 있는 데이터를 CPU로 가지고 오면 CUDA의 역할이 끝나게 됩니다. 이런 과정이 CUDA 및 GPGPU프로그래밍의 기본적인 개념입니다.

일반적인 GPGPU에서는 이렇게 데이터를 GPU에 올리고 내리고 할때 그래픽스에 관한 지식이 있어야 가능하지만 CUDA의 목적은 그런 지식 없이도 일반적인 C프로그래머들이 접근하기 용이하게 만드는게 목적입니다. (그러나 여전히 제 수준에는 어렵다는..;;)
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 아리수

2008/04/30 10:06 2008/04/30 10:06
,
Response
No Trackback , No Comment
RSS :
http://arisu.mireene.com/rss/response/93

Leave a comment

불친절한 CUDA 설치하기 정리

테스트환경
필요 hardware
  CUDA 사용 가능한 GPU 머신
  참조 : http://kr.nvidia.com/object/cuda_learn_products.html

  * G80 시리즈 중에서 8400은 현재 4만원이면 구입가능. 나머진 너무 비쌈..ㅡ_ㅡ;
     CUDA에서 에뮬레이션 모드를 지원하나 실제 머신에서 돌리는 것과 에뮬레이션 모드에서 돌릴때의 차이가 있기 때문에 에뮬레이션보다는 실제머신에서 돌려보는 것을 추천.
     ex) double precision같은 경우 현재 출시되어 있는 GPU들은 지원하지 않음. 그래서 실제 하드웨어 상에서 double을 쓰면 문제 발생. 그러나 에뮬레이션 모드에서는 이런 문제가 발생하지 않음.
필요 software
  windows xp
  visual c++ 2005 express edition

CUDA toolkit 과 CUDA SDK를 순서대로 설치
다운 : http://kr.nvidia.com/object/cuda_get.html
* 경우에 따라 CUDA Dirver 필요할 수 있음.

테스트
CUDA SDK가 설치된 경로인 "NVIDIA CUDA SDK\projects" 에 있는 예제들을 돌려서  잘 돌아가는지 확인. ex) MatrixMul

CUDA 프로그램 작성
새로운 CUDA 프로그램을 작성하려면 projects폴더에 있는 예제중에 template라고 되어 있는 걸 원하는 곳에 복사한 다음 이름을 바꿔서 사용 하면됨.

현재 CUDA파일은 .cu 라는 확장자를 가지고 kernel부분이 따로 분리되어 있으나 kernel을 분리할 필요없이 하나의 파일에 통합해서 프로그래밍 하는 것도 가능함.

설치 관련된 내용은 CUDA SDK 가 설치된 하위 폴더중 doc라는 폴더의 CUDA_SDK_release_notes_windows.txt 을 참조.

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 아리수

2008/03/18 22:48 2008/03/18 22:48
,
Response
No Trackback , 4 Comments
RSS :
http://arisu.mireene.com/rss/response/91

Comments List

  1. 현호 2008/07/17 10:27 # M/D Reply Permalink

    잘 봤습니다. 고맙습니다.

    1. 아리수 2008/07/18 09:39 # M/D Permalink

      감사합니다.^^

  2. 애기다람쥐 2008/07/24 12:04 # M/D Reply Permalink

    CUDA 에 대해서 공부를 한번 해보고 싶어서
    이리저리 다니다가 우연히 이곳을 오게 되었습니다..

    우선 설치 하고 하는데.. 먼가좀 돌아가야 할텐데.. 돌아가질 않네요.

    Toolkit, SDK 와 드라이버도 설치를 했습니다.
    툴킷은 c:\couda 에 설치가 되었습니다.
    SDK 는 프로그램 파일 폴더에 잘 설치가 된거 같습니다.

    이 상태에서 먼가를 해보고 싶은데.. 잘 모르겠네요.
    OS 는 서버2008를 쓰고 있고요. VS2008 를 쓰고 있습니다.
    그래픽카드는 지포스 8500 이고요..

    제가 아직 많은 지식이 없고 초보라서.. 혹시 조언좀 부탁 드립니다.^^

    sisioo@nate.com

    ^^ 수고하세요.

  3. 아리수 2008/07/27 22:07 # M/D Reply Permalink

    설치 하셨으면요. 설치폴더에 들어있는 예제폴더들 돌려보시구요.
    template project돌리는건 여기에도 정리해 놨으니 보시고 하시면 될거예요.

    template돌려보셨으면 예제중에 matrixmul이라는게 matrix연산하는 간단한 예제이니 돌려보시면 될거예요. matrixmul은 CUDA 메뉴얼에도 예제로 나와있으니 참고하시면서 보시면 될거예요.

Leave a comment

CUDA 시작 글

CUDA 관련 기본글 퍼온 것

CUDA
("Compute Unified Device Architecture"),는 그래픽 처리장치(GPU)에서 수행하는 알고리즘을 코딩하는데 있어서 C 프로그래밍 언어를 사용할 수 있도록 하는 GPGPU 기술이다. CUDA는 엔비디아(Nvidia)에 의해서 개발되어져왔고 이 아키텍쳐의 사용하기위해선 Nvidia GPU와 특별한 스트림 처리 드라이버가 필요하다. CUDA는 G8X GPUs로 구성된 GeForce 8시리즈에서 동작할 수 있다.; Nvidia는 GeForce 8 시리즈상에 작성된 프로그램은 앞으로 개발될 Ncidia 비디오 카드에서도 프로그램 수정없이 작동할 것이라고 선언했다. CUDA는 CUDA GPUs 안의 명령셋과 대용량 병렬처리 메모리를 접근할 수 있도록 해준다.

최초의 CUDA SDK는 2007년 2월 15일에 공개되었다. CUDA의 컴파일러는 Open64에 기반을 두었다.

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 아리수

2008/03/18 22:17 2008/03/18 22:17
,
Response
No Trackback , No Comment
RSS :
http://arisu.mireene.com/rss/response/90

Leave a comment