简体   繁体   中英

Parallelize three_for_loop in C++ by openmp

I have a code. Here, A, B, C, A1, B1, C1 are vectors in 3 dimensional. A, B, C are independent together and A1, B1, C1 are also independent together. I want to parallelize to calculate it by using openmp. However, I run it with openmp, I get "Segmentation fault" error.Could you help me for this problem? Thank you in advance.

#include <omp.h>
#include<math.h> 
#include<cmath> 
#include<vector>    
#include<iostream>

using namespace std;
int main ()
{

int NX=801;              // NUmber of grid in X direction
int NY=501;              
int NZ=401;   
float PI=3.14159265358979323846;
unsigned int i,j,k;
vector<vector<vector<float> > > A (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
vector<vector<vector<float> > > B (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
vector<vector<vector<float> > > C (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
vector<vector<vector<float> > > A1 (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
vector<vector<vector<float> > > B1 (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
vector<vector<vector<float> > > C1 (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));

cout<<"start"<<endl;
#pragma omp parallel for private (j) shared(A,B,C,i,k,NX,NY,NZ) 
for (i=0;i<NX;i++)
    for (j=0;j<NY;j++)
        for (k=0;k<NZ;k++)
        {
            A[i][j][k]=sin(2.0*PI/float(NX*NY*NZ)*float(i*j*k));
            B[i][j][k]=cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
            C[i][j][k]=sin(2.0*PI/float(NX*NY*NZ))*cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
        }

#pragma omp parallel for private (j) shared(A1,B1,C1,A,B,C,i,k,NX,NY,NZ) 
for (i=1;i<NX-1;i++)
    for (j=1;j<NY-1;j++)
        for (k=1;k<NZ-1;k++)
        {
            A1[i][j][k]=C[i+1][j][k]*cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
            B1[i][j][k]=A[i][j][k]+B[i][j][k]+C[i][j][k]*cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
            C1[i][j][k]=16.0*A[i][j][k]*cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
        }
cout<<"finish"<<endl;


return 0;
}

This code is very easy to parallelise with OpenMP. However, you did some mistakes in your own attempt, notably by trying to declare i and k shared whereas they should actually be private . Better even, don't declare the variables in advance and simply declare them inside the for loop. This way, they will have automatically the right scope, preventing you from mixing it up.

Here is what it would give:

#include <omp.h>
#include<math.h> 
#include<cmath> 
#include<vector>    
#include<iostream>

using namespace std;
int main ()
{

    int NX=801;              // NUmber of grid in X direction
    int NY=501;              
    int NZ=401;   
    float PI=3.14159265358979323846;
    vector<vector<vector<float> > > A (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > B (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > C (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > A1 (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > B1 (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > C1 (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));

    cout<<"start"<<endl;
    #pragma omp parallel for
    for (int i=0;i<NX;i++)
        for (int j=0;j<NY;j++)
            for (int k=0;k<NZ;k++)
            {
                A[i][j][k]=sin(2.0*PI/float(NX*NY*NZ)*float(i*j*k));
                B[i][j][k]=cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
                C[i][j][k]=sin(2.0*PI/float(NX*NY*NZ))*cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
            }

    #pragma omp parallel for 
    for (int i=1;i<NX-1;i++)
        for (int j=1;j<NY-1;j++)
            for (int k=1;k<NZ-1;k++)
            {
                A1[i][j][k]=C[i+1][j][k]*cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
                B1[i][j][k]=A[i][j][k]+B[i][j][k]+C[i][j][k]*cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
                C1[i][j][k]=16.0*A[i][j][k]*cos(5.0*PI/float(NX*NY*NZ)*float(i*j*k));
            }
    cout<<"finish"<<endl;

    return 0;
}

Now, since you ask for parallelising this code, I guess you are interested in performance. So nothing should prevent you from implementing one or two very basic performance optimisations like this:

#include <omp.h>
#include<math.h> 
#include<cmath> 
#include<vector>    
#include<iostream>

using namespace std;
int main ()
{

    int NX=801;              // NUmber of grid in X direction
    int NY=501;              
    int NZ=401;   
    float PI=3.14159265358979323846;
    vector<vector<vector<float> > > A (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > B (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > C (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > A1 (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > B1 (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));
    vector<vector<vector<float> > > C1 (NX,vector<vector<float> >(NY,vector <float>(NZ,0.0)));

    const float PIOverSize = PI/(NX*NY*NZ);
    const float sin2PIOverSize = sin(2.0f*PIOverSize);
    cout<<"start"<<endl;
    double tbeg = omp_get_wtime();
    #pragma omp parallel
    {
    #pragma omp for
    for (int i=0;i<NX;i++)
        for (int j=0;j<NY;j++)
        {
            float IJPIOverSize=i*j*PIOverSize;
            for (int k=0;k<NZ;k++)
            {
                A[i][j][k]=sin(2.0f*IJPIOverSize*k);
                B[i][j][k]=cos(5.0f*IJPIOverSize*k);
                C[i][j][k]=sin2PIOverSize*cos(5.0f*IJPIOverSize*k);
            }
         }
    #pragma omp for 
    for (int i=1;i<NX-1;i++)
        for (int j=1;j<NY-1;j++)
        {
            float IJPIOverSize=i*j*PIOverSize;
            for (int k=1;k<NZ-1;k++)
            {
                A1[i][j][k]=C[i+1][j][k]*cos(5.0f*IJPIOverSize*k);
                B1[i][j][k]=A[i][j][k]+B[i][j][k]+C[i][j][k]*cos(5.0f*IJPIOverSize*k);
                C1[i][j][k]=16.0f*A[i][j][k]*cos(5.0f*IJPIOverSize*k);
            }
        }
    }
    double time = omp_get_wtime() - tbeg;
    cout<<"finish in "<<time<<" seconds"<<endl;

    return 0;
}

With this, your code should already be much faster.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM