OpenMP
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
OpenMP는 공유 메모리 다중 프로세서 환경에서 병렬 프로그래밍을 지원하는 API(Application Programming Interface)이다. 1997년에 처음 발표되었으며, C, C++, Fortran 등 다양한 프로그래밍 언어를 지원한다. OpenMP는 컴파일러 지시어를 사용하여 병렬 처리를 구현하며, 스레드 생성, 작업 분담, 데이터 환경 관리, 동기화, 런타임 루틴 및 환경 변수 등의 기능을 제공한다. OpenMP는 이식성이 높고, 점진적인 병렬화를 통해 코드 변경을 최소화하며, 다양한 컴파일러에서 지원된다는 장점이 있다. 단점으로는 디버깅의 어려움, 공유 메모리 환경에 대한 의존성, 그리고 특정 연산을 지원하지 않는다는 점 등이 있다. OpenMP는 여러 버전으로 발전해 왔으며, 최신 버전은 5.2이다.
더 읽어볼만한 페이지
- 포트란 - 존 배커스
존 배커스는 FORTRAN 프로그래밍 언어 설계 및 개발, ALGOL 60 개발 참여 및 바커스-나우르 표기법 고안 등 컴퓨터 과학에 기여한 미국의 과학자이다. - 포트란 - OpenACC
OpenACC는 지시어를 사용하여 병렬 프로그래밍을 수행하는 방법으로, OpenMP와 유사하게 작동하며 런타임 라이브러리를 포함하고, `#pragma acc parallel`, `#pragma acc kernels`, `#pragma acc data`, `#pragma acc loop` 등의 주요 지시어를 통해 하드웨어 가속을 제어한다. - C 프로그래밍 언어 계열 - C (프로그래밍 언어)
C는 하드웨어 제어와 이식성이 뛰어난 고급 절차적 프로그래밍 언어로서, 다양한 분야에서 사용되며 후속 언어에 영향을 주었고, 성능과 효율성이 높지만 안전성 문제 개선이 필요한 언어이다. - C 프로그래밍 언어 계열 - 펄
펄은 래리 월이 개발한 텍스트 조작에 강점을 가진 다목적 프로그래밍 언어이며, 1987년 펄 1.0이 처음 공개된 이후 여러 버전 업데이트를 거쳐 객체 지향 프로그래밍과 유니코드 지원 기능을 추가했고, 현재 펄 5가 널리 사용되며 CPAN을 통해 방대한 모듈 생태계를 제공한다. - 병렬 컴퓨팅 - 슈퍼컴퓨터
슈퍼컴퓨터는 일반 컴퓨터보다 훨씬 높은 성능을 가진 컴퓨터로, 복잡한 계산과 시뮬레이션을 수행하며, 프로세서, 메모리, 스토리지, 네트워크 등으로 구성되어 병렬 처리를 통해 높은 성능을 구현하고, 군사, 기상 예측, 과학 기술 분야, 인공지능 등 다양한 분야에서 활용되고 있다. - 병렬 컴퓨팅 - 컴퓨터 클러스터
컴퓨터 클러스터는 여러 대의 상용 컴퓨터를 고속 네트워크로 연결하여 고성능 컴퓨팅 시스템을 구축하는 방식으로, 슈퍼컴퓨터를 포함한 다양한 분야에서 높은 가용성과 확장성을 제공하며, 클러스터 미들웨어를 통해 시스템 관리, 부하 분산, 통신 방식, 데이터 공유 등을 지원하고 노드 장애 관리를 위한 펜싱 기술을 활용한다.
| OpenMP - [IT 관련 정보]에 관한 문서 | |
|---|---|
| 기본 정보 | |
![]() | |
| 장르 | C, C++, 그리고 Fortran 확장; API |
| 라이선스 | 다양함 |
| 웹사이트 | OpenMP 공식 웹사이트 |
| 개발 | |
| 개발자 | OpenMP 아키텍처 검토 위원회 |
| 최신 버전 | 6.0 |
| 최신 릴리스 날짜 | 2024년 11월 |
| 운영 체제 | 크로스 플랫폼 |
| 플랫폼 | 크로스 플랫폼 |
2. 역사
OpenMP 아키텍처 리뷰 보드(ARB)는 1997년 10월 최초의 API 규격인 포트란 1.0용 OpenMP를 발표했다.[74] 1998년 10월에는 C/C++용 OpenMP가 공개되었고,[74] 2000년 11월에는 포트란 버전 2.0,[74] 2002년 3월에는 C/C++ 규격 2.0 버전이 출시되었다.[74] 2005년 5월 발표된 버전 2.5부터는 C/C++/포트란 규격이 통합되었다.[74]
OpenMP의 핵심 요소는 스레드 생성, 작업 분담(작업 공유), 데이터 환경 관리, 스레드 동기화, 사용자 수준 런타임 루틴 및 환경 변수를 위한 구성 요소이다.
OpenMP는 여러 상용 컴파일러에서 구현되었다. 예를 들어, GNU 컴파일러 모음(GCC), Visual C++, 인텔 병렬 스튜디오(Intel Parallel Studio), 오라클 솔라리스 스튜디오(Oracle Solaris Studio) 컴파일러, 더 포틀랜드 그룹(The Portland Group) 컴파일러 등에서 OpenMP를 지원한다.[23] GCC는 버전 4.2부터, Visual C++는 2005년부터 OpenMP를 지원하고 있다.[20][21][22]
버전 2.0까지 OpenMP는 주로 수치 프로그래밍에서 발생하는 것처럼 루프의 반복 횟수를 입력 시점에 알 수 있는 매우 규칙적인 루프를 병렬화하는 방법을 지정했다. 그러나 이는 제한 사항으로 인식되었고, 다양한 태스크 병렬 확장 기능이 구현에 추가되었다. 2005년에는 태스크 병렬성을 표준화하기 위한 노력이 시작되어 2007년에 제안서가 발표되었는데, 이는 Cilk, X10, Chapel의 태스크 병렬 기능에서 영감을 받았다.
2008년 5월 출시된 버전 3.0에는 ''태스크'' 개념과 ''태스크'' 구문이 포함되어 있어, OpenMP 2.0의 대부분을 구성했던 병렬 루프 구문을 넘어 OpenMP의 범위를 크게 확장했다.[74]
2013년 7월 출시된 버전 4.0은 하드웨어 가속 지원, 원자성, 오류 처리, 스레드 선호도, 태스크 확장, 사용자 정의 축소, SIMD 지원, Fortran 2003 지원과 같은 기능을 추가하거나 개선했다.[74]
2015년 11월에는 버전 4.5,[74] 2018년 11월에는 버전 5.0이 발표되었다.[74] 2019년 기준으로 버전 2.5 이하는 레거시 사양으로 취급되고 있다. 2021년 11월 현재 최신 버전인 5.2가 출시되었다. 2024년 11월에는 버전 6.0이 출시될 예정이다.
모든 컴파일러 및 운영 체제가 최신 버전의 모든 기능 세트를 지원하는 것은 아니다.
3. 설계
OpenMP는 멀티스레딩 구현체로, ''기본'' 스레드가 지정된 수의 ''하위'' 스레드를 생성(fork)하고 시스템이 작업을 스레드 간에 분할하는 방식을 사용한다. 그러면 스레드는 동시적으로 실행되며, 런타임 환경이 스레드를 서로 다른 프로세서에 할당한다.
병렬로 실행될 코드 섹션은 컴파일러 지시어로 표시되어, 해당 섹션이 실행되기 전에 스레드가 형성되도록 한다.[3] 각 스레드는 `omp_get_thread_num()` 함수를 사용하여 얻을 수 있는 고유 ''ID''를 가진다. 스레드 ID는 정수이며, 기본 스레드의 ID는 ''0''이다. 병렬화된 코드가 실행된 후, 스레드는 다시 기본 스레드에 ''join''되어 프로그램의 끝까지 계속 진행된다.
기본적으로 각 스레드는 병렬화된 코드 섹션을 독립적으로 실행한다. ''작업 공유 구성''을 사용하면 각 스레드가 할당된 코드 부분을 실행하도록 스레드 간에 작업을 분할할 수 있다. 이 방식으로 OpenMP를 사용하여 작업 병렬 처리와 데이터 병렬 처리를 모두 수행할 수 있다.
런타임 환경은 사용량, 머신 부하 및 기타 요인에 따라 스레드를 프로세서에 할당한다. 런타임 환경은 환경 변수를 기반으로 스레드 수를 할당할 수 있으며, 코드는 함수를 사용하여 스레드 수를 할당할 수도 있다. OpenMP 함수는 C/C++에서 `
4. 주요 요소
C/C++에서 OpenMP는 #pragma를 사용한다. 다음은 C 언어에서 for 루프를 병렬 처리하는 예시이다.
```c
int main(int argc, char *argv[])
{
int i;
#pragma omp parallel for
for (i = 0; i < 10000; ++i)
{
/* (병렬 처리하고 싶은 프로그램) */
}
return 0;
}
```
OpenMP는 루프의 반복 처리를 자동으로 여러 스레드로 분할하여 병렬 처리한다. 예를 들어 4개의 스레드를 사용하여 처리를 분할하는 경우, 위의 예시에서는 인덱스 [0, 2499], [2500, 4999], [5000, 7499], [7500, 9999]의 각 범위를 각각의 스레드에 분담시키는 식이다. 실제로 몇 개의 스레드를 시작할 것인지, 그리고 각 스레드에 어떻게 처리를 분배할 것인지는 OpenMP 처리계(컴파일러) 및 프로그램 실행 환경 등의 조건에 따라 달라진다[57]。
다음은 구분구적법을 사용한 원주율 π의 수치 계산을 OpenMP 병렬 리덕션을 사용하여 수행하는 C++ 코드 예시이다.
```cpp
#include
#include
#include
#include
#include
const double D_PI = 3.1415926535897932384626433832795;
// 구분구적법으로 π의 근사값을 구한다.
// 1 / (x^2 + 1)을 구간 [0, 1]에서 적분하면 π/4가 된다는 정적분을 이용한다.
int main()
{
const int DivNum = 1000 * 1000 * 1000;
const double delta = 1.0 / DivNum;
std::cout << "OpenMP max threads count = " << omp_get_max_threads() << std::endl;
const auto startTime = std::chrono::system_clock::now();
double sum = 0;
#pragma omp parallel for reduction(+ : sum)
for (int i = 0; i < DivNum; ++i)
{
const double x = (delta * i);
const double area = delta * 1.0 / (x * x + 1.0);
sum += area;
}
const double pi = sum * 4.0;
const auto endTime = std::chrono::system_clock::now();
std::cout << std::setprecision(15) << "PI ~= " << pi << std::endl;
std::cout << "Error [%] = " << (100.0 * std::fabs(D_PI - pi) / D_PI) << std::endl;
std::cout << "Elapsed time [ms] = " << std::chrono::duration_cast
return 0;
}
```
`#pragma omp parallel for`는 병렬 루프의 지시문이다. 바로 뒤에 오는 `reduction`은 병렬 처리의 동작을 조정할 수 있다. 여기서는 총합을 저장하는 스레드 공유 변수 `sum`에 대한 갱신 연산자(덧셈)를 지정하고 있다.
OpenMP 컴파일 옵션의 유무를 전환하거나, OpenMP 지시문을 주석 처리/주석 해제한 후 컴파일 및 실행함으로써, 멀티 스레드 버전과 싱글 스레드 버전의 속도 성능 비교를 간단하게 수행할 수 있다는 것이 OpenMP 프로그램의 특징이다.
4. 1. 스레드 생성
`omp parallel` 지시어는 구문 내의 작업을 병렬로 수행하기 위해 추가 스레드를 생성하는 데 사용된다. 원래 스레드는 스레드 ID가 0인 "마스터 스레드"로 지정된다.[17]
다음은 C 프로그램 예시이다. 여러 스레드를 사용하여 "Hello, world."를 표시한다.
```c
#include
#include
int main(void)
{
#pragma omp parallel
printf("Hello, world.\n");
return 0;
}
```
GCC를 사용하여 컴파일하려면 `-fopenmp` 플래그를 사용한다.
```bash
$ gcc -fopenmp hello.c -o hello
```
두 개의 코어, 즉 두 개의 스레드가 있는 컴퓨터의 출력은 다음과 같을 수 있다.
```bash
Hello, world.
Hello, world.
```
하지만 두 스레드가 표준 출력을 공유하여 발생한 경합 상태로 인해 출력이 엉망이 될 수도 있다.
```bash
Hello, wHello, woorld.
rld.
```
`printf`가 원자적인지 여부는 기본 구현에 따라 다르다.[17]
4. 2. 작업 공유 구문
OpenMP의 핵심 요소는 스레드 생성, 작업 분담(작업 공유), 데이터 환경 관리, 스레드 동기화, 사용자 수준 런타임 루틴 및 환경 변수를 위한 구성 요소이다.
독립적인 작업을 하나 또는 모든 스레드에 할당하는 방법을 지정하는 데 사용되는 작업 공유 구문은 다음과 같다.
다음은 각 스레드를 사용하여 작업의 일부를 수행하여 대형 배열의 값을 병렬로 초기화하는 C 코드 예시이다.
```c
int main(int argc, char **argv)
{
int a[100000];
#pragma omp parallel for
for (int i = 0; i < 100000; i++) {
a[i] = 2 * i;
}
return 0;
}
```
위 예시에서 `#pragma omp parallel for` 지시어는 OpenMP 시스템에 작업을 작업 스레드 간에 분할하도록 지시한다. 각 스레드는 변수의 고유하고 개인적인 버전을 받는다.[19] 예를 들어, 두 개의 작업자 스레드가 있는 경우, 한 스레드는 0에서 49999까지 실행되는 `i`의 버전을 받고, 두 번째 스레드는 50000에서 99999까지 실행되는 버전을 받는다.
OpenMP는 루프의 반복 처리를 자동으로 여러 스레드로 분할하여 병렬 처리할 수 있도록 한다. 예를 들어 4개의 스레드를 사용하여 처리를 분할하는 경우, 위의 예시에서는 인덱스 [0, 2499], [2500, 4999], [5000, 7499], [7500, 9999]의 각 범위를 각각의 스레드에 분담시키는 식이다. 실제로 몇 개의 스레드를 시작할 것인지, 그리고 각 스레드에 어떻게 처리를 분배할 것인지는 OpenMP 처리계(컴파일러) 및 프로그램 실행 환경 등의 조건에 따라 달라진다.[57]
4. 3. 변형 지시문 (Variant directives)
변형 지시어는 프로그래머가 성능 이식성을 개선할 수 있도록 OpenMP 5.0 사양에 도입된 주요 기능 중 하나이다.[1] 이를 통해 컴파일 시 OpenMP 프라그마와 사용자 코드를 조정할 수 있다.[1] 이 사양은 활성 OpenMP 구문, 실행 장치 및 구현에서 제공하는 기능을 설명하는 특성, 특성 및 사용자 정의 조건을 기반으로 하는 컨텍스트 선택기, 사용자가 변형 지시어로 동일한 코드 영역을 프로그래밍할 수 있도록 하는 ''메타지시어'' 및 ''선언 변형 지시어'' 지시어를 정의한다.[1]
두 변형 지시어가 변형을 선택하기 위해 제공하는 메커니즘은 C/C++ 전처리보다 사용하기 더 편리하다.[1] 이는 OpenMP에서 변형 선택을 직접 지원하고 OpenMP 컴파일러가 변형 및 컨텍스트에서 최종 지시어를 분석하고 결정할 수 있도록 하기 때문이다.[1]
```c
// 전처리 지시어를 사용한 코드 적응
int v1[N], v2[N], v3[N];
#if defined(nvptx)
#pragma omp target teams distribute parallel for map(to:v1,v2) map(from:v3)
for (int i= 0; i< N; i++)
v3[i] = v1[i] * v2[i];
#else
#pragma omp target parallel for map(to:v1,v2) map(from:v3)
for (int i= 0; i< N; i++)
v3[i] = v1[i] * v2[i];
#endif
// OpenMP 5.0에서 메타지시어를 사용한 코드 적응
int v1[N], v2[N], v3[N];
#pragma omp target map(to:v1,v2) map(from:v3)
#pragma omp metadirective \
when(device={arch(nvptx)}: target teams distribute parallel for)\
default(target parallel for)
for (int i= 0; i< N; i++)
v3[i] = v1[i] * v2[i];
4. 4. 절 (Clauses)
OpenMP는 공유 메모리 프로그래밍 모델이므로, 대부분의 변수는 기본적으로 모든 스레드에 보인다. OpenMP는 데이터 공유 속성 절, 동기화 절, 스케줄링 절 등 다양한 절을 통해 데이터 환경 및 스레드 동작을 제어할 수 있다.4. 4. 1. 데이터 공유 속성 절
OpenMP는 공유 메모리 프로그래밍 모델을 사용하므로, 코드 내 대부분의 변수는 기본적으로 모든 스레드에서 접근할 수 있다. 그러나 경합 조건을 방지하기 위해 개인 변수가 필요할 때도 있고, 순차적 부분과 병렬 영역 간에 값을 전달해야 할 때도 있다. 이를 위해 OpenMP는 ''데이터 공유 속성 절''을 제공한다.4. 4. 2. 동기화 절
4. 4. 3. 스케줄링 절
`schedule (type, chunk)`는 작업 공유 구조가 do-loop 또는 for-loop인 경우에 유용하며, 작업 공유 구조의 반복을 스레드에 할당하는 방법을 정의한다.[19] 스케줄링 유형은 다음과 같다.4. 4. 4. 기타 절
OpenMP는 스레드 생성, 작업 분담, 데이터 환경 관리, 스레드 동기화, 사용자 수준 런타임 루틴 및 환경 변수를 위한 구성 요소를 제공한다. 이 중 기타 절에 해당하는 내용은 다음과 같다.4. 5. 사용자 수준 런타임 루틴
스레드 수를 수정/확인하고, 실행 컨텍스트가 병렬 영역에 있는지 감지하며, 현재 시스템의 프로세서 수를 확인하고, 락을 설정/해제하며, 타이밍 함수 등을 사용하는 데 사용된다.[3] OpenMP 함수는 C/C++에서 `omp.h`로 레이블이 지정된 헤더 파일에 포함되어 있다.
4. 6. 환경 변수
OpenMP 애플리케이션의 실행 특징은 환경 변수를 통해 변경할 수 있다. 루프 반복 스케줄링, 기본 스레드 수 등을 제어할 수 있으며, 예를 들어 `OMP_NUM_THREADS` 환경 변수는 애플리케이션에서 사용할 스레드 수를 지정한다.[3]
5. 구현
OpenMP 3.0, 3.1, 4.0, 4.5, 5.0을 지원하는 컴파일러 목록은 다음과 같다.버전 컴파일러 3.0 3.1 4.0 4.5 5.0 (부분 지원)
다음은 OpenMP 지시문을 지원하는 자동 병렬화 컴파일러이다.
OpenMP를 지원하는 프로파일러 및 디버거는 다음과 같다.
구체적인 지원 현황은 다음과 같다.
6. 장단점
OpenMP는 장점과 단점을 모두 가지고 있다.
'''장점'''
OpenMP를 사용하면 이식성이 좋은 멀티스레딩 코드를 쉽게 작성할 수 있다. MPI와 비교했을 때, 공유 메모리 시스템에서 비슷한 수준의 확장성을 제공하며, 점진적인 병렬화가 가능하다는 장점이 있다. 또한, 직렬 및 병렬 응용 프로그램에 대해 통합된 코드를 작성할 수 있고, 코드 수정량이 적어 버그 발생 가능성이 낮다. 거친 입자성 및 세밀한 입자성 병렬 처리를 모두 지원하며, GPGPU[41], FPGA와 같은 다양한 가속기에서 사용할 수 있어 활용성이 높다.
'''단점'''
OpenMP는 디버깅이 어려운 동기화 버그나 경쟁 조건을 유발할 수 있다. 또한, 현재는 공유 메모리 다중 프로세서 플랫폼에서만 효율적으로 작동하며, OpenMP를 지원하는 컴파일러가 반드시 필요하다. 메모리 아키텍처에 따라 확장성이 제한될 수 있으며, 비교-교환을 지원하지 않고, 신뢰성 있는 오류 처리가 부족하다는 단점도 있다. 스레드-프로세서 매핑을 정밀하게 제어하기 어렵고, 허위 공유 코드를 작성할 위험도 존재한다.[44]
6. 1. 장점
- 이식 가능한 멀티스레딩 코드를 작성할 수 있다. (C/C++ 등에서 멀티스레딩을 사용하려면 플랫폼별 기본 요소를 호출해야 한다.)
- 단순하며, MPI처럼 메시지 전달을 처리할 필요가 없다.
- 데이터 레이아웃 및 분할은 지시문에 의해 자동으로 처리된다.
- 공유 메모리 시스템에서 MPI와 비슷한 확장성을 가진다.[39]
- 점진적 병렬화가 가능하다. (한 번에 프로그램의 한 부분에서 작업할 수 있으며, 코드에 큰 변경이 필요하지 않다.)
- 직렬 및 병렬 응용 프로그램을 위한 통합 코드를 작성할 수 있다. (순차 컴파일러를 사용하면 OpenMP 구문이 주석으로 처리된다.)
- 일반적으로 OpenMP로 병렬화할 때 원래 (직렬) 코드 문을 수정할 필요가 거의 없다. 이는 실수로 버그가 발생할 가능성을 줄인다.
- 거친 입자성 및 세밀한 입자성 병렬 처리가 모두 가능하다.
- SPMD 계산 모드를 따르지 않는 불규칙한 다중 물리 응용 프로그램(예: 긴밀하게 결합된 유체-입자 시스템)에서 OpenMP의 유연성은 MPI보다 큰 성능 이점을 가질 수 있다.[39][40]
- GPGPU[41] 및 FPGA와 같은 다양한 가속기에서 사용할 수 있다.
6. 2. 단점
7. 성능 예측
OpenMP를 사용하여 프로그램을 병렬화하여 ''N'' 프로세서 플랫폼에서 실행할 때, ''N''배의 속도 향상을 기대하기는 어렵다. 이는 다음과 같은 이유 때문이다.
- 종속성이 존재하는 경우, 프로세스는 종속된 데이터가 계산될 때까지 대기해야 한다.
- 여러 프로세스가 비병렬 증명 리소스(예: 쓰기 파일)를 공유하는 경우, 해당 요청은 순차적으로 실행된다. 따라서 각 스레드는 다른 스레드가 리소스를 해제할 때까지 대기해야 한다.
- 프로그램의 많은 부분이 OpenMP에 의해 병렬화되지 않을 수 있으며, 이는 암달의 법칙에 따라 속도 향상의 이론적 상한선이 제한됨을 의미한다.
- 대칭형 멀티프로세싱(SMP)에서 N개의 프로세서는 N배의 계산 능력을 가질 수 있지만, 메모리 대역폭은 일반적으로 N배로 확장되지 않는다. 종종 원래 메모리 경로는 여러 프로세서에 의해 공유되며, 공유 메모리 대역폭을 놓고 경쟁할 때 성능 저하가 관찰될 수 있다.
- 병렬 컴퓨팅에서 최종 속도 향상에 영향을 미치는 부하 분산, 동기화 오버헤드 등 다른 많은 일반적인 문제도 OpenMP에 적용된다.
- OpenMP를 호출할 때 컴파일러 최적화가 효과적이지 않을 수 있다. 이는 일반적으로 단일 스레드 OpenMP 프로그램이 OpenMP 플래그 없이 컴파일된 동일한 코드(완전히 직렬화됨)보다 느리게 실행되는 결과를 초래할 수 있다.[3]
8. 스레드 선호도 (Thread affinity)
일부 공급업체는 OpenMP 스레드를 특정 프로세서 코어와 연결하기 위해 프로세서 선호도를 설정하는 것을 권장한다.[45][46][47] 이렇게 하면 코어 간의 스레드 마이그레이션 및 컨텍스트 전환 비용을 최소화할 수 있다. 또한 데이터 지역성을 개선하고 코어(또는 프로세서) 간의 캐시 일관성 트래픽을 줄여준다.
9. 벤치마크
OpenMP의 사용을 시연하고, 성능을 테스트하며, 정확성을 평가하기 위해 다양한 벤치마크가 개발되었다.
성능 벤치마크는 다음과 같다.
- NAS 병렬 벤치마크
- 바르셀로나 OpenMP 태스크 스위트(Barcelona OpenMP Task Suite): OpenMP 태스킹 구현을 테스트할 수 있는 애플리케이션 모음
- SPEC 시리즈
- * SPEC OMP 2012
- * SPEC ACCEL 벤치마크 스위트: OpenMP 4 타겟 오프로딩 API 테스트
- * SPEChpc 2002 벤치마크
- CORAL 벤치마크
- 엑사스케일 프록시 애플리케이션
- Rodinia: 가속기에 초점
- 문제 기반 벤치마크 스위트
정확성 벤치마크는 다음과 같다.
- OpenMP 검증 스위트
- OpenMP 검증 및 확인 테스트 스위트
- DataRaceBench: OpenMP 데이터 레이스 감지 도구의 효과를 체계적이고 정량적으로 평가하도록 설계된 벤치마크 스위트
- AutoParBench: OpenMP 지시문을 자동으로 삽입할 수 있는 컴파일러 및 도구를 평가하는 벤치마크 스위트
10. 예제 프로그램
OpenMP를 사용한 병렬 프로그래밍 예시를 몇 가지 소개한다.
하위 섹션에 OpenMP를 활용한 C, C++, 포트란 코드 예시와 함께, for 루프 병렬 처리 및 구분구적법을 사용한 원주율 π 계산 예시가 제시되어 있다. 이 예시들은 OpenMP를 사용하여 어떻게 병렬 처리를 구현하고 성능 향상을 얻을 수 있는지 보여준다.
10. 1. Hello World
`omp parallel` 지시어는 구문 내의 작업을 병렬로 수행하기 위해 추가 스레드를 생성하는 데 사용된다. 원래 스레드는 스레드 ID가 0인 "마스터 스레드"로 지정된다.[17]다음은 여러 스레드를 사용하여 "Hello, world."를 표시하는 C 프로그램 예시이다.
```c
#include
#include
int main(void)
{
#pragma omp parallel
printf("Hello, world.\n");
return 0;
}
```
GCC를 사용하여 컴파일하려면 `-fopenmp` 플래그를 사용한다.
```bash
$ gcc -fopenmp hello.c -o hello -ldl
```
두 개의 코어, 즉 두 개의 스레드가 있는 컴퓨터의 출력은 다음과 같다.
```bash
Hello, world.
Hello, world.
```
그러나 두 스레드가 표준 출력을 공유하여 발생한 경합 상태로 인해 출력이 엉망이 될 수도 있다.[18]
```bash
Hello, wHello, woorld.
rld.
10. 1. 1. C
c#include
#include
#include
int main (int argc, char *argv[]) {
int th_id, nthreads;
#pragma omp parallel private(th_id)
{
th_id = omp_get_thread_num();
printf("Hello World : 스레드 %d\n", th_id);
#pragma omp barrier
if ( th_id == 0 ) {
nthreads = omp_get_num_threads();
printf("모두 %d 개의 스레드가 있습니다\n",nthreads);
}
}
return EXIT_SUCCESS;
}
```
`omp parallel` 지시어는 구문 내의 작업을 병렬로 수행하기 위해 추가 스레드를 생성하는 데 사용된다. 원래 스레드는 스레드 ID가 0인 "마스터 스레드"로 지정된다.
다음은 C 프로그램 예시이다. 여러 스레드를 사용하여 "Hello, world."를 표시한다.
```c
#include
#include
int main(void)
{
#pragma omp parallel
printf("Hello, world.\n");
return 0;
}
```
GCC를 사용하여 컴파일하려면 `-fopenmp` 플래그를 사용한다.
```bash
$ gcc -fopenmp hello.c -o hello -ldl
```
두 개의 코어, 즉 두 개의 스레드가 있는 컴퓨터의 출력은 다음과 같다.
```bash
Hello, world.
Hello, world.
```
그러나 두 스레드가 표준 출력을 공유하여 발생한 경합 상태로 인해 출력이 엉망이 될 수도 있다.
```bash
Hello, wHello, woorld.
rld.
```
`printf`가 원자적인지 여부는 기본 구현에 따라 다르며[17] C++11의 `std::cout`과 달리 기본적으로 스레드 안전하다.[18]
10. 1. 2. C++
cpp#include
#include
#include
int main (int argc, char *argv[]) {
int th_id, nthreads;
#pragma omp parallel private(th_id)
{
th_id = omp_get_thread_num();
std::ostringstream ss;
ss << "Hello World : 스레드 " << th_id << std::endl;
std::cout << ss.str();
#pragma omp barrier
#pragma omp master
{
nthreads = omp_get_num_threads();
std::cout << "모두 " << nthreads << "개의 스레드가 있습니다" << std::endl;
}
}
return 0;
}
```
이 코드는 OpenMP를 사용하여 C++ 프로그램에서 병렬 처리를 구현하는 예제이다.
- `#include
` : OpenMP 라이브러리를 포함한다. - `#pragma omp parallel private(th_id)`: 병렬 영역을 시작하고, `th_id` 변수를 각 스레드에 대해 private으로 선언한다. 즉 각 스레드는 자신만의 `th_id`변수를 가진다.
- `th_id = omp_get_thread_num();`: 현재 스레드의 ID를 가져온다.
- `std::ostringstream`: 문자열 스트림을 사용하여 출력을 버퍼링한다.
- `ss << "Hello World : 스레드 " << th_id << std::endl;`: 각 스레드는 "Hello World : 스레드" 와 자신의 스레드 번호를 출력한다.
- `std::cout << ss.str();`: 버퍼링된 문자열을 출력한다.
- `#pragma omp barrier`: 모든 스레드가 이 지점에 도달할 때까지 기다린다.
- `#pragma omp master`: 마스터 스레드(ID가 0인 스레드)만 이 블록을 실행한다.
- `nthreads = omp_get_num_threads();`: 전체 스레드 수를 가져온다.
- `std::cout << "모두 " << nthreads << "개의 스레드가 있습니다" << std::endl;` : 마스터 스레드는 총 스레드 개수를 출력한다.
10. 1. 3. 포트란 77
fortranPROGRAM HELLO
INTEGER ID, NTHRDS
INTEGER OMP_GET_THREAD_NUM, OMP_GET_NUM_THREADS
!$OMP PARALLEL PRIVATE(ID)
ID = OMP_GET_THREAD_NUM()
PRINT *, 'HELLO WORLD : 스레드', ID
!$OMP BARRIER
IF ( ID .EQ. 0 ) THEN
NTHRDS = OMP_GET_NUM_THREADS()
PRINT *, '모두', NTHRDS, '개의 스레드가 있습니다'
END IF
!$OMP END PARALLEL
END
10. 1. 4. 자유형 포트란 90
fortranprogram hello90
use omp_lib
integer:: id, nthreads
!$omp parallel private(id)
id = omp_get_thread_num()
print *, 'Hello World : 스레드', id
!$omp barrier
if (id == 0) then
nthreads = omp_get_num_threads()
print *, '모두', nthreads, '개의 스레드가 있습니다'
end if
!$omp end parallel
end program hello90
```
다음은 변경 사항입니다.
- `write (*,*)`를 `print *`로 변경했습니다. 이는 포트란에서 콘솔 출력을 위한 더 간결한 방법입니다.
- 코드 블록을 나타내기 위해 `
` 태그 대신 위키텍스트의 일반적인 코드 블록 표현을 사용했습니다. ` `는 허용되지 않는 태그입니다.
10. 2. C 언어 for 루프 병렬 처리
다음은 C 언어에서 for 루프를 병렬 처리하는 예시이다.```c
int main(int argc, char *argv[])
{
int i;
#pragma omp parallel for
for (i = 0; i < 10000; ++i)
{
/* (병렬 처리하고 싶은 프로그램) */
}
return 0;
}
```
OpenMP는 루프의 반복 처리를 자동으로 여러 스레드로 분할하여 병렬 처리할 수 있도록 한다. 예를 들어 4개의 스레드를 사용하여 처리를 분할하는 경우, 위의 예시에서는 인덱스 [0, 2499], [2500, 4999], [5000, 7499], [7500, 9999]의 각 범위를 각각의 스레드에 분담시키는 식이다. 실제로 몇 개의 스레드를 시작할 것인지, 그리고 각 스레드에 어떻게 처리를 분배할 것인지는 OpenMP 처리계(컴파일러) 및 프로그램 실행 환경 등의 조건에 따라 달라진다.[57]
10. 3. 구분구적법을 사용한 원주율 π 계산 (C++)
다음은 구분구적법을 사용하여 원주율 π의 수치 계산을 OpenMP 병렬 리덕션을 사용하여 수행하는 C++ 코드 예시이다. 일부에 C++11의 기능이 사용되었지만, OpenMP의 지시문 자체는 언어 버전과 관계없이 C++98/C++03에서도 사용할 수 있다.[57]```cpp
#include
#include
#include
#include
#include
const double D_PI = 3.1415926535897932384626433832795;
// 구분구적법으로 π의 근사값을 구한다.
// 1 / (x^2 + 1)을 구간 [0, 1]에서 적분하면 π/4가 된다는 정적분을 이용한다.
int main()
{
const int DivNum = 1000 * 1000 * 1000;
const double delta = 1.0 / DivNum;
std::cout << "OpenMP max threads count = " << omp_get_max_threads() << std::endl;
const auto startTime = std::chrono::system_clock::now();
double sum = 0;
#pragma omp parallel for reduction(+ : sum)
for (int i = 0; i < DivNum; ++i)
{
const double x = (delta * i);
const double area = delta * 1.0 / (x * x + 1.0);
sum += area;
}
const double pi = sum * 4.0;
const auto endTime = std::chrono::system_clock::now();
std::cout << std::setprecision(15) << "PI ~= " << pi << std::endl;
std::cout << "Error [%] = " << (100.0 * std::fabs(D_PI - pi) / D_PI) << std::endl;
std::cout << "Elapsed time [ms] = " << std::chrono::duration_cast
return 0;
}
```
`#pragma omp parallel for`는 병렬 루프의 지시문이다. 바로 뒤에 오는 `reduction`은 병렬 처리의 동작을 조정할 수 있다. 여기서는 총합을 저장하는 스레드 공유 변수 `sum`에 대한 갱신 연산자(덧셈)를 지정하고 있다. 다른 스레드에서 공유 변수에 접근할 때는 상호 배제 및 원자적 연산이 필요하지만, OpenMP의 clause를 사용하면 그러한 번거로운 코드를 작성할 필요가 없어지고, 세부 사항을 처리계에 맡겨 숨길 수 있다.[57]
OpenMP 컴파일 옵션의 유무를 전환하거나, OpenMP 지시문을 주석 처리/주석 해제한 후 컴파일 및 실행함으로써, 멀티 스레드 버전과 싱글 스레드 버전의 속도 성능 비교를 간단하게 수행할 수 있다는 것이 OpenMP 프로그램의 특징이다.
11. 지원 컴파일러
- GCC: 버전 4.9에서 C/C++용 OpenMP 4.0을, 버전 4.9.1에서 Fortran용 OpenMP 4.0을 지원했다[62]。 GCC 5에서는 오프로드 기능 지원이 추가되었다. GCC 6 이후 C/C++용 OpenMP 4.5를, GCC 7 이후 Fortran용 OpenMP 4.5를 지원하고 있다. GCC 9 이후 OpenMP 5.0의 초기 지원이 시작되었다.
- Clang: 버전 3.7에서 OpenMP 3.1을 지원했다[63]。 Clang 3.7 이전에는 파생 프로젝트가 존재했다[64]。 Clang 3.9에서 오프로드 이외의 OpenMP 4.5 기능을 모두 지원했다[65]。
- Microsoft Visual C++: Visual C++ 2017 시점에서 OpenMP 2.0을 지원하고 있다[66]。 Visual C++ 2019에서는 SIMD 벡터화 기능을 실험적으로 지원한다[67][68]。
- 인텔 C++ 컴파일러: 버전 12.1에서 OpenMP 3.1을 지원하고 있다. 또한, 버전 14.0에서 OpenMP 4.0의 기능을 일부 지원하고 있다[69]。
- 인텔 포트란 컴파일러: 버전 18.0 이후 OpenMP 5.0 기능의 대부분을 지원하고 있다[70]。
12. 더 알아보기
다음은 OpenMP 관련 서적 및 자료 목록이다.
원서
- Rohit Chandra, Ramesh Menon, Leo Dagum, David Kohr, Dror Maydan, Jeff McDonald 공저: ''Parallel Programming in OpenMP'', Morgan Kaufmann, ISBN 978-1558606715 (2000년 10월).
- Barbara Chapman, Gabriele Jost, Ruud Van der Pas 공저: ''Using OpenMP: Portable Shared Memory Parallel Programming'', MIT Press, ISBN 978-0-262-53302-7 (2007년 10월).
- Ruud van der Pas, Eric Stotzer, Christian Terboven 공저: ''Using OpenMP -- The Next Step: Affinity, Accelerators, Tasking, and SIMD'', The MIT Press, ISBN 978-0262344005 (2017년 10월 27일). (OpenMP 4.5 사양 기술)
- Timothy G. Mattson, Yun (Helen) He, Alice Evelyn Konigs 공저: ''The OpenMP Common Core: Making OpenMP Simple Again'', The MIT Press, ISBN 978-0262538862 (2019년 11월 19일).
- Tom Deakin, Timothy G. Mattson 공저: ''Programming Your GPU with OpenMP: Performance Portability for GPUs'', The MIT Press, ISBN 978-0-262547536 (2023년 11월 7일).
일본 서적 등
- 우시지마 사토시 저: "OpenMP에 의한 병렬 프로그래밍과 수치 계산법", 마루젠, ISBN 978-4621077177 (2006년 5월).
- https://www.cc.u-tokyo.ac.jp/public/VOL9/special/9.pdf 쿠로다 히사야스: "C 언어에 의한 OpenMP 입문", 도쿄 대학 정보 기반 센터 슈퍼컴퓨팅 뉴스, Vol.9, No. Special Issue 1 (2008), pp.149-168
- https://www2.ccs.tsukuba.ac.jp/workshop/HPCseminar/2010/material/2010-03openmp.pdf 사토 미츠히사: "OpenMP 병렬 프로그래밍 입문", 쓰쿠바 대학 계산 과학 센터 (2010)
- 스가와라 키요후미 저: "C/C++ 프로그래머를 위한 OpenMP 병렬 프로그래밍", 제2판, 컷 시스템, ISBN 978-4-87783-223-0 (2012년 6월).
- 카타기리 타카히로 저: "병렬 프로그래밍 입문: 샘플 프로그램으로 배우는 OpenMP와 OpenACC", 도쿄 대학 출판회, ISBN 978-4130624565 (2015년 5월 29일).
- https://www.r-ccs.riken.jp/wp/wp-content/uploads/2020/09/katagiri190425.pdf 카타기리 타카히로: "OpenMP의 기초", 나고야 대학 정보 기반 센터, 계산 과학 기술 특론 A 제3회 (2017년도)
- 키타야마 히로유키 저: "OpenMP 기본과 실천 - 메니 코어 CPU 시대의 병렬 프로그래밍 수법", 컷 시스템, ISBN 978-4877834494 (2018년 10월 1일).
참조
[1]
웹사이트
About the OpenMP ARB and
http://openmp.org/wp[...]
OpenMP.org
2013-08-14
[2]
웹사이트
OpenMP Compilers & Tools
https://www.openmp.o[...]
OpenMP.org
2020-03-05
[3]
서적
Operating system concepts
Wiley
2012-12-17
[4]
Youtube
OpenMP Tutorial at Supercomputing 2008
http://openmp.org/wp[...]
[5]
Youtube
Using OpenMP – Portable Shared Memory Parallel Programming – Download Book Examples and Discuss
http://openmp.org/wp[...]
[6]
간행물
Running OpenMP applications efficiently on an everything-shared SDSM
2006-05
[7]
서적
2007 IEEE International Parallel and Distributed Processing Symposium
IEEE Press
[8]
간행물
OpenMP compiler for distributed memory architectures
2010-05
[9]
Youtube
Cluster OpenMP
https://software.int[...]
[10]
학술회의
A proposal for task parallelism in OpenMP
http://people.ac.upc[...]
[11]
웹사이트
OpenMP Application Program Interface, Version 3.0
http://www.openmp.or[...]
openmp.org
2014-02-06
[12]
학술회의
A Runtime Implementation of OpenMP Tasks
[13]
웹사이트
OpenMP 4.0 API Released
http://openmp.org/wp[...]
OpenMP.org
2013-08-14
[14]
웹사이트
OpenMP Application Program Interface, Version 4.0
http://www.openmp.or[...]
openmp.org
2014-02-06
[15]
웹사이트
OpenMP 5.2 Specification
https://www.openmp.o[...]
[16]
웹사이트
OpenMP ARB Releases OpenMP 6.0 for Easier Programming
https://www.openmp.o[...]
[17]
웹사이트
C - How to use printf() in multiple threads
https://stackoverflo[...]
[18]
웹사이트
std::cout, std::wcout - cppreference.com
https://en.cpprefere[...]
[19]
웹사이트
Tutorial – Parallel for Loops with OpenMP
http://supercomputin[...]
2009-07-14
[20]
Youtube
Visual C++ Editions, Visual Studio 2005
http://msdn2.microso[...]
[21]
Youtube
Visual C++ Editions, Visual Studio 2008
http://msdn2.microso[...]
[22]
Youtube
Visual C++ Editions, Visual Studio 2010
http://msdn2.microso[...]
[23]
웹인용
Intel addresses development life cycle with Parallel Studio
http://www.sdtimes.c[...]
SDTimes
2009-05-26
[24]
Youtube
XL C/C++ for Linux Features
http://www-01.ibm.co[...]
[25]
웹사이트
Oracle Technology Network for Java Developers | Oracle Technology Network | Oracle
http://developers.su[...]
Developers.sun.com
2013-08-14
[26]
웹사이트
openmp – GCC Wiki
https://gcc.gnu.org/[...]
Gcc.gnu.org
2013-08-14
[27]
웹사이트
Intel® C++ and Fortran Compilers now support the OpenMP* 3.1 Specification | Intel® Developer Zone
http://software.inte[...]
Software.intel.com
2013-08-14
[28]
웹사이트
IBM XL C/C++ compilers features
https://www.ibm.com/[...]
2018-12-13
[29]
웹사이트
IBM XL Fortran compilers features
http://www-01.ibm.co[...]
2018-12-13
[30]
웹사이트
Clang 3.7 Release Notes
http://llvm.org/rele[...]
llvm.org
2015-10-10
[31]
웹사이트
Absoft Home Page
https://www.absoft.c[...]
2019-02-12
[32]
웹사이트
GCC 4.9 Release Series – Changes
https://www.gnu.org/[...]
www.gnu.org
[33]
웹사이트
OpenMP* 4.0 Features in Intel Compiler 15.0
https://software.int[...]
Software.intel.com
2014-11-10
[34]
웹사이트
GCC 6 Release Series - Changes
https://www.gnu.org/[...]
www.gnu.org
[35]
웹사이트
OpenMP Compilers & Tools
https://www.openmp.o[...]
www.openmp.org
2019-10-29
[36]
웹사이트
OpenMP Support — Clang 12 documentation
https://clang.llvm.o[...]
2020-10-23
[37]
웹사이트
GOMP — An OpenMP implementation for GCC - GNU Project - Free Software Foundation (FSF)
https://web.archive.[...]
2020-10-23
[38]
웹사이트
OpenMP* Support
https://www.intel.co[...]
2020-10-23
[39]
학술지
OpenMP parallelism for fluid and fluid-particulate systems
[40]
학술지
Efficient parallel CFD-DEM simulations using OpenMP
[41]
웹사이트
OpenMP Accelerator Support for GPUs
https://www.openmp.o[...]
[42]
웹사이트
Detecting and Avoiding OpenMP Race Conditions in C++
http://developers.su[...]
[43]
웹사이트
Alexey Kolosov, Evgeniy Ryzhkov, Andrey Karpov 32 OpenMP traps for C++ developers
https://web.archive.[...]
2009-04-15
[44]
문서
Stephen Blair-Chappell, Intel Corporation, Becoming a Parallel Programming Expert in Nine Minutes, presentation on ACCU (organisation) 2010 conference
[45]
학술지
Multi-Core Software
2007-11-15
[46]
웹사이트
OMPM2001 Result
http://www.spec.org/[...]
SPEC
2008-01-28
[47]
웹사이트
OMPM2001 Result
https://web.archive.[...]
SPEC
2003-04-01
[48]
웹사이트
OpenMP 3.1 Released
https://www.openmp.o[...]
[49]
웹사이트
OpenMP® ARB Releases OpenMP 6.0 for Easier Programming
https://www.openmp.o[...]
[50]
서적
High performance computing : modern systems and practices
https://www.worldcat[...]
[51]
웹사이트
§Example: /openmp (Enable OpenMP Support) | Microsoft Learn
https://learn.micros[...]
[52]
웹사이트
第 4 章 入れ子並列処理 (Sun Studio 12: OpenMP API ユーザーズガイド)
https://docs.oracle.[...]
[53]
학술지
Hybrid MPI/OpenMP Parallel Programming on Clusters of Multi-Core SMP Nodes
https://ieeexplore.i[...]
2009-02
[54]
웹사이트
OpenMP 4.0 Specifications Released - OpenMP
https://www.openmp.o[...]
[55]
웹사이트
インテル® コンパイラーを使用した OpenMP* による並列プログラミング - セッション 3: OpenMP* の SIMD 機能
https://jp.xlsoft.co[...]
[56]
웹사이트
インテル® コンパイラーを使用した OpenMP* による GPU オフロードの基本
https://jp.xlsoft.co[...]
[57]
웹사이트
OpenMP* 入門 | iSUS
http://www.isus.jp/p[...]
[58]
웹사이트
OpenMP Application Program Interface Version 3.0 May 2008(日本語版)| 富士通株式会社
https://openmp.org/w[...]
[59]
웹사이트
OpenMP ディレクティブの使用 - IBM Documentation
https://www.ibm.com/[...]
[60]
웹사이트
インテル® Fortran コンパイラーの Fortran 言語と OpenMP* 機能 | iSUS
https://www.isus.jp/[...]
[61]
웹사이트
OpenMP API ユーザーズガイド - Sun™ Studio 9 | Sun Microsystems, Inc.
https://docs.oracle.[...]
[62]
웹사이트
openmp - GCC Wiki
https://gcc.gnu.org/[...]
[63]
웹사이트
Clang 3.7 Release Notes — Clang 3.7 documentation
http://releases.llvm[...]
2017-06-04
[64]
웹사이트
OpenMP®/Clang
http://clang-omp.git[...]
[65]
웹사이트
Clang 3.9 Release Notes — Clang 3.9 documentation
https://releases.llv[...]
[66]
웹사이트
OpenMP in Visual C++ | Microsoft Docs
https://docs.microso[...]
[67]
웹사이트
/openmp (Enable OpenMP Support) | Microsoft Learn
https://learn.micros[...]
[68]
웹사이트
SIMD Extension | Microsoft Learn
https://learn.micros[...]
[69]
웹사이트
OpenMP* 4.0 Features in Intel C++ Composer XE 2013 | Intel® Developer Zone
https://software.int[...]
[70]
웹사이트
インテル® Fortran および C++ コンパイラーで実装される OpenMP* 機能の調査 | iSUS
https://www.isus.jp/[...]
[71]
웹사이트
About the OpenMP ARB and OpenMP.org
http://openmp.org/wp[...]
2013-08-09
[72]
웹사이트
About the OpenMP ARB and OpenMP.org
http://openmp.org/wp[...]
2013-08-09
[73]
웹사이트
OpenMP Compilers
http://openmp.org/wp[...]
[74]
웹사이트
OpenMP 버전별 사양
https://www.openmp.o[...]
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com
