![](/img/trans.png)
[英]incomprehensible performance improvement with openmp even when num_threads(1)
[英]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.