OpenMP Parallel Programming (1)
OpenMP?
구성요소
- Compiler Directives
- Runtime routines
- Environment variables
structure block
#pragma omp //컴파일러 지시자
{
/*structure block*/
}
위에서 아래로 순차적으로 진행되며,
abort(), exit()을 통해서 빠져나올 수 있음
OMP 헤더파일
#include <omp.h>
컴파일 및 실행
cywgin64 터미널에서 실행한다.
설치 방법은 별도 링크에서 확인
gcc -o filename filename.c -fopenmp
./filename.exe
옵션 -fopenmp
를 붙여주는 것이 중요하다.
Thread 관련 함수
omp_set_num_thread(n);
thread 개수 지정
omp_get_thread_num();
현재 쓰레드 번호 반환
omp_get_num_threads();
설정된 전체 쓰레드 개수 반환
Parallel
Parallel Region
#pragma omp parallel //컴파일러 지시자
{
/* code executed by each thread */
}
thread 개수만큼 fork
되고 각 thread가 코드를 동시에 수행하다가 join
하며 마무리된다.
Private Variables
pragma 밖에 선언된 변수는 모든 thread에서 공유될 수 있다.
이때 지시자에서 private으로 선언하면 각 thread로 공유(복사)되지 않는다.
#pragma omp parallel private(id)
{
id = omp_get_thread_num();
printf("My thread num = %d\n", id);
}
Master Region
오로지 하나의 thread만 실행해야 하는 코드가 있을 때 유용하다.
#pragma omp parallel
{
#pragma omp master
{
int k = omp_get_thread_num();
printf("My thread num = %d\n", k);
}
}
Barrier
Thread 팀의 모든 Thread가 동기화 된다. 이 지점에서 다른 Thread가 종료되길 기다린다. 기다리고 싶지 않다면 nowait 지시문을 추가해준다.
Loop Parallel
index를 직접 지정해주는 pthread와 달리 openmp는 index를 알아서 핸들링해준다.
#pragma omp parallel for
{
for(int i=0; i<n; i++)
c[i] = a[i];
}
for문에서 인덱스를 선언해주거나 private 변수를 만들 필요가 없다.
Scheduling of Loop
앞서 언급한 것처럼 index를 알아서 핸들링해주지만, 각 thread가 어떤 값을 가지는지 정확히 하려면 스케쥴링이 필요하다.
#pragma omp parallel for schedule(mode, chunksize)
chunksize
는 각 thread가 하는 최소한 작업양을 의미한다.
openmp에서는 5가지 스케줄링 모드를 지원한다.
1. static
2. dynamic
3. guided
4. auto
5. runtime
static
chunksize를 round-robin
방식으로 우선순위를 두지 않고, thread를 0부터 n까지 순차적으로 할당한다.
별도로 chunksize를 지정하지 않는다면 n 길이의 loop와 p개의 thread가 있을 때, 각 thread는 n/p 만큼의 chunksize 작업을 수행한다.
- 코어에 한 프로그램만 돌아갈 때
- 반복자(iteration)가 상수일 때
- loop limit이 알려져 있을 때
사용하면 가장 좋은 방식이다.
serial하게 수행되는 것이 아니라 concurrent하게 수행된다.
#include <stdio.h>
#include <omp.h>
#define WORKSIZE 40
#define NTHREADS 4
int main(int argc, char *argv[])
{
int data[NTHREADS][WORKSIZE];
for(int i=0; i<WORKSIZE; i++){
for(int j=0; j<NTHREADS; j++){
data[j][i] = 0;
}
}
omp_set_num_threads(NTHREADS);
#pragma omp parallel
{
#pragma omp for schedule(static, 4)
for(int i=0; i<WORKSIZE; i++){
data[omp_get_thread_num()][i] = i;
}
}
for(int i=0; i<WORKSIZE; i++){
printf("%d\t%d\t%d\t%d\n", data[0][i], data[1][i], data[2][i], data[3][i]);
return 0;
}
위 코드를 thread 4개로 돌렸다면,
thread0: 0, 1, 2, 3
thread1: 4, 5, 6, 7
thread2: 8, 9, 10, 11
thread3: 12, 13, 14, 15
thread0: 16, 17, 18, 19
...
와 같이 돌아갈 것이다.
만약 chunksize를 따로 지정해주지 않았다면 WORKSIZE 40을 THREAD 개수 4로 나눈 10개 단위로 THREAD마다 할당해 작업했을 것이다.
dynamic
chunk
의 값에 따라 크기가 제어되며 사이즈는 고정된다. static이 모든 thread를 순차적으로 사용했다면, dynamic에서는 사용 가능한 thread에 동적으로 작업으로 할당한다.
guided
dynamic과 유사하지만, 작업의 크기가 계속 줄어드는 방식이다. minimum size를 지정할 수 있다.
WORKSIZE가 40이고 minimum size가 4라면, 10개 - 8개 - 8개 - 6개 - 4개 - 4개 처럼 점점 작업 크기가 작아질 것이다.
runtime
환경 변수에 모드를 지정해주는 방식이다. 이후 실행되는 파일은 환경 변수에 지정된 방식을 따른다.
$set env OMP_SCHEDULE [mode]
auto
위의 여러 방식 중 상황에 맞는 가장 적합한 방식을 알아서 정해서 실행해준다.
참고자료
https://yechan821.tistory.com/9
http://egloos.zum.com/himskim/v/3266925
http://egloos.zum.com/himskim/v/3273089
https://hpac.cs.umu.se/teaching/pp-18/
https://throwexception.tistory.com/660
Author And Source
이 문제에 관하여(OpenMP Parallel Programming (1)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@bae12/OpenMP-Parallel-Programming저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)