簡體   English   中英

關於OpenMP和-Ofast的組合

[英]About the combination of OpenMP and -Ofast

在for循環中實現了OpenMP並行化,在該循環中 ,我有一個總和 ,這是導致我的代碼運行緩慢的主要原因。 當我這樣做時,我發現最終結果與非並行代碼(用C編寫)獲得的結果不同。 因此,首先,人們可能會認為“嗯,我只是沒有很好地實現並行化”,但是奇怪的是,當我使用-Ofast優化運行並行化代碼時,結果突然是正確的。

那將是:

  • -O0正確
  • -Ofast正確
  • OMP -O0錯誤
  • OMP -O1錯誤
  • OMP -O2錯誤
  • OMP -O3錯誤
  • OMP -Ofast正確!

-Ofast可以做什么來解決僅在實現openmp時出現的錯誤? 對我可以檢查或測試的內容有何建議? 謝謝!

編輯在這里,我包括仍會重現該問題的最小版本的代碼。

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

#define LENGTH 100
#define R 50.0
#define URD 1.0/sqrt(2.0)
#define PI (4.0*atan(1.0)) //pi

const gsl_rng_type * Type;
gsl_rng * item;

double CalcDeltaEnergy(double **M,int sx,int sy){
    double DEnergy,r,zz;
    int k,j;
    double rrx,rry;
    int rx,ry;
    double Energy, Cpm, Cmm, Cmp, Cpp;
    DEnergy = 0;

    //OpenMP parallelization:
    #pragma omp parallel for reduction (+:DEnergy)
    for (int index = 0; index < LENGTH*LENGTH; index++){
        k = index % LENGTH;
        j = index / LENGTH;

    zz = 0.5*(1.0 - pow(-1.0, k + j + sx + sy));
    for (rx = -1; rx <= 1; rx++){
        for (ry = -1; ry <= 1; ry++){
            rrx = (sx - k - rx*LENGTH)*URD;
            rry = (sy - j - ry*LENGTH)*URD;

            r = sqrt(rrx*rrx + rry*rry + zz);
            if(r != 0 && r <= R){
                Cpm = sqrt((rrx+0.5*(0.702*cos(M[k][j])-0.702*cos(M[sx][sy])))*(rrx+0.5*(0.702*cos(M[k][j])-0.702*cos(M[sx][sy]))) + (rry+0.5*(0.702*sin(M[k][j])-0.702*sin(M[sx][sy])))*(rry+0.5*(0.702*sin(M[k][j])-0.702*sin(M[sx][sy]))) + zz);
                Cmm = sqrt((rrx-0.5*(0.702*cos(M[k][j])-0.702*cos(M[sx][sy])))*(rrx-0.5*(0.702*cos(M[k][j])-0.702*cos(M[sx][sy]))) + (rry-0.5*(0.702*sin(M[k][j])-0.702*sin(M[sx][sy])))*(rry-0.5*(0.702*sin(M[k][j])-0.702*sin(M[sx][sy]))) + zz);
                Cpp = sqrt((rrx+0.5*(0.702*cos(M[k][j])+0.702*cos(M[sx][sy])))*(rrx+0.5*(0.702*cos(M[k][j])+0.702*cos(M[sx][sy]))) + (rry+0.5*(0.702*sin(M[k][j])+0.702*sin(M[sx][sy])))*(rry+0.5*(0.702*sin(M[k][j])+0.702*sin(M[sx][sy]))) + zz);
                Cmp = sqrt((rrx-0.5*(0.702*cos(M[k][j])+0.702*cos(M[sx][sy])))*(rrx-0.5*(0.702*cos(M[k][j])+0.702*cos(M[sx][sy]))) + (rry-0.5*(0.702*sin(M[k][j])+0.702*sin(M[sx][sy])))*(rry-0.5*(0.702*sin(M[k][j])+0.702*sin(M[sx][sy]))) + zz);
                Cpm = 1.0/Cpm;
                Cmm = 1.0/Cmm;
                Cpp = 1.0/Cpp;
                Cmp = 1.0/Cmp;
                Energy = (Cpm + Cmm - Cpp - Cmp)/(0.702*0.702); // S=cte=1

                DEnergy -= 2.0*Energy;
            }
        }
    }
    }
return DEnergy;
}

void Initialize(double **M){
double random;
    for(int i=0;i<(LENGTH-1);i=i+2){
          for(int j=0;j<(LENGTH-1);j=j+2) {
              random=gsl_rng_uniform(item);
              if (random<0.5) M[i][j]=PI/4.0;
              else M[i][j]=5.0*PI/4.0;

              random=gsl_rng_uniform(item);
              if (random<0.5) M[i][j+1]=3.0*PI/4.0;
              else M[i][j+1]=7.0*PI/4.0;

              random=gsl_rng_uniform(item);
              if (random<0.5) M[i+1][j]=3.0*PI/4.0;
              else M[i+1][j]=7.0*PI/4.0;

              random=gsl_rng_uniform(item);
              if (random<0.5) M[i+1][j+1]=PI/4.0;
              else M[i+1][j+1]=5.0*PI/4.0;
          }
    }
}

int main(){
    //Choose and initiaze the random number generator
    gsl_rng_env_setup();
    Type = gsl_rng_default; //default=mt19937, ran2, lxs0
    item = gsl_rng_alloc (Type);

    double **S; //site matrix
    S = (double **) malloc(LENGTH*sizeof(double *));
    for (int i = 0; i < LENGTH; i++)
        S[i] = (double *) malloc(LENGTH*sizeof(double ));

    //Initialization
    Initialize(S);

    int l,m;
    for (int cl = 0; cl < LENGTH*LENGTH; cl++) {
        l = gsl_rng_uniform_int(item, LENGTH); // RNG[0, LENGTH-1]
        m = gsl_rng_uniform_int(item, LENGTH); // RNG[0, LENGTH-1]
        printf("%lf\n", CalcDeltaEnergy(S, l, m));
    }


    //Free memory
    for (int i = 0; i < LENGTH; i++)
        free(S[i]);
    free(S);
    return 0;
} 

我編譯:

g++ [optimization] -lm test.c -o test.x -lgsl -lgslcblas -fopenmp

並運行:

GSL_RNG_SEED=123; ./test.x > test.dat

比較不同優化的輸出,可以看到我之前所說的內容。

免責聲明:我對OpenMP幾乎沒有經驗

使用OpenMP時可能會遇到競爭狀況。

您需要將OpenMP循環內的所有這些變量聲明為private 一個芯可以計算的某一值及其值index ,其被及時重新計算為不同的值上,使用的另一值的芯index :變量如kjrrxrry等正在計算節點之間共享。

而不是使用像

#pragma omp parallel for private(k,j,zz,rx,ry,rrx,rry,r,Cpm,Cmm,Cpp,Cmp,Energy) reduction (+:D\

(以下是Zulan提供的評論:)您還可以在並行區域內盡可能局部地聲明變量。 這使它們隱式地成為私有的,並且不容易出現初始化問題,並且更易於推理。

(您甚至可以考慮將所有內容放入函數的外部for循環( index ):與計算相比,函數調用的開銷是最小的。)

至於為什么-Ofast與OpenMP一起實際產生正確的輸出。

我的猜測是:主要是運氣。 這是-Ofast功能(gcc手冊):

忽略嚴格的標准合規性。 -Ofast啟用所有-O3優化。 它還啟用了並非對所有符合標准的程序都有效的優化。 它打開-ffast-math [...]

這是有關-ffast-math的部分:

除-Ofast外,此選項未由任何-O選項打開,因為它可能導致依賴於數學函數的IEEE或ISO規則/規范的確切實現的程序輸出不正確。 但是,對於不需要這些規范保證的程序,它可能會產生更快的代碼。

因此, sqrtcossin可能會更快。 我的猜測是,在這種情況下,外循環內部的變量的計算不會互相影響,因為各個線程是如此之快,因此它們不會沖突。 但這是一個非常費力的解釋和猜測。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM