제안 된 OpenMP 병렬 처리가 올바르지 않아 잘못된 결과가 발생할 수 있습니다. collapse(2)
을 지정할 때 스레드는 (j, k) 반복을 "동시에"실행합니다. 두 개 이상의 스레드가 같은 j이지만 다른 k에서 작동하면 A[i][k]*B[k][j]
의 결과가 동일한 배열 위치 C[i][j]
에 누적됩니다. 이것은 "경합 조건"이라고합니다. 즉, "두 개 이상의 스레드가 공유 데이터에 액세스 할 수 있으며 동시에 변경하려고합니다"(What is a race condition?). 코드가 OpenMP 유효하지 않고 여러 요인 (스케줄링, 컴파일러 구현, 스레드 수 등)에 따라 잘못된 결과가 발생할 수 있지만 데이터 경주가 반드시 잘못된 결과로 이어지는 것은 아닙니다. 위의 코드에서 문제를 해결하려면, OpenMP의는 reduction
절을 제공합니다 :
#pragma omp parallel
{
for(int i=0;i<n;i++) {
#pragma omp for collapse(2) reduction(+:C)
for(int j=0;j<n;j++) {
for(int k=0;k<n;k++) {
C[i][j]+=A[i][k]*B[k][j];
개인 사본 각 암시 적 작업 (...)에서 생성되고 감소의 초기화 값으로 초기화됩니다 "그래서 -identifier. 영역이 끝나면 원래 목록 항목은 축소 식별자와 연결된 결합자를 사용하여 개인 복사본의 값으로 업데이트됩니다 "(http://www.openmp.org/wp-content/uploads/openmp-4.5.pdf). C의 배열 축소는 OpenMP 4.5부터 표준에 의해 직접 지원됩니다 (컴파일러가 지원하는지 확인하십시오. 그렇지 않은 경우이를 구현하기위한 오래된 수동 방법이 있습니다, Reducing on array in OpenMp).
그러나, 주어진 코드, 가장 안쪽의 루프의 병렬화를 피하기 위해 아마 더 적합해야 감소는 전혀 필요하지 않도록 :
#pragma omp parallel
{
#pragma omp for collapse(2)
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
for(int k=0;k<n;k++) {
C[i][j]+=A[i][k]*B[k][j];
직렬가 OpenMP의 버전보다 빠를 수 있습니다 작은 크기의 행렬 및/또는 적은 수의 스레드. 인텔 컴퓨터에서 최대 16 개의 코어 (n = 1000), GNU 컴파일러 v6.1을 사용하는 경우 -O3 최적화가 활성화되면 약 4 코어가 중단되고 -O0으로 컴파일되는 약 2 코어가 중단됩니다. 성능 손실이 극적인 (반전 속도 업)입니다 감소를 사용
Serial 418020
----------- WRONG ORIG -- +REDUCTION -- OUTER.COLLAPSE -- OUTER.NOCOLLAPSE -
OpenMP-1 1924950 2841993 1450686 1455989
OpenMP-2 988743 2446098 747333 745830
OpenMP-4 515266 3182262 396524 387671
OpenMP-8 280285 5510023 219506 211913
OpenMP-16 2227567 10807828 150277 123368
: 명확하게하기 위해 나는 측정 된 성과를보고한다. 외부 병렬 처리 (w 또는 o/붕괴)가 가장 좋은 옵션입니다.
큰 행렬에 대한 실패와 관련하여 가능한 원인은 사용 가능한 스택의 크기와 관련이 있습니다. 시스템 및 OpenMP 스택 크기를 모두 확대 해보십시오. 즉,
ulimit -s unlimited
export OMP_STACKSIZE=10000000
외부 루프의 병렬 처리에 유리하게 보입니다. 축소 된 내부 루프를 포함하여 다른 스레드가 암시하는 것처럼 스레드 내에서 중요한 최적화가 제외 될 수 있습니다. 처음에는 단일 스레드를 최적화하지 않고 병렬 처리를 시작하면 어쨌든 제한이 있습니다. – tim18