簡體   English   中英

如何優化並行化嵌套循環?

[英]How to optimally parallelize nested loops?

我正在編寫一個應同時在串行和並行版本中運行的程序。 一旦讓它實際執行了應該執行的操作,我便開始嘗試將它與OpenMP(強制性)並行化。

問題是我找不到何時使用#pragma的文檔或參考。 因此,我正在盡力進行猜測和測試。 但是使用嵌套循環進行測試並不能很好地進行。

您如何並行化一系列嵌套循環,如下所示:

for(int i = 0; i < 3; ++i){
    for(int j = 0; j < HEIGHT; ++j){
        for(int k = 0; k < WIDTH; ++k){
            switch(i){
                case 0:
                        matrix[j][k].a = matrix[j][k] * someValue1;
                        break;
                case 1:
                        matrix[j][k].b = matrix[j][k] * someValue2;
                        break;   
                case 2:
                        matrix[j][k].c = matrix[j][k] * someValue3;                
                        break;
            }
        }
    }
}
  • 在我必須運行的測試中,HEIGHT和WIDTH通常是相同的大小。 一些測試示例是32x32和4096x4096。
  • 矩陣是具有屬性a,b和c的自定義結構的數組
  • someValue是雙精度型

我知道OpenMP並不總是適用於嵌套循環,但是歡迎任何幫助。

[更新]:

到目前為止,我已經嘗試展開循環。 它可以提高性能,但是我在這里增加了不必要的開銷嗎? 我在重用線程嗎? 我嘗試獲取每個for中使用的線程的ID,但沒有正確。

#pragma omp parallel
        {
#pragma omp for collapse(2)
            for (int j = 0; j < HEIGHT; ++j) {
                for (int k = 0; k < WIDTH; ++k) {
                    //my previous code here
                }
            }
#pragma omp for collapse(2)
            for (int j = 0; j < HEIGHT; ++j) {
                for (int k = 0; k < WIDTH; ++k) {
                    //my previous code here
                }
            }
#pragma omp for collapse(2)
            for (int j = 0; j < HEIGHT; ++j) {
                for (int k = 0; k < WIDTH; ++k) {
                    //my previous code here
                }
            }
        }

[更新2]

除了展開循環之外,我還嘗試並行化外循環(比展開最糟糕的性能提升)並折疊兩個內循環(與展開大致相同的性能提升)。 這是我得到的時代。

  • 序列號:〜130毫秒
  • 循環展開:〜49毫秒
  • 折疊兩個最里面的循環:〜55毫秒
  • 並行最外層循環:〜83毫秒

您認為最安全的選擇是什么? 我的意思是,通常對大多數系統而言,哪一個對我來說最好,而不僅僅是我的計算機?

您可能希望並行化for simd示例for simd以便編譯器可以向量化, collapse循環,因為僅在表達式matrix[j][k]使用jk ,並且不依賴於矩陣的任何其他元素。 如果什么都沒有修改somevalue1等,則它們應該是uniform 給循環計時,以確保它們確實可以提高速度。

OpenMP的問題在於它的級別很高 ,這意味着您無法訪問底層功能,例如生成線程,然后再使用它。 因此,讓我明確您可以做什么和不可以做什么:

假設您不需要任何互斥體來防止出現競爭情況 ,則可以選擇以下方法:

  1. 您並行化最外層的循環,這將使用3個線程,這是您將獲得的最和平的解決方案

  2. 您將第一個內部循環與之並行化,然后, 當為每個WIDTH元素生成一個新線程的開銷比執行最內部循環所需的工作量小得多時,性能才會提高。

  3. 並行化最內部的循環,但這是世界上最糟糕的解決方案,因為您將重新生成線程3 * HEIGHT次。 絕對不要那樣做!

  4. 不要使用OpenMP,而要使用低級的東西,例如std::thread ,您可以在其中創建自己的線程池,然后將要執行的所有操作放入隊列中。

希望這有助於將事情放在透視中。

這是另一種選擇,它認識到只有三個循環才能分配最外層循環的迭代,這可能會導致很差的負載平衡,

i=0
#pragma omp parallel for
for(int j = 0; j < HEIGHT; ++j){
    for(int k = 0; k < WIDTH; ++k){
    ...
}

i=1
#pragma omp parallel for
for(int j = 0; j < HEIGHT; ++j){
    for(int k = 0; k < WIDTH; ++k){
    ...
}

i=2
#pragma omp parallel for
for(int j = 0; j < HEIGHT; ++j){
    for(int k = 0; k < WIDTH; ++k){
    ...
}

警告-自己檢查語法,這僅是手動循環展開的草圖。

嘗試將其組合並折疊jk循環。

哦,不要抱怨代碼重復,您已經告訴我們您在性能改進方面得到了部分評分。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM