簡體   English   中英

當num_threads變化時,OpenMP並行區域開銷增加

[英]OpenMP parallell region overhead increase when num_threads varies

我試圖在程序的不同部分使用不同數量的線程來實現最大加速。 但是,發現使用num_threads子句切換線程號會產生很大的開銷。 我正在尋找一個解釋,因為根據我的理解,線程池應始終包含給定數量的線程,無論調用的實際數量。 我也在尋找可能的解決方案。 謝謝。

示例代碼:

#include<cstdio>
#include<omp.h>

void omp_sum(int ntd) {
    int s = 0;
    #pragma omp parallel num_threads(ntd)
    {
        int i = omp_get_thread_num();
        #pragma omp atomic
        s += i;
    }
}   

int main()
{
    int N = 100;
    int NT1 = 6, NT2 = 12;
    double t;

    t = omp_get_wtime();
    for(int n=0;n<N;n++) {
        omp_sum(NT1);
    }
    printf("%lf\n", (omp_get_wtime() - t) * 1e6 );

    t = omp_get_wtime();
    for(int n=0;n<N;n++) {
        omp_sum(NT2);
    }
    printf("%lf\n", (omp_get_wtime() - t) * 1e6 );

    t = omp_get_wtime();
    for(int n=0;n<N;n++) {
        omp_sum(NT1);
        omp_sum(NT1);
    }
    printf("%lf\n", (omp_get_wtime() - t) * 1e6 );

    t = omp_get_wtime();
    for(int n=0;n<N;n++) {
        omp_sum(NT2);
        omp_sum(NT2);
    }
    printf("%lf\n", (omp_get_wtime() - t) * 1e6 );

    t = omp_get_wtime();
    for(int n=0;n<N;n++) {
        omp_sum(NT1);
        omp_sum(NT2);
    }
    printf("%lf\n", (omp_get_wtime() - t) * 1e6 );
}

樣本輸出(在我們中):

1034.069001
1058.620000
1034.572000
2210.681000
18234.355000

編輯 :運行代碼的工作站有2個六核Intel E5-2630L CPU,因此總共應該有12個硬件核心和24個超線程。 我正在使用Fedora 19和GCC 4.8.2。

我可以在我的四核系統/八超線程系統上用GCC 4.8(g ++ -O3 -fopenmp foo.cpp)重現你的結果。 我將N1更改為4,將N2更改為8。

你的函數omp_sum很簡單

pushq   %rbx    
movq    %rdi, %rbx
call    omp_get_thread_num
movq    (%rbx), %rdx
lock addl   %eax, (%rdx)
popq    %rbx
ret

這是循環的匯編代碼

for(int n=0;n<N;n++) {
    omp_sum(NT1);
    omp_sum(NT2);
}

.L10
leaq    32(%rsp), %rsi
xorl    %ecx, %ecx
movl    $4, %edx
movl    $_Z7omp_sumi._omp_fn.0, %edi
movl    $0, 28(%rsp)
movq    %rbx, 32(%rsp)
call    GOMP_parallel
leaq    32(%rsp), %rsi
xorl    %ecx, %ecx
movl    $8, %edx
movl    $_Z7omp_sumi._omp_fn.0, %edi
movl    $0, 28(%rsp)
movq    %rbx, 32(%rsp)
call    GOMP_parallel
subl    $1, %ebp
jne .L10

這幾乎與循環的組件相同

for(int n=0;n<N;n++) {
    omp_sum(NT2);
    omp_sum(NT2);
}

唯一的變化是movl $4, %edx而不是movl $8, %edx 因此很難看出導致問題的原因。 所有的魔法都發生在GOMP_parallel中。 我們必須查看GOMP_parallel的源代碼,但我的猜測是GOMP_parallel檢查並行調用中最后一次使用的線程數,如果新的並行調用使用不同數量的線程,則需要一些開銷。 這個開銷遠遠大於你的簡單功能。

但我不確定為什么這會成為一個問題。 在實踐中,使用這樣的短並行部分是沒有意義的(一個將並行化一個循環而N會更大),因此開銷不應該是問題。

編輯:標題為“確定並行區域的線程數”的OpenMP 3.1規范的第2.41節給出了確定線程數的算法。 來自GCC-4.8的GOMP_parallel的源代碼顯示它調用的第一個函數是gomp_resolve_num_threads

暫無
暫無

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

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