2016-03-21 63 views
1

我一塊,我要並行化和OpenMP程序比串行版本慢得多的代碼,那麼,什麼是錯我的執行?這是程序的代碼OpenMP的等待時間內爲

#include <iostream> 
#include <gsl/gsl_math.h> 
#include "Chain.h" 
using namespace std; 

int main(){ 
    int const N=1000; 
    int timeSteps=100; 
    double delta=0.0001; 
    double qq[N]; 
    Chain ch(N); 
    ch.initCond(); 
    for (int t=0; t<timeSteps; t++){ 
    ch.changeQ(delta*t); 
    ch.calMag_i(); 
    ch.calForce001(); 
    } 
    ch.printSomething(); 
} 

的Chain.h是

class Chain{ 
    public: 
    int N; 
    double *q; 
    double *mx; 
    double *my; 
    double *force; 

    Chain(int const Np); 
    void initCond(); 
    void changeQ(double delta); 
    void calMag_i(); 
    void calForce001(); 
}; 

而且Chain.cpp是

Chain::Chain(int const Np){ 
    this->N  = Np; 
    this->q  = new double[Np]; 
    this->mx = new double[Np]; 
    this->my = new double[Np]; 
    this->force = new double[Np]; 
} 

void Chain::initCond(){ 
    for (int i=0; i<N; i++){ 
    q[i]  = 0.0; 
    force[i] = 0.0; 
    } 
} 

void Chain::changeQ(double delta){ 
    int i=0; 
    #pragma omp parallel 
    { 
    #pragma omp for 
    for (int i=0; i<N; i++){ 
     q[i] = q[i] + delta*i + 1.0*i/N; 
    } 
    } 
} 

void Chain::calMag_i(){ 
    int i =0; 
    #pragma omp parallel 
    { 
    #pragma omp for 
    for (i=0; i<N; i++){ 
     mx[i] = cos(q[i]); 
     my[i] = sin(q[i]); 
    } 
    } 
} 

void Chain::calForce001(){ 
    int i; 
    int j; 
    double fij =0.0; 
    double start_time = omp_get_wtime(); 
    #pragma omp parallel 
    { 
    #pragma omp for private(j, fij) 
    for (i=0; i<N; i++){ 
     force[i] = 0.0; 
     for (j=0; j<i; j++){ 
     fij = my[i]*mx[j] - mx[i]*my[j]; 
     #pragma omp critical 
     { 
      force[i] += fij; 
      force[j] += -fij; 
     } 
     } 
    } 
    } 
    double time = omp_get_wtime() - start_time; 
    cout <<"time = " << time <<endl; 
} 

所以方法changeQ()和calMag_i()是實際上比串行代碼快,但我的問題是calForce001()。執行時間是:

  • 使用OpenMP 3.939s
  • 沒有OpenMP的0.217s

現在,顯然,我做錯了什麼或代碼不能並行。請有用的幫助。 在此先感謝。 卡洛斯

編輯: 爲了闡明I增加功能omp_get_wtime()的問題來計算功能calForce001()的執行時間和所述次爲一個執行是

  • 與OMP :0.0376656
  • 而不OMP:0.00196766

因此,與OMP方法是慢20倍

否則,我也計算用於calMag_i()的時間方法

  • 與OMP:3.3845e-05
  • 而不OMP:9.9516e-05

對於這種方法omp是快3倍

我希望這確認延遲問題在calForce001()方法。

+0

你不顯示calForce001,但你可能想看看這個和剖析你的代碼:http://stackoverflow.com/questions/7181078/how-to-profile-openmp-bottlenecks –

+0

我顯示calForce是Chain.cpp中的最後一個方法(有一個滾動條) – alfaceor

+0

現在我添加函數來計算在#pragma omp parallel之前和之後使用的時間。所以時間是一個執行如下:與omp的時間是0.0376656,沒有雜注(沒有omp)時間是0.00196766 – alfaceor

回答

3

有三個原因,你沒有任何加速中受益。

  • 你有#pragma omp parallel遍及你的代碼。這個編譯指南的作用是啓動「線程團隊」。在該區塊結束時,該團隊解散。這是非常昂貴的。刪除這些並使用#pragma omp parallel for而不是#pragma omp for將在第一次遇到時開始團隊,並在每個塊之後將其設置爲休眠狀態。這使我的應用程序速度提高了4倍。
  • 您使用#pragma omp critical。在大多數平臺上,這將強制使用互斥鎖 - 這是一個非常激烈的爭論,因爲所有線程都想同時寫入該變量。所以,不要在這裏使用關鍵部分。你可以使用atomic updates,但在這種情況下,這不會有很大的區別 - 見第三項。只是刪除關鍵部分提高了另外3倍的速度。
  • 並行性只有在有實際工作負載時纔有意義。您的所有代碼太小,無法從並行中受益。只需要太少的工作量就可以贏回開始/喚醒/銷燬線程的時間。如果你的工作量是十倍,parallel for的一些是有道理的。但特別是Chain::calForce001()將永遠不值得它,如果你必須做原子更新。

關於編程風格:您使用C++進行編程。請儘可能使用局部範圍變量 - 例如Chain::calForce001(),在內部循環中使用本地double fij。這可以使您不必編寫private子句。編譯器足夠聰明來優化。正確的作用域允許更好的優化。

+1

如果編譯器尚未自動進行矢量化,@alfaceor可能會從OpenMP SIMD矢量化中獲得體面加速。 'calForce001'的內部循環看起來是可以矢量化的,而不需要向量中的水平操作。它甚至可以在沒有'-fast-math'的情況下進行自動矢量化,在這種情況下,OpenMP simd編譯指示可能不會對'-O3'上的正常編譯器輸出產生幫助 –