我正在学习openmp,使用通过quadature计算pi值的例子。在串行中,我运行以下C代码:
double serial() {
double step;
double x,pi,sum = 0.0;
step = 1.0 / (double) num_steps;
for (int i = 0; i < num_steps; i++) {
x = (i + 0.5) * step; // forward quadature
sum += 4.0 / (1.0 + x*x);
}
pi = step * sum;
return pi;
}
我将这与使用并行减少的omp实现进行比较:
double SPMD_for_reduction() {
double step;
double pi,sum = 0.0;
step = 1.0 / (double) num_steps;
#pragma omp parallel for reduction (+:sum)
for (int i = 0; i < num_steps; i++) {
double x = (i + 0.5) * step;
sum += 4.0 / (1.0 + x*x);
}
pi = step * sum;
return pi;
}
对于num_steps = 1,000,000,000,以及omp的6个线程,我编译和时间:
double start_time = omp_get_wtime();
serial();
double end_time = omp_get_wtime();
start_time = omp_get_wtime();
SPMD_for_reduction();
end_time = omp_get_wtime();
不使用cc编译器优化,运行时间约为4s(串行)和.66s(omp)。使用-O3标志,串行运行时将降至“.000001s”,并且omp运行时基本不变。这里发生了什么?是使用矢量指令,还是代码或定时方法不好?如果它是矢量化,为什么omp函数不会受益?
我正在使用的机器正在使用现代的6核Xeon处理器。
谢谢!
答案 0 :(得分:3)
编译器超出你的要求。对于串行版本,它能够检测到从未使用过计算结果。因此它完全抛弃了计算。
double start_time = omp_get_wtime();
serial(); //<-- Computations not used.
double end_time = omp_get_wtime();
在openMP的情况下,编译器无法看到函数体内是否真的没有效果,所以为了保持安全,它会保持函数调用。
你当然可以写一些像double serial_pi = serial();
这样的东西,并且在时间测量之外用变量serial_pi
做一些虚拟的东西。这样编译器将保持函数调用并执行您实际需要的优化。