2014-09-10 20 views
0

我嘗試使用openmp並發現奇怪的結果。使用openmp啓用slow serial「for」

並行「for」按照預期運行openmp。但是,當openmp禁用時(不帶/ openmp選項vs 2013),序列「for」運行得更快。

測試代碼

const int n = 5000; 
    const int m = 2000000; 
    vector <double> a(n, 0); 

    double start = omp_get_wtime(); 
    #pragma omp parallel for shared(a) 
    for (int i = 0; i < n; i++) 
    { 
     double StartVal = i; 

     for (int j = 0; j < m; ++j) 
     { 
      a[i] = (StartVal + log(exp(exp((double)i)))); 
     } 
    } 

    cout << "omp Time: " << (omp_get_wtime() - start) << endl; 

    start = omp_get_wtime(); 

    for (int i = 0; i < n; i++) 
    { 
     double StartVal = i; 

     for (int j = 0; j < m; ++j) 
     { 
      a[i] = (StartVal + log(exp(exp((double)i)))); 
     } 
    } 

    cout << "serial Time: " << (omp_get_wtime() - start) << endl; 

無/ OpenMP的選項

0 
omp Time: 6.4389 
serial Time: 6.37592 

輸出,帶/ OpenMP的選項

0 
1 
2 
3 
omp Time: 1.84636 
serial Time: 16.353 

輸出是否正確的結果?或者我做錯了什麼?

+2

啓用OpenMP可能會抑制某些類型的編譯器優化。你是使用Release還是使用Debug代碼運行?內部循環是多餘的,在釋放模式下不應該將其變爲二進制。 – 2014-09-10 12:14:45

+0

輸出爲發佈模式 – user1312837 2014-09-11 10:19:18

回答

0

我相信部分答案隱藏在您運行的計算機的體系結構中。我試着在另一臺機器上運行相同的代碼(GNU + Linux上的GCC 4.8,四核Core2 CPU),並且運行了很多次,結果發現有點奇怪:雖然兩個循環的時間不一樣,而且有很多線程的OpenMP運行速度一直很快,即使沒有OpenMP,第二個循環也不會比第一個循環跑得快得多。

下一步是嘗試消除循環之間的依賴關係,爲第二個循環分配第二個向量。它仍然沒有比第一次跑得快。所以我試着倒過來,在串口之後運行OpenMP循環;雖然它在多線程時仍然運行得很快,但現在第一次循環時會出現延遲。這看起來更像是一個操作系統行爲;長壽的線程似乎更有可能被打斷。我採取了一些措施來減少中斷(nice -15,特定的CPU集合),但這不是專門用於基準測試的系統。但是,我的結果沒有任何結果與您的結果差不多。我第一次猜測造成你的巨大差異的是你重複使用同一個陣列首先運行並行循環。這會將陣列分配到所有內核的緩存中,導致將線程遷移到數據還是其他方式的兩難處境;並且OpenMP可能選擇了任何分發,包括迭代i來線程i%線程(與schedule(static,1)一樣),這可能會傷害多線程運行時,或者每個緩存線會損害稍後的單線程讀取(如果它適合每個內核緩存)。但是,所有的數組訪問都是寫操作,所以處理器不應該首先等待它們。

總之,你的結果肯定是平臺相關和意外的。我建議重新運行交換順序的測試,這兩個循環在不同的數組上運行,並放置在不同的編譯單元中,當然也用於驗證書面結果。你可能在你的編譯器中發現了一個缺陷。

+0

我會一直等到OP確認他正在發佈模式下編譯。我發現很難相信用'log(exp(exp((double)i))只填充5000個雙精度的數組在現代處理器上花費6秒鐘。 – 2014-09-11 08:50:05

+0

對串行和並行循環使用不同的矢量消除了這個問題 – user1312837 2014-09-11 10:23:38