OpenMP는 다양한 플랫폼에서 C/C++/Fortran에서 병렬처리를 손쉽게 해주는 API일종이다. 공식 홈페이지는 http://www.openmp.org이다.
뭔말인고 하니, 병렬처리 프로그래밍하려면 UNIX에서 fork/ipc나 pthread 등등 다양한 API에 대해 공부해야하고, 이것을 Windows로 옮길 경우, Win32API로 소스를 뜯어 고쳐야하는 불상사가 있었다. 이걸 해결하고자 OpenMP 표준을 지키는 컴파일러에서 간단하게 thread를 생성, 운용할 수 있도록 통합한 API이다. 게다가 잘만 운용하면 기존 소스를 거의 고칠 필요가 없다는 것! OpenMP는 현재 2.5(Draft는 3.0)까지 나왔으며, GCC에서 지원하는 것도 2.5까지다. 컴파일할 때 -fopenmp를 해주면 "#pragma omp" 구문을 알아서 "omp_*" 함수로 변환해준다. 아래는 간단한 예제이며, 돌려본 결과를 미리 이야기 하자면, 66.7% 이득을 봤다. 나름 쓸모 있는 녀석이긴 하지만, 제어할 수 있는 부분이 너무 적어서 과연 과학적 연산을 제외하고 일반적인 상품(게임 클라이언트)에 쓸모가 있을런지는 모르겠다.
테스트 환경
빌드 파일(CMakeList.txt)
뭔말인고 하니, 병렬처리 프로그래밍하려면 UNIX에서 fork/ipc나 pthread 등등 다양한 API에 대해 공부해야하고, 이것을 Windows로 옮길 경우, Win32API로 소스를 뜯어 고쳐야하는 불상사가 있었다. 이걸 해결하고자 OpenMP 표준을 지키는 컴파일러에서 간단하게 thread를 생성, 운용할 수 있도록 통합한 API이다. 게다가 잘만 운용하면 기존 소스를 거의 고칠 필요가 없다는 것! OpenMP는 현재 2.5(Draft는 3.0)까지 나왔으며, GCC에서 지원하는 것도 2.5까지다. 컴파일할 때 -fopenmp를 해주면 "#pragma omp" 구문을 알아서 "omp_*" 함수로 변환해준다. 아래는 간단한 예제이며, 돌려본 결과를 미리 이야기 하자면, 66.7% 이득을 봤다. 나름 쓸모 있는 녀석이긴 하지만, 제어할 수 있는 부분이 너무 적어서 과연 과학적 연산을 제외하고 일반적인 상품(게임 클라이언트)에 쓸모가 있을런지는 모르겠다.
테스트 환경
Linux 2.6.23
AMD Athlon 64 X2 Dual Core 3800+
RAM 2G
GCC 4.1.2
GLIBC 2.7
CMAKE 2.4
먼저 소스 파일(openmp.c)#include <pthread.h> #include <sys/time.h> #include <omp.h> #include <stdio.h> #define __restrict__ restrict static const size_t gTestCount = 10000000; static const size_t gArraySize = 32*32; long long getTimestamp(void) { static __thread struct timeval tv; gettimeofday(&tv, NULL); return 1000000LL * tv.tv_sec + tv.tv_usec; } static inline void clean(double* restrict a, double* restrict b) { static __thread size_t i = 0; while ( i < gArraySize ) { a[i] = i; b[i] = -i; ++i; } } static inline void alu(double* restrict a, const double* restrict b) { static __thread size_t i = 0; while ( i < gArraySize ) { a[i] = a[i]*b[i]; ++i; } } int main(int argc,char* argv[]) { double a[gArraySize], b[gArraySize]; size_t c = 0; long long t1, t2, diff; clean(a,b); t1 = getTimestamp(); for ( c = 0; c < gTestCount; c++ ) { alu(a,b); } t2 = getTimestamp(); diff = t2-t1; printf("Serial: %lld\n", diff); clean(a,b); omp_set_num_threads(4); t1 = getTimestamp(); # pragma omp parallel for for ( c = 0; c < gTestCount; c++ ) { alu(a,b); } t2 = getTimestamp(); diff = t2-t1; printf("Parallel: %lld\n", diff); return 0; }
빌드 파일(CMakeList.txt)
add_definitions(-DNDEBUG -D_REENTRANT)
add_executable(openmp openmp.c)
target_link_libraries(openmp pthread)
set_target_properties(openmp
PROPERTIES
LINK_FLAGS "${CMAKE_LINK_FLAGS} -fopenmp -Wall -g -O3"
COMPILE_FLAGS "${CMAKE_COMPILE_FLAGS} -std=c99 -fopenmp -O3 -ftree-vectorize")
실행 결과
$ cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/daldev/purewell/tmp/openmp
$ make
[100%] Building C object CMakeFiles/openmp.dir/openmp.o
/home/daldev/purewell/tmp/openmp/openmp.c: In function ‘main’:
/home/daldev/purewell/tmp/openmp/openmp.c:68: warning: iteration variable ‘c’ is unsigned
Linking C executable openmp
[100%] Built target openmp
$ ./openmp
Serial: 30121
Parallel: 10328
Powered by ScribeFire.
댓글
댓글 쓰기