2013-03-04 227 views
1
#include <iostream> 
#include <iomanip> 
#include <fstream> 
#include <sstream> 
#include <string> 
#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <omp.h> 
using namespace std; 


void output(float a[], float X[], float Y[], int I, int J) 
{ 
    ofstream ft; 
    int i; 

    ft.open("flow.dat"); 
    ft<<"variables=\"x\",\"y\",\"a\""<<"\n" 
    <<"zone f=point"<<"\n" 
    <<"I="<<I<<",J="<<J<<"\n" 
    <<endl; 

    for(int i=0;i<I*J;i++) 
    { 
    ft<<setiosflags(ios::scientific) 
     <<X[i]<<" "<<Y[i]<<" "<<a[i]<<endl; 
    } 

    ft.close(); 

} 

void set(float a[], float X[], float Y[], int I, int J, float hx, float hy) 
{ 
    for(int j=0;j<J;j++) 
    for(int i=0;i<I;i++) 
     { 
     int iC=j*I+i; 
     X[iC]=i*hx; 
     Y[iC]=j*hy; 
     a[iC]=0.0; 
     if(j==J-1) a[iC]=1.0; 
     } 
} 

void difference_serial(float a[], int I, int J, const float hx, const float hy) 
{ 
    const float aC=(hx*hx+hy*hy)*2; 
    const float aX=hy*hy; 
    const float aY=hx*hx; 
    for(int j=1;j<J-1;j++) 
    for(int i=1;i<I-1;i++) 
     { 
     int iC=j*I+i; 
     int iL=iC-1; 
     int iR=iC+1; 
     int iU=iC+I; 
     int iD=iC-I; 
     a[iC]=(aX*(a[iL]+a[iR])+aY*(a[iU]+a[iD]))/aC; 
     } 


} 

void difference_omp(float a[], int I, int J, const float hx, const float hy) 
{ 
    const float aC=(hx*hx+hy*hy)*2; 
    const float aX=hy*hy; 
    const float aY=hx*hx; 

    int i,j,iC,iL,iR,iU,iD; 
#pragma omp parallel for private(i,j,iC,iL,iR,iU,iD) shared(a,I,J) schedule(dynamic) 
    for(j=1;j<J-1;j++) 
    for(i=1;i<I-1;i++) 
     { 
     iC=j*I+i; 
     iL=iC-1; 
     iR=iC+1; 
     iU=iC+I; 
     iD=iC-I; 
     a[iC]=(aX*(a[iL]+a[iR])+aY*(a[iU]+a[iD]))/aC; 
     } 
} 

int main() 
{ 
    const int I=129; 
    const int J=129; 
    const int N=I*J; 
    const float hx=1.0/(I-1); 
    const float hy=1.0/(J-1); 

    float *a=new float[N]; 
    float *X=new float[N]; 
    float *Y=new float[N]; 

    //set the grid and flow 
    set(a,X,Y,I,J,hx,hy); 

    //iteation 
    clock_t start=clock(); 
    for(int it=0;it<10000;it++) 
    difference_serial(a,I,J,hx,hy); 
    clock_t end=clock(); 
    printf("Serial time=%f\n",(float)(end-start)/CLOCKS_PER_SEC); 


    set(a,X,Y,I,J,hx,hy); 
    clock_t start2=clock(); 
    for(int it2=0;it2<10000;it2++) 
    difference_omp(a,I,J,hx,hy); 
    clock_t end2=clock(); 
    printf("Omp time=%f\n",(float)(end2-start2)/CLOCKS_PER_SEC); 

    //output 
    output(a,X,Y,I,J); 

    //free memory 
    delete[] a; 
    delete[] X; 
    delete[] Y; 
} 

我寫了一段代碼來解決二維非常簡單的拉普拉斯方程。試比較串行代碼和OpenMP代碼爲什麼我的OpenMP C++代碼比串行代碼慢?

我試圖編譯 G ++ tmp.cpp -fopenmp

的代碼,並得到了非常奇怪的結果 輸出: 串行時間= 1.620000 外膜蛋白時間= 9.820000

有沒有人可以幫助我找出背後的原因以及如何糾正OpenMP代碼。

+3

你正在測量CPU時間,而不是「掛鐘」時間http://en.wikipedia.org/wiki/Wall_clock_time – CharlesB 2013-03-04 16:38:28

+0

這是一個問題,但它沒有原來的問題。我拿了代碼,並將時間測量值改爲'omp_get_wtime()',但它仍然爲我的PC提供了omp time 13s和serial 3s。我猜這是平行區域instatation開銷。 – luk32 2013-03-04 16:47:26

回答

7

我遇到了有趣的結果。

luk32:~/projects/tests$ g++ -fopenmp -lgomp ./laplace.cpp 
luk32:~/projects/tests$ ./a.out 
Omp time=13.000000 
Serial time=3.000000 
luk32:~/projects/tests$ g++ -O3 -fopenmp -lgomp ./laplace.cpp 
luk32:~/projects/tests$ ./a.out 
Omp time=31.000000 
Serial time=1.000000 

因此,與O3的OpenMP的時間惡化和串行版本下降。我的猜測是問題實例太小,以至於來自調用並行區域的實際開銷在此顯現。

您試圖在您的PC上並行化1.5s/10k = 0.15毫秒的內容。初始化線程池和調度它的開銷尤其是與schedule(dynamic)

我會嘗試做一些測試來確認。不確定隨機碰撞是否合法IJ

後測試:

OK我切換J=I=10240;和設置for(int it=0;it<50;it++)。我還使用omp_get_wtime()進行時間測量。以下是完整的diff文件。

下面是結果:

Serial time=58.982189 
Omp time=9.158118 

據perfromed 6的PHY/12-邏輯核的機器上。現在結果如預期。您的示例問題對於OpenMP來說太小,以至於開銷花費的時間比計算長。

DIFF:

luk32:~/projects/tests$ diff laplace.orig.cpp laplace.cpp 
88,89c88,89 
< const int I=129; 
< const int J=129; 
--- 
> const int I=10000; 
> const int J=10000; 
102,103c102,103 
< clock_t start=clock(); 
< for(int it=0;it<10000;it++) 
--- 
> double start=omp_get_wtime(); 
> for(int it=0;it<50;it++) 
105,106c105,106 
< clock_t end=clock(); 
< printf("Serial time=%f\n",(float)(end-start)/CLOCKS_PER_SEC); 
--- 
> double end=omp_get_wtime(); 
> printf("Serial time=%f\n",(float)(end-start)); 
110,111c110,111 
< clock_t start2=clock(); 
< for(int it2=0;it2<10000;it2++) 
--- 
> double start2=omp_get_wtime(); 
> for(int it2=0;it2<50;it2++) 
113,114c113,114 
< clock_t end2=clock(); 
< printf("Omp time=%f\n",(float)(end2-start2)/CLOCKS_PER_SEC); 
--- 
> double end2=omp_get_wtime(); 
> printf("Omp time=%f\n",(float)(end2-start2)); 

編輯:我剛纔加粗的主要問題,所以任何人誰碰到這個來自動聚焦。

+3

+1 - '您的示例問題太小,OpenMP無法高效'。這是'多線程版本更慢'〜90%的答案。 – 2013-03-04 17:46:59

+0

這是微不足道的並行性,即=)但是它的可伸縮性。它也可能是錯誤的代碼,以及代碼中的冗餘和事情。 TBH我也很「狡猾」。我自己執行xD後,看到了10k個循環。 '10kx10k'已經接近size_t溢出。這個代碼的問題是,即使是大的實例也需要幾秒鐘才能執行。 '輸出'比100倍計算長100倍。問題在於是否應該把時間放在第一位並行。你不會並行執行需要1s的東西。順便說一句,MPI在這裏。 =) – luk32 2013-03-05 00:38:11

相關問題