openmp
OpenMP의 루프 병렬성
수색…
매개 변수
절 | 매개 변수 |
---|---|
private | 쉼표로 구분 된 개인 변수 목록 |
firstprivate | private 과 같지만 루프에 들어가기 전에 변수의 값으로 초기화됩니다. |
lastprivate | private 와 마찬가지로 변수는 exit시 루프의 마지막 반복에 해당하는 값을 가져옵니다. |
reduction | 감소 연산자 : 쉼표로 구분 된 해당 감소 변수 목록 |
schedule | 선택 사항 인 청크 크기가있는 static , dynamic , guided , auto 또는 runtime |
collapse | 축소 및 병렬 처리 할 완벽하게 중첩 된 루프 수 |
ordered | 루프의 일부분을 순차적으로 보관할 필요가 있음을 알려줍니다 (이 부분은 루프 본문 내에서 ordered 절로 명확하게 식별됩니다) |
nowait | 루프 구문의 끝 부분에 기본적으로 존재하는 암시 적 장벽 제거 |
비고
schedule
절의 의미는 다음과 같습니다.
-
static[,chunk]
: 라운드 로빈 방식으로chunk
크기의 일괄 처리 된 루프 반복을 정적으로 (즉, 루프에 들어가기 전에 배포가 이루어진다는 의미로) 배포하십시오.chunk
가 지정되지 않은 경우chunk
는 가능한 한 균일하고 각 스레드는 최대 하나를 얻습니다. -
dynamic[,chunk]
: 일괄 처리가 남아 있지 않을 때까지 선착순 정책으로chunk
크기의 일괄 처리로 스레드 사이에 루프 반복을 배포합니다. 지정하지 않으면chunk
가 1로 설정됩니다. -
guided[,chunk]
:dynamic
것처럼 보이지만 크기가 점점 작아지는 배치를 사용하면 1까지 내려갑니다. -
auto
: 컴파일러 나 런타임 라이브러리가 무엇이 가장 적합한 지 결정하게하십시오. -
runtime
:OMP_SCHEDULE
환경 변수를 사용하여runtime
에 결정을OMP_SCHEDULE
하십시오. 런타임에 환경 변수가 정의되어 있지 않으면 기본 스케줄링이 사용됩니다
schedule
의 기본값은 구현 정의 입니다. 많은 환경에서 static
이지만 dynamic
수도 있고 auto
수도 있습니다. 따라서 구현이 명시 적으로 설정하지 않고 암묵적으로 의존하지 않도록주의하십시오.
위의 예제에서 우리는 융합 된 형태를 parallel for
또는 parallel do
사용했습니다. 그러나 루프 구조는 parallel
영역 내에서 #pragma omp for [...]
또는 !$omp do [...]
독립 실행 형 지시문의 #pragma omp for [...]
형태로 parallel
지시문과 함께 사용하지 않고 사용할 수 있습니다.
Fortran 버전의 경우에만 parallized 루프의 루프 인덱스 변수가 기본적으로 항상 private
입니다. 따라서 명시 적으로 private
선언 할 필요는 없습니다 (오류는 발생하지 않음).
C 및 C ++ 버전의 경우 루프 인덱스는 다른 변수와 같습니다. 따라서 범위가 병렬 처리 된 루프 외부로 확장되는 경우 for ( int i = ...)
와 같이 선언되지 않고 for ( int i = ...)
와 같이 선언 된 경우 for ( int i = ...)
int i; ... for ( i = ... )
private
로 선언 해야합니다 .
C의 전형적인 예
#include <stdio.h>
#include <math.h>
#include <omp.h>
#define N 1000000
int main() {
double sum = 0;
double tbegin = omp_get_wtime();
#pragma omp parallel for reduction( +: sum )
for ( int i = 0; i < N; i++ ) {
sum += cos( i );
}
double wtime = omp_get_wtime() - tbegin;
printf( "Computing %d cosines and summing them with %d threads took %fs\n",
N, omp_get_max_threads(), wtime );
return sum;
}
이 예제에서는 100 만 코사인을 계산하고 그 값을 병렬로 합계합니다. 또한 병렬 처리가 성능에 어떤 영향을 주는지 여부를 확인하기 위해 실행을 시간을 잰다. 마지막으로, 우리는 시간을 측정하기 때문에 컴파일러가 수행 한 작업을 최적화하지 않아야하므로 결과를 반환하는 것처럼 가장합니다.
Fortran에서의 동일한 예
program typical_loop
use omp_lib
implicit none
integer, parameter :: N = 1000000, kd = kind( 1.d0 )
real( kind = kd ) :: sum, tbegin, wtime
integer :: i
sum = 0
tbegin = omp_get_wtime()
!$omp parallel do reduction( +: sum )
do i = 1, N
sum = sum + cos( 1.d0 * i )
end do
!$omp end parallel do
wtime = omp_get_wtime() - tbegin
print "( 'Computing ', i7, ' cosines and summing them with ', i2, &
& ' threads took ', f6.4,'s' )", N, omp_get_max_threads(), wtime
if ( sum > N ) then
print *, "we only pretend using sum"
end if
end program typical_loop
다시 여기에서 1 백만 코사인을 계산하고 누적합니다. 우리는 루프를 돌리고 원치 않는 컴파일러 최적화를 피하기 위해 결과를 사용하여 가장합니다.
예제 컴파일 및 실행
GCC 버전 4.4를 사용하는 8 코어 Linux 컴퓨터에서 C 코드는 다음과 같이 컴파일되고 실행될 수 있습니다.
$ gcc -std=c99 -O3 -fopenmp loop.c -o loopc -lm
$ OMP_NUM_THREADS=1 ./loopc
Computing 1000000 cosines and summing them with 1 threads took 0.095832s
$ OMP_NUM_THREADS=2 ./loopc
Computing 1000000 cosines and summing them with 2 threads took 0.047637s
$ OMP_NUM_THREADS=4 ./loopc
Computing 1000000 cosines and summing them with 4 threads took 0.024498s
$ OMP_NUM_THREADS=8 ./loopc
Computing 1000000 cosines and summing them with 8 threads took 0.011785s
Fortran 버전의 경우 다음과 같습니다.
$ gfortran -O3 -fopenmp loop.f90 -o loopf
$ OMP_NUM_THREADS=1 ./loopf
Computing 1000000 cosines and summing them with 1 threads took 0.0915s
$ OMP_NUM_THREADS=2 ./loopf
Computing 1000000 cosines and summing them with 2 threads took 0.0472s
$ OMP_NUM_THREADS=4 ./loopf
Computing 1000000 cosines and summing them with 4 threads took 0.0236s
$ OMP_NUM_THREADS=8 ./loopf
Computing 1000000 cosines and summing them with 8 threads took 0.0118s
구성을 위해 OpenMP 병렬을 사용하는 두 벡터의 추가
void parallelAddition (unsigned N, const double *A, const double *B, double *C)
{
unsigned i;
#pragma omp parallel for shared (A,B,C,N) private(i) schedule(static)
for (i = 0; i < N; ++i)
{
C[i] = A[i] + B[i];
}
}
이 예는 스레드 팀 (예 : OMP_NUM_THREADS
변수로 지정)을 스폰하고 각 스레드에 작업 청크를 할당하여 두 개의 벡터 ( A
와 B
를 C
)를 추가합니다 (이 예에서는 schedule(static)
통해 정적으로 할당 됨 schedule(static)
표현).
private(i)
선택 사항과 관련하여 비고 부분을 참조하십시오.