f

우분투에 쿠다 설치할 때 missing required library libglut.so 에러

2013.02.20 15:04 콤퓨타/CUDA

missing required library libglut.so 이런 에러가 발생하면

sudo apt-get install libglew-dev freeglut3-dev 설치해 줄 것.

Trackbacks 0 / Comments 0

could not find -lcuda

2013.02.20 15:04 콤퓨타/CUDA

Ubuntu 10.04 LTS 64bit

CUDA 4.0

 

sudo apt-get install nvidia-current

sudo ln -s /usr/lib/nvidia-current/libcuda.so /usr/lib/libcuda.so

Trackbacks 0 / Comments 0

ubuntu 10.04 64bit에서 cannot find -lcutil

2013.02.20 15:03 콤퓨타/CUDA

<환경>

Ubuntu 10.04 64bit

Cuda 4.0

cannot find -lcutil 에러

Makefile에서 라이브러리를 직접 링크해줘야함

-L$(CUDA_HOME)/lib64 -lcutil_x86_64

Trackbacks 0 / Comments 0

CUDA shared memory와 coalesced memory access

2013.02.20 15:02 콤퓨타/CUDA

 

[출처 : http://eaglface.blogspot.kr/2008/08/cuda-shared-memory-coalesced-memory.html]

뭔가 새로운 것을 배워나갈때 좋은 방법중에 하나는 잘 만들어진 예제를 참고하는 것이다. CUDA의 경우에는 SDK에 꽤나 좋은 예제가 많아서 배울 때 도움이 많이 된다.

그 중에 Convolution예제는 반드시 봐 두면 좋을 것 같은 예제다. 우선 원래 알고리즘이 매우 직관적이고 Serial implementation이 간단해서 원래 뭐였는지 고민할 필요가 없다는 점이 좋고, CUDA로 대충 구현했을때도 간단히 할 수 있지만 생각보다 속도가 나오지 않으며, 예제의 구현을 따라가면 훨씬 효율적으로 구현할 수 있음을 확인하면서 일반적인 CUDA 구현을 배울 수 있기 때문에 그렇다.

이번 포스트에서 생각해보고자 하는 것은 왜 나이브한 구현이 느려지는지와 shared memory의 사용에 대한 것이다. CUDA를 이용해 GPU를 구동했을 때 빨라지는 것은 거의 thread의 수가 늘어나는 것과 메모리 활용에 달려있다. 가능한 한 많은 thread를 동시에 구동할 수 있게 하는 것과, memory access pattern을 디자인하는 것이 속도 향상을 꾀할 때 필요한 것이다.

thread의 갯수는 거의 알고리즘의 복잡도에 달려있는데 이는 총 thread의 수가 각 thread내에서의 레지스터와 블럭 내의 shared memory사용량에 달려있기 때문이다. 다른 한 가지 요소는 coalesced memory access를 할 수 있는가이다. coalesced memory access는 각 thread가 메모리의 연속된 값에 접근할 때 한꺼번에 가져오거나 쓰는 것을 말하는데, 몇 가지 요구사항이 만족될 때만 이루어진다. 이를 coalescing requirement라고 하는데, 프로그래밍 가이드에 나와있기로는,
1) 각 thread가 32, 64, 128비트(4,8,16바이트) 워드를
2) thread number N인 thread가 (HalfWarpBaseAddress + N)에 접근하고
3) HalfWarpBaseAddress가 16*sizeof(type) 바이트의 주소 구조를 가지는 경우
이다.

그러나 모든 알고리즘이 이런 조건을 만족시킬 수 없으므로 성능은 생각보다 저하된다. 어떤 경우에는 데이터를 먼저 정렬시켜 넘겨줌으로써 가능할 수도 있지만 정렬에도 시간이 걸리며, 가능하지 않은 경우도 많다. 이 같은 경우 shared memory를 버퍼로 사용하여 메모리에 접근하면 눈에 띄는 성능 향상을 얻을 수 있다.

