2016-07-17 75 views
1

循環我有這樣的代碼:的OpenMP用的std ::矢量和標量減少與

#pragma omp declare reduction(* : scalar : omp_out *= omp_in)  
scalar like=1; 
vector<scalar>& bigsum; 
#pragma omp parallel for // reduction(* : like)  
for (int m = 0; m < M-1; m++) 
    like *= bigsum[m]; 

我試圖得到一個一致的結果,但它沒有做(競爭狀態的問題),但應該如何我修復它?因爲它在代碼中可見,我有我自己的reduction function,但它也不起作用。我應該知道的標量和std :: vector有什麼技巧嗎?

標量變量在這裏只是通過在我創建的每個double上應用log()來重寫浮點數,因爲有很多double to double乘法,並且它們之後的結果接近於零。例如,通過執行log(),然後乘法變成加法等等。

獲得一致的答案一個解決的方法是這樣的:

#pragma omp parallel 
    { 
     scalar loc = 1; 
    #pragma omp for 
     for (std::size_t m = 1; m < M;m++) 
     { 
      _flm[m-1] = Qratio[m-1] * k1 + k2; 
      bigsum[m-1] = kappa0omegaproduct + kappa[1] * _flm[m-1]; 
    #pragma omp critical (reduce_product) 
      { 
      like *= bigsum[m-1]; 
      } 
     } 
} 

這個答案是正確的,但這麼慢呢是我的8芯機上慢了近8倍!

+0

什麼類型是'scalar'?你觀察到什麼樣的競爭條件。 – Zulan

+0

我正在處理非常大的雙數。當我將它們乘以很多時,它們變得太接近於零,所以我使用這種標量類型,這種標量類型在這些小型雙打日誌上超載操作。 –

+1

無論如何,請提供[mcve]。 – Zulan

回答

2

三天後我自己有一個答案,並解釋了我發現的內容。

我已經創建了自己的降噪功能是這樣的:

#pragma omp declare reduction(* : scalar : omp_out *= omp_in) initializer (omp_priv (1)) 

訣竅是omp_priv,顯然減少值初始化是很重要的,我事端在here教訓。

該我做的代碼通過應用我的OpenMP像這樣的循環簡單得多:

#pragma omp parallel for reduction (* : like) 

很簡單,乾淨。以這種新方式,代碼得到了並行化,運行速度比我在問題主體中的速度更快。不幸的是,它仍然比串行版本慢。也許這是因爲std :: vector的用法,或者重載的算術運算非常慢!我不知道。代碼太大了,我無法複製粘貼到這裏,這是可以理解的,而不是爲了讓別人閱讀而痛苦。

1

您的第一個示例依賴於本機OpenMP減少。您確定用戶定義的OpenMP減少工作正確嗎?這可能是一個重載操作符的問題。

你的第二個例子是正確的(你說過),但由於關鍵部分非常緩慢。爲什麼不通過每個線程使用局部變量(例如「local_like」),然後在「omp for」之後使用臨界區域來手動實現OpenMP壓縮?

+0

是的,我應該更新我的減少功能。首先,我必須進行調試才能瞭解爲什麼某些重載函數未被調用!謝謝你提到它。 –

+0

當我用局部變量做到這一點時,如果您查看自己的答案,我看不到所需的加速,我已經完成了減少,並且比我在8核心機器上共享的代碼快了近10倍。 –