오늘날 멀티코어 프로세서 세상은 이기종 컴퓨팅 환경이 대부분이라 해도 과언이 아니다.
병렬 컴퓨팅은 비약적인 속도 향상과 전력 소비 감소라는 장점이 있지만 사용하기가 까다롭고 특히 다양한 아키텍처로 이루어진 이기종 컴퓨팅 환경에서는 소프트웨어 개발이 더욱 어려워진다.
이 프리젠테이션에서는 이기종 컴퓨팅 환경에서의 병렬 처리를 위한 프로그래밍 언어를 소개하고 OpenCV와 같은 영상처리 라이브러리에서의 활용 예시를 보여준다
3. 멀티코어의 필요성 (= 병렬화의 필요성)
성능? 전력 소모? 소모 전력당 성능이 중요해짐
4. 코어는 한번에 하나의 명령
(instruction)을 처리하는 하드웨
어 연산장치
프로세서는 코어와 캐쉬 메모리,
컨트롤러 등을 구성하여 하나의
Die에 구현한 것
시스템은 프로세서, 메모리, I/O
버스 등으로 구성한 하나의 복합
체
시스템 안의 프로세서 안의 코어
5. 병렬 컴퓨팅을 위한 프로세서(수 십개의 코어)
= 주로 데이터 병렬화 (예 : GPU)
직렬 컴퓨팅을 위한 프로세서(몇 개의 코어)
= 주로 태스크 병렬화 (예 : 쿼드코어 CPU)
멀티코어 프로세서의 분류
6. 멀티코어 프로세서의 분류
SMP(Symmetric Multi Processor)
- Homogeneous Computing
AMP(Asymmetric Multi Processor)
- Heterogeneous Computing
7. 멀티코어 프로세서 발전 과정
1die
1core
1die
1core
x N 1die
N core
1die
SMP +
ASMP
8. 멀티코어 프로세서 설계 트렌드 변화
과거에는 목적에 따라
SMP 또는 ASMP를 설계
SMP와 ASMP의 장점을 모
두 접목시킨 설계로 발전
다양한 산업의 요구사항을
만족하기 위하여
10. 같은 종류의 코어들로 구성
(일반적으로 CPU들을 하나의 프로세서에 구현)
다른 종류의 코어들로 구성
(CPUs, GPUs, DSPs 하드웨어 가속기 등을
하나의 프로세서에 구현)
각각의 코어에서 동일하게 동작 각각의 코어에서 동작의 균일성을 보장 못함
각각의 코어들은 범용 목적으로 설계됨 각각의 코어들은 보통 특정 목적에 최적화됨
태스크를 분산시키기 좋음(Task off loading)
태스크 분산이 복잡함
소프트웨어 호환성이 좋음
소프트웨어 호환성이 나쁨
13. Stanford 대학에서 Ian Buck 박사가 제안
ANSI C를 확장한 데이터 병렬화를 위한 초창기 언어
Streaming programming 모델 개념 도입
현재 병렬 프로그래밍 분야의
핵심 Guru 들이 Brook Language에 관여하였고
오늘날 기술들이 Brook의 영향을 받음
Brook Language (Stream computing on graphics H/W)
14. Streams :
- 비슷한 연산이 요구되는 데이터의 집합
- 데이터의 병렬 처리
- 배열과 비슷하지만 index 연산이 불가능
Ray r<200>;
float3 velocityfield<100,100,100>;
r[3] = 3; // ERROR!!
예를 들면 이런 연산들
16. Arithmetic intensity(산술 집중도) 때문
Arithmetic intensity는 ( GPU로)전송된 데이터당 수행된 명령어의 수에 의해 결정됨
만약 이 하나의 data element만 수정한다면 메모리 접근
이 끝날 때까지 다른 element들은 기다려야 한다
따라서 Streamming programming 에서는 stream 내의
특정 element에 대한 접근은 불허
이상적인 GPGPU 연산은 최대한 많은 데이터를 최대한
병렬화로 처리를 하고 데이터 element간의 의존도를 최
소화 해야 한다.
왜 Array 접근, 연산을 허용하지 않는가?
17. GPGPU를 위해 Nvidia에서 개발한 기술
가장 성공적인 상업용 기술 중 하나
nVidia는 Brook을 제안한 Ian Buck을 고용하여 CUDA 프로젝트를 진행
CUDA에는 Stream, kernel 과 같은 개념이 그대로 적용되어 있다
CUDA는 nVidia 사의 GPGPU만을 위한 기술이지만 병렬 프로그래밍을 성공적
으로 상업화 하였다는데에 그 의미가 있다
그 외에도 MS의 C++ AMP나 OpenACC 등과 같은 기술들도 존재한다
CUDA
취업의 신
19. OpenCL
Apple의 SW 아키텍트 Munshi Aaftab에 의해 제안
이기종 플랫폼에서 이식성과 확장성을 높이기 위해 제안된
개방형 범용 병렬 컴퓨팅 프레임워크
(CPU, GPU, DSP 등의 프로세서로 이루어진 이종 플랫폼에서 실행되는 프로그램 작성을 위함)
OpenCL 표준명세는 Khronos 에서 관리
현재 2.0까지 공개되어 있으며 많은 SDK들은 OpenCL 1.2를 지원 한다.
https://www.khronos.org/opencl/
얼굴 공개 안함
Munshi Aaftab역시 CUDA와 Brook의 영향을 받았고
OpenCL와 CUDA의 문법이 크게 다르지 않다.
OpenCL-CUDA 간의 코드 이식 연구들도 진행된 바 있다
20. 이 프리젠테이션 에서는 OpenCL 에 대한 자세한 명세를 모
두 다룰 수 없기 때문에 중요한 특징만 짚고 넘어 가도록 할
예정이다.
21. 호스트
디바이스
디바이스
디바이스
계산 유닛
계산 유닛
계산 유닛
계산 유닛
계산 유닛
(Compute Unit)
Processing
Element
OpenCL 플랫폼 모델
Legacy program이
여기서 수행된다.
int main(){
...
}
OpenCL C program이
여기서 수행된다
__kernel__ void func(){
...
}
단 하나의 호스트와 한 개 이상의 디바이스로 구성
22. 호스트는 Master 프로세서이며 Legacy 프로그램이 동작하는 환경
즉, 입출력이나 프로그램 사용자 등 OpenCL 프로그램 외부의 환경과 상호작용
디바이스는 Slave 프로세서이며 OpenCL 계산 유닛, 즉 커널을 수행
실질적인 병렬 연산이 디바이스에서 수행되며 실제적인 계산은 PE(Processing
Element) 안에서 이루어진다.
디바이스는 CPU, GPU, DSP 또는 하드웨어 가속기 등이 될 수 도 있다
OpenCL 플랫폼 모델
23. OpenCL 플랫폼 모델
Master 프로세서가 다른 Slave 프로세서들을 관
리하는 구조는 태스크를 Offloading 하고 처리
결과를 취합 및 동기화
25. 커널은 연산을 위한 핵심 로직!!
이 핵심 로직은 이기종 플랫폼 간의 높은 이식성을 위해
OpenCL C 언어로 구현되며 OpenCL C 컴파일러로 컴파일
된다
OpenCL C는 상당 부분을 ANSI C 표준을 기준으로 설계되
었지만 병렬처리를 위해 추가(내장 함수들)되거나 제약(I/O,
stdlib 등) 되는 기능과 문법 들이 많다.
26. 호스트 프로그램은 OpenCL안에서 정의된 커널 객체들이 어떻
게 상호 연동해야 하는지를 규정
이 정책과 연산 순서를 문맥이라고 한다
문맥에 포함된 것은 한 개 이상의 프로그램 객체이고 이 객체는
커널을 위한 코드를 갖고 있다
27. OpenCL 예제
OpenCL 창시자이자 OpenCL programming
guide 저자인 Aafftab Munshin는 블로그 관리가
귀찮았는지 폐쇄하고 예제 코드를 구글 코드 저
장소에 올려버렸으니 참고하길 바란다
https://code.google.com/p/opencl-book-samples/
28. Hello OpenCL
HelloWorld.cpp 에는 우리가 잘 아는 c++ 언어로
구현되어 문맥이 작성되어 있다.
HelloWorld.cl 은 C 언어 문법이지만 조금은 생
소한 지시자가 보인다.
__kernel 지시자는 커널 함수를 의미한다
29. HelloWorld.cl
__kernel void hello_kernel(__global const float *a, __global const float *b, __global float *result)
{
int gid = get_global_id(0); //OpenCL에서 element에 접근하기 위한 기준인 1차원 global ID를 받아오기 위함
result[gid] = a[gid] + b[gid]; // 병렬 연산. Streaming programming 이다
}
+
=
a
b
result
30. (The world’s most complex) HelloWorld.cpp
int main(int argc, char** argv)
{
cl_context context = 0;
cl_command_queue commandQueue = 0;
cl_program program = 0;
cl_device_id device = 0;
cl_kernel kernel = 0;
cl_mem memObjects[3] = { 0, 0, 0 };
cl_int errNum;
// 문맥 객체 생성
context = CreateContext();
// 명령큐 객체 생성
commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);
// OpenCL 프로그램 객체 생성
program = clCreateProgramWithSource(context, 1, (const char**)&srcStr, NULL,
NULL);
// OpenCL 커널 객체 생성
kernel = clCreateKernel(program, "hello_kernel", NULL);
// 명령큐에 커널 전달 및 연산 수
행
errNum = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL,
globalWorkSize, localWorkSize,
0, NULL, NULL);
// 버퍼로부터 결과값 읽어옴
errNum = clEnqueueReadBuffer(commandQueue, memObjects[2], CL_TRUE, 0,
ARRAY_SIZE * sizeof(float), result, 0, NULL, NULL);
// 결과 출력
for (int i = 0; i < ARRAY_SIZE; i++)
{
std::cout << result[i] << " ";
}
std::cout << std::endl;
std::cout << "Executed program succesfully." << std::endl;
Cleanup(context, commandQueue, program, kernel, memObjects);
return 0;
}
// 메모리 객체 생성
float result[ARRAY_SIZE];
float a[ARRAY_SIZE];
float b[ARRAY_SIZE];
for (int i = 0; i < ARRAY_SIZE; i++)
{ a[i] = (float)i; b[i] = (float)(i * 2); }
memObjects[0] = clCreateBuffer(context, CL_MEM_READ_ONLY |
CL_MEM_COPY_HOST_PTR, sizeof(float) * ARRAY_SIZE, a, NULL);
memObjects[1] = clCreateBuffer(context, CL_MEM_READ_ONLY |
CL_MEM_COPY_HOST_PTR, sizeof(float) * ARRAY_SIZE, b, NULL);
memObjects[2] = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(float) *
ARRAY_SIZE, NULL, NULL);
...
// 커널 인자에 메모리 객체 포인
터 전달
errNum = clSetKernelArg(kernel, 0, sizeof(cl_mem), &memObjects[0]);
errNum |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &memObjects[1]);
errNum |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &memObjects[2]);
size_t globalWorkSize[1] = { ARRAY_SIZE };
size_t localWorkSize[1] = { 1 };
31. 명령큐
// 문맥 객체 생성
// 명령큐 객체 생성
// OpenCL 프로그램 객체 생성
// OpenCL 커널 객체 생성
// 메모리 객체 생성
// 커널 인자에 메모리 객체 포인터
전달
// 명령큐에 커널 전달 및 연산 수행
// 명령큐로부터 결과값 읽어옴
// 결과 출력 호스트
디바이스
커널
객체
커널
객체
메모리 객체
메모리 객체
메모리 객체
커널
객체
메모리 객체
HelloWorld.cpp
커널 연산
수행
결과값 복사
프로그램 객체
HelloWorld.cl gray_scale.cl
프로그램 객체
직접 접근 불가!
이 개념을 문맥이라 한다
32. 플랫폼 1
플랫폼, 디바이스 그리고 문맥
플랫폼1 플랫폼1
CPU
GP
U
GP
U
문맥 문맥
OpenCL에서 문맥은 연관된 디바이스들과 메모리 객체, 명령
큐를 위한 컨테이너를 제공한다
특정 디바이스, 또는 디바이스들 사이의 통신을 수행하는 것
이 바로 문맥(Context) 이다
OpenCL은 문맥의 관점에서 메모리 모델을 정의하며 같은 문
맥안에 있는 모든 디바이스들은 메모리에 있는 내용의 갱신
을 볼 수 있도록 보장한다
- OpenCL Programming guide 중에서 -
33. 프로그램 객체란?
프로그램 객체는 커널에서 사용하는 함수들을 정의하는 동적 라
이브러리고 생각하는 것이 좋다.
왜냐하면 프로그램 객체는 호스트 프로그램 안에서 런타임
에 빌드 되기 때문이다
프로그래머는 OpenCL 응용을 작성하고 최종 사용자에게 전해주는데, 최종 사용자
는 그 OpenCL 응용을 어디서든 실행 가능하다
응용 프로그래머는 엔드 유저가 어떤 GPU나 CPU 에서 혹은 다른 칩 위에서 응용
을 실행할지 알 수 없다!
프로그래머가 알 수 있는 것은 그냥 타겟 플랫폼이 OpenCL명세를 따른다는 것 뿐
이다.
HelloWorld.cl
디바이스A 디바이스B
프로그램 객체A 프로그램 객체A
런타임에 빌드
커널
객체
커널
객체
커널
객체
커널
객체커널
객체
34. Hello OpenCL
역대 Hello world 예제를 많이 보았지만 OpenCL 예제가 가장 길고 복잡한 것으
로 보임
디바이스 자원을 활용하기 위해 호스트와 디바이스간 데이터 공유 절차가 복잡
한 이유는
1) 다양한 디바이스를 지원하기 위한 추상화와
2) 병렬화를 위한 제약사항 때문
35. OpenCL을 지원하는 플랫폼 및 프로젝트들
개방형. 플랫폼 독립적. 이러한 OpenCL의 장점은
이기종 멀티코어 프로세서 세상에서 그 진가를 발휘하고 있다
특히 멀티미디어 데이터 처리가 중요한 분야에서
36. OpenCL SDK를 지원하는 Chip vendor들
상당수의 major chip vendor들 역시 OpenCL을 지원하기 위한 SDK를 발표
37. OpenCV 와 병렬처리
OpenCV는 가장 대표적이고 유명한 컴퓨터 비전, 이미지 처
리, 머신 러닝을 위한 오픈소스 라이브러리
다양한 플랫폼을 지원하기 때문에 이식성이 뛰어남
주로 2차원의 영상 데이터를 다루기 때문에 데이터 병렬화
의 이득을 가장 많이 받는 라이브러리 중 하나
43. OpenCV on OpenCL
OpenCV는 이미 CUDA 뿐만 아니라 OpenCL을 위한
3rd party 라이브러리를 지원하고 있다
현재 2.4.9까지 release 되어 있으며 3.0은 alpha 버전이 개
발 및 테스트 중에 있다
3.0에서 가장 두드러진 특징은 OpenCL에 대한 상당한 개선
들이 이루어질 것으로 보인다
44. OpenCV OCL module
OCL 이라고 불리는 OpenCL wrapping 모듈을 통해
알고리즘을 조합
opencv / modules / ocl / src /
- opencl을 응용한 알고리즘 코드.
- 커널 연산을 위한 문맥들을 정의하고 있으며 c++ 함수로 wrapping 하였다
opencv / modules / ocl / src / opencl
- opencl kernel 코드들
45. 산술 연산
arithm_add, arithm_log, arithm_minMax, arithm_pow 등등...
색 공간 변환
convertC3C4, cvt_color 등등..
이미지 처리
imgproc_bilateral, imgproc_calcHarris, imgproc_canny, imgproc_convolve
imgproc_gftt, imgproc_histogram, imgproc_median, imgproc_resize imgproc_sobel3,
imgproc_threshold, imgproc_warpAffine 등등..
객체 검출
haarobjectdetect, haarobjectdetect_scaled2, objdetect_hog 등등..
kernel 함수로 구현된 알고리즘들
수십개의 영상처리 알고리즘이 커널로 구현되어 있다
46. OpenCV-CL 알고리즘 구현 예시
kernel
func
opencl wrapping 함수 호출
kernel
func
kernel
func
kernel
func
hog()
알고리즘 완성에 필요한 각각의 단계별 알고리즘을 kernel
로 구현
단계별 알고리즘을 wrapping한 함수들을 차례로 호출
47. 끝마치며
소모전력 당 성능 요구사항은 병렬처리와 이기종 멀티코어
프로세서의 발전을 가져옴
복잡한 플랫폼에서 task off loading과 재사용성을 모두 만
족해야 하는 소프트웨어의 개발 언어가 필요해짐
Brook, CUDA와 같은 기존의 병렬처리를 위한 기술들의 아
이디어에 영향을 받아 개방형 범용 병렬 컴퓨팅 프레임워크
가 등장
영상처리, 컴퓨터 비전 등 멀티미디어 데이터 처리를 위한
오픈 소스 라이브러리들이 OpenCL을 지원하기 시작
48. References
Khronos Association https://www.khronos.org/
Brook Language
https://graphics.stanford.edu/projects/brookgpu/lang.html
Ian Buck 블로그 http://graphics.stanford.edu/~ianbuck/
논문과 발표자료 http://graphics.stanford.edu/papers/brookgpu/
From Brook to CUDA by Ian Buck
http://www.nvidia.com/content/GTC/documents/1001_GTC09.pdf
OpenCL Programming Guide Paperback – July 23, 2011
by Aaftab Munshi, Benedict Gaster , Timothy G. Mattson, James
Fung, & 1 more (번역서 : OpenCL 프로그래밍 가이드. 이영민 역)
예제 코드 repository https://code.google.com/p/opencl-book-
samples/
OpenCV on CUDA
http://on-
demand.gputechconf.com/gtc/2013/webinar/open
cv.mp4
http://on-
demand.gputechconf.com/gtc/2013/webinar/open
cv-gtc-express-shalini-gupta.pdf
OpenCV www.opencv.org
OpenCV code repository
www.github.com/Itseez/opencv
49. 감사합니다
이 발표자료는 온라인에 공개합니다
http://sshlab.blogspot.com
http://http://www.slideshare.net/sshtel