기본 콘텐츠로 건너뛰기

OpenMP

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% 이득을 봤다. 나름 쓸모 있는 녀석이긴 하지만, 제어할 수 있는 부분이 너무 적어서 과연 과학적 연산을 제외하고 일반적인 상품(게임 클라이언트)에 쓸모가 있을런지는 모르겠다.

테스트 환경
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.

댓글

이 블로그의 인기 게시물

설치한 패키지에서 RPM 추출하기

오래된 패키지를 관리할 저장소가 없어졌고, 기존 패키지로 다른 서버를 세팅해야할 일이 생겼다면 RPM의 리패키지 기능을 이용해보자. $ rpm -e --repackage [PACKAGE_NAME] 위와 같이 리패키지하면, /var/spool/repackage/ 에 생성한 RPM파일이 있다. :-)

Winget 해시 무시하기

가끔씩 Winget 에서 패키지를 다운로드 했을 때, "설치 관리자 해시가 일치하지 않습니다." 오류가 뜰 때가 있다. 보안 이슈가 있지만, 그냥 무시하고 싶을 때, 아래 순서로 무시해준다. 관리자 권한 winget settings --enable InstallerHashOverride 설치 winget install --ignore-security-hash --id NirSoft.NirCmd