我试图在程序的不同部分使用不同数量的线程来实现最大加速度。但是,发现使用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。
答案 0 :(得分: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节标题为“确定并行区域的线程数”,给出了确定线程数的算法。 The source code for GOMP_parallel from GCC-4.8表示它调用的第一个函数是gomp_resolve_num_threads
。