Search

'VS11'에 해당되는 글 1건

  1. 2011.12.01 [미리보는 C++ AMP-2] C++ AMP 맛 보기

[미리보는 C++ AMP-2] C++ AMP 맛 보기

DirectX 11 2011.12.01 08:00 Posted by 조진현


백문이 불여일견이라고들 하죠?
글로써 언급하는 것보다,
프로그래머들은 코드로 볼 때 더 직관적인 이해를 할 수 있는 경우가 많습니다.

간단하게 두 배열의 합을 구하는 코드를 통해서,
이를 AMP 적으로 어떻게 작성하는지를 보겠습니다.

아래는 우리가 일반적으로 생각할 수 있는 CPU를 활용해서
합을 구하는 코드입니다.

void AddArrays(int n, int * pA, int * pB, int * pC)

{

   for (int i=0; i<n; i++)

   {

      pC[i] = pA[i] + pB[i];

   }

}


자세한 설명은 생략해도 될 것이라 생각합니다.^^
아래는 C++ AMP로 작성된 합을 구하는 코드입니다.

#include <amp.h>

using namespace concurrency;

void AddArrays(int n, int * pA, int * pB, int * pC)

{

   array_view<int,1> a(n, pA);

   array_view<int,1> b(n, pB);

   array_view<int,1> sum(n, pC);

   parallel_for_each( sum.grid,

                                          [=](index<1> i) restrict(direct3d)

   {

      sum[i] = a[i] + b[i];

   }   );

}


 

위의 AMP 구현 부분에서 색상이 들어간 부분이 CPU를 활용한 부분과 다른 부분입니다.
코드량이 증가해버린 단순한 사실을 우리는 확인할 수 있습니다.
코드가 증가한 가장 기본적인 이유는 메모리 문제입니다.
우리가 지금까지 C++ 에서 사용하는 메모리는 CPU 가 접근할 수 있는 시스템 메모리입니다.
이 메모리를 GPU 로 처리하기 위해서는 GPU가 직접적으로 접근 가능해야 합니다.
그런데 C++ 에서 할당한 메모리는 GPU가 접근할 수가 없습니다.
그래서 비디오-메모리에 시스템-메모리의 데이터를 복사하는 과정이 필요합니다.
그 과정이 바로 코드의 증가를 불러오는 것입니다.
( 복사라고 보기는 조금 모호합니다만, 지금은 그냥 넘어가겠습니다. )

이 증가한 코드들에 대해서 지금부터 살펴보겠습니다.


#include <
amp.h>

using namespace concurrency;


AMP를 사용하기 위한 헤더의 선언입니다.
기본적으로 AMP를 사용하기 위해서는 람다식과 concurrency  에 대한 이해가 있어야 합니다.


array_view
<int,1> a(n, pA);

array_view<int,1> b(n, pB);

array_view<int,1> sum(n, pC);

이 부분은 앞서 언급했던 GPU가 접근할 수 있는 메모리 영역으로
데이터를 만드는 부분입니다.
이 데이터를 만들 수 있는 메모리 영역이
array 와 array_view 라는 것으로
구분됩니다.
이 둘의 차이는 이후에 다루어 드릴테니,
지금은 GPU가 접근할 수 있는 메모리 영역으로 생각해 주셨으면 합니다.^^


parallel_for_each(
 ... ) restrict( direct3d )

c++ 에 main(...) 이 있다면, AMP 에는 parallel_for_each( ... ) restrict( direct3d ) 가 있습니다.
이 부분은 GPU가 연산을 시작하는 진입점( EntryPoint ) 입니다.

parallel_for_each를 잘 모르시는 분들은 아래의 링크를 참고하시 바랍니다.
http://vsts2010.net/123
더 자세한 사항은 이 블로그의 VC++ 10 Concurrency Runtime 카테고리를 참고하시기 바랍니다.

 

제가 단순하게 정리해 드리면,
기존에 VC++ 10 에서 사용되는 parallel_for_each 는 CPU를 활용해서 병렬적으로 처리하는 것이지만,
뒤에 restrict( direct3d )를 명시함으로써 이를 GPU에서 병렬적으로 처리
하도록 합니다.
 

이 진입 함수는 parallel_for_each(  람다식 ) 형태를 가지게 됩니다.
이는 GPU의 많은 스레드들에게 '이 람다식을 각각 실행해 주세요' 라고 명령을 내리는 것입니다.
역시 람다( Lambda ) 에 대해서 잘 모르시는 분은 옆의 카테고리에서
c++0x 를 보시기 바랍니다.
람다의 첫번째 설명 링크는 아래와 같습니다.
http://vsts2010.net/73

 

그러면 얼마나 많은 스레드들이 람다식을 실행해야 하는지에 대한 명시가 있어야 합니다.
그것이 바로 paralle_for_each( ... ) 의 첫번째 인자인 sum.grid 입니다.

grid 에 대한 설명은 뒷부분에서 자세히 다루겠으니,
지금은 스레드 갯수에 대한 정의로 보시면 충분합니다.

람다식의 인자로 index<1> idx 가 보이실 것입니다.
이 인자는 람다식에 전달되는 스레드들의 ID들입니다.
이 ID들을 통해서 스레들을 식별할 수 있습니다.
스레드들의 ID를 통해서 배열 형태의 데이터를 캡쳐해서 값을 저장하는 것입니다.

간단한 프로그램이지만, 사실 이런 형태가 C++ AMP의 전부입니다.^^

물론 이렇게 간단히 끝나면 무척 행복하겠지만,
난이도는 역시 알면 알수록 높아집니다.^^


본 글에서 사용된 예제들은 MS에서 사용된 예제들입니다.
제가 구현한 것들이 아님을 알려드립니다.^^

신고