기본적인 아이디어는 각 thread를, 1)데이터 수집, 2) 프로세싱, 3) 데이터 저장 의 세 단계로 만드는 것이다. 데이터 수집단계에서는 필요한 data를 parallel thread를 써서 coalescing access하여 shared memory buffer에 가져오고, 프로세싱 단계에서는 이 데이터를 처리해서 다른 shared memory에 담고, 저장 단계에서는 프로세싱된 데이터를 다시 coalescing access로 global memory에 돌려주는 것이다. 각 단계 사이에 thread동기화를 통해 데이터를 확실히 얻도록 해야 한다. 불필요한 동작이 많은 것 같아 보이지만 메모리 접근횟수가 확실히 줄어들고 shared memory는 매우 빨리 읽고 쓸 수 있기 때문에 더 빠른 구현이 가능해진다. multiplication이나 convolution 예제에서는 이런 데이터 접근에 대해서 상세히 설명하고 있다.

빠른 버퍼를 두어서 데이터 접근 패턴을 바꾸는 것은 반드시 알아두어야 할 테크닉으로 이를 통해서 약 10배의 속도향상을 얻을 수 있다.

다루고 있는 데이터가 4,8,16 바이트가 아닐 경우에는 문제가 약간 복잡해지는데, 이 때는 4,8,16 바이트의 크기를 갖는 char struct를 정의해 두고, type casting을 통해 강제로 읽어들이게 하여 해결해야 한다. 어떤 경우든 인덱싱과 base address요구조건에 신경을 써 줘야만 함에 주의하자.

Trackbacks 0 / Comments 0

CUDA에서 구현시 생각해야 할 것

2013.02.20 14:50 콤퓨타/CUDA

 

[출처 : http://eaglface.blogspot.kr/2008/06/cuda.html]

1) global memory access
알고리즘에 따라 메모리에 접근하는 방법이 다를 텐데, CUDA에서는 global memory에 Random access를 할 경우 성능이 무지하게 저하되어 버린다. global memory를 쓰려면 Coalesced access를 할 필요가 있는데, 이게 조건이 상당히 까다롭네.

뭐 물론 익숙해지면 여러가지 방법을 쓸 수 있겠지만, 일단 아직 익숙치가 않다. 흑...

2) shared memory access
shared memory는 global memory 보다 무지하게 빠르므로 최대한 이용할 수 있도록 한다. 레지스터 보다는 좀 느린 것 같긴 한데, 그래도 충분히 빠르니까.

문제는 shared memory 크기가 그리 크지 않다는 것인데, 16KB로 전부 나눠써야하니까 너무 낭비하게 되면 다른 thread block을 할당할 수 없는 사태가 발생할 수도 있으니 주의. 그래두 뭐 이런 것도 레지스터를 적게 쓰는 알고리즘을 만들었을때나 통하는 얘기고, 레지스터 많이 써버리면 결국 한 블록 밖에 못 돌리니까 shared memory는 더 많이 쓸 수 있게 되더라... 좋은 건지는 모르겠지만.

3) constant memory
constant memory는 device에서 쓸 수는 없고 읽을 수만 있기 때문에 kernel 진입전에 전부 set해주고 들어가야 함. global memory상에 있으나 8KB/MP의 비교적 큰 캐시를 사용하게되고 동시에 돌리는 어떤 thread block에서도 coalescing 없이 빠르게 접근이 가능하므로 상수 테이블을 올려서 사용하면 좋을 듯. 특히 8KB이내의 테이블이면 레지스터를 사용하듯 사용할 수 있다. 물론 읽기만 되지만...

4) thread control
쓰레드 배치는 memory coalescing 과 관련이 깊으므로 심사숙고 해야 함. 특히 thread내에서 divergent branch가 일어나면 다 엉망이 되므로 thread sync시점을 잘 조정해야 할 듯

Trackbacks 0 / Comments 0

Copyright © 어니엉월드 All Rights Reserved | JB All In One Version 0.4 Designed by CMSFactory.NET