2016-11-13 46 views
0

---------------------編輯------------------ -------OpenMP:ON NUMA的編譯指示取消

我已編輯的代碼如下:

#pragma omp parallel for private(i, piold, err) shared(threshold_err) reduction(+:pi) schedule (static) 
{ 
    for (i = 0; i < 10000000000; i++){ //1000000000//705035067 
     piold = pi; 
     pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1); 
     err = fabs(pi-piold); 
     if (err < threshold_err){ 
#pragma omp cancel for 
     } 

    } 
} 
    pi = 4*pi; 

我與LLVM3.9/Clang4.0編譯它。當我使用一個線程運行它時,我得到了預期的結果,其中使用了雜注取消操作(對照非編譯指示取消版本進行檢查,導致運行速度更快)。

但是當我運行線程> = 2時,程序進入循環。我在NUMA機器上運行代碼。發生什麼事?也許取消條件不滿足!但是,然後代碼花費比單線程非編譯指示取消版本更長的時間!僅供參考,它在OMP_CANCELLATION = false時運行文件。


我有以下的OpenMP代碼。我正在使用LLVM-3.9/Clang-4.0編譯此代碼。

#pragma omp parallel private(i, piold, err) shared(pi, threshold_err) 
{ 
#pragma omp for reduction(+:pi) schedule (static) 
    for (i = 0; i < 10000000 ; i++){ 
     piold = pi; 
     pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1); 
     #pragma omp critical 
     { 
     err = fabs(pi-piold);// printf("Err: %0.11f\n", err); 
     } 
     if (err < threshold_err){ 
       printf("Cancelling!\n"); 
       #pragma omp cancel for 
     } 

    } 
} 

不幸的是,我不認爲#pragma omp cancel for被終止整個for循環。我最終打印出的值是err,但再次使用並行性時,會打印出哪個值會產生混淆。 err的最終值小於threshold_err。打印取消是打印,但在程序的最開始,這是令人驚訝的。程序在那之後繼續運行!

如何確保這是正確的實施? BTW OMP_CANCELLATION設置爲true,並且一個小測試程序爲相應的函數omp_get_cancellation()返回'1'。

回答

1

據我所知,omp cancel只是一箇中斷信號,它會通知以便以後不再創建線程。仍在運行的線程將一直持續到結束。請參閱http://bisqwit.iki.fi/story/howto/openmp/http://jakascorner.com/blog/2016/08/omp-cancel.html

實際上,在我看來,我看到您的程序產品可接受的近似值。但是,一些變量可以保持在較小的範圍內。這是我的建議

#include <iostream> 
#include <cmath> 
#include <iomanip> 

int main() { 

    long double pi = 0.0; 
    long double threshold_err = 1e-7; 
    int cancelFre = 0; 

#pragma omp parallel shared(pi, threshold_err, cancelFre) 
    { 
#pragma omp for reduction(+:pi) schedule (static) 
     for (int i = 0; i < 100000000; i++){ 
      long double piold = pi; 
      pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1); 
      long double err = std::fabs(pi-piold); 
      if (err < threshold_err){ 

#pragma omp cancel for 
       cancelFre++; 
      } 

     } 
    } 

    std::cout << std::setprecision(10) << pi * 4 << " " << cancelFre; 

    return 0; 
} 
+0

嗨,感謝您的回覆。什麼是cancelFre? – algoProg

+1

另外,當我刪除'cancel for'循環部分時,代碼在'i = 100000000'時需要約11秒。但是在取消它的過程中,我必須永遠放棄它。 – algoProg

+0

@algoProg cancelFre是cancalling的頻率,我把它放在ompcancel之後來計算髮送取消信號的次數(這樣我就知道它只是一個信號)。我很確定我可以通過循環。我也在我的筆記本電腦上確認您的代碼也適用。我只是看到你分享了很多變數。 –

1

好吧,我解決了它。在我的代碼上面的問題在這裏:

err = fabs(pi-piold);

在上線pi如果條件改變後,之前被改變。多個線程也是如此。據我瞭解,這使得程序陷入僵局。

我解決它通過強制只有一個線程,主人,做此項檢查:

if(omp_get_thread_num()==0){ 
err = fabs(pi-piold); 
if (err < threshold_err){ 
#pragma omp cancel for 
     } 
} 

我可以使用#pragma omp single,但它給了錯誤關於嵌套編譯指示。

這裏性能受到線程數量較少(1-4比正常的順序代碼差)。之後,性能提高。這不是最好的解決方案,有人可以肯定地改善這一點。

+0

我還是不明白爲什麼你更喜歡讓我和圈外的人在圈外,同時他們可以在循環範圍內。如果它們只在循環內部,則不會擔心競爭條件,因爲它們在每個循環中都是分開的。 –

+0

請看khôinguyễn的答案。有用!!基本上在並行雜注中定義'i'和'piold'。儘管1-4線程的性能仍然不利於順序。 5-16線性放大(16是最大線程數)。 – algoProg