我试图在我的内部循环中减少对 std::max 的调用次数,因为我调用它数百万次(毫不夸张!),这使得我的并行代码比顺序代码运行得慢。基本思想(是的,这是一个分配)是代码计算某个网格点的温度,一次又一次地迭代,直到最大变化不超过某个非常小的数字(例如 0.01)。新温度是其上方、下方和旁边的单元格中温度的平均值。结果,每个单元格都有不同的值,我想返回给定网格块的任何单元格中的最大变化。
我已经让代码工作了,但是速度很慢,因为我在内循环中对 std::max 进行了大量(过多)调用,而且它是 O(n*n)。我使用了一维域分解
注意: tdiff 不依赖于任何东西,只依赖于矩阵中的内容
归约函数的输入是 lambda 函数的结果
diff 是该网格块中单个单元格在 1 次迭代中的最大变化
阻塞范围在代码前面定义
t_new 是该网格点的新温度,t_old 是旧温度
max_diff = parallel_reduce(range, 0.0,
//lambda function returns local max
[&](blocked_range<size_t> range, double diff)-> double
{
for (size_t j = range.begin(); j<range.end(); j++)
{
for (size_t i = 1; i < n_x-1; i++)
{
t_new[j*n_x+i]=0.25*(t_old[j*n_x+i+1]+t_old[j*n_x+i-1]+t_old[(j+1)*n_x+i]+t_old[(j-1)*n_x+i]);
tdiff = fabs(t_old[j*n_x+i] - t_new[j*n_x+i]);
diff = std::max(diff, tdiff);
}
}
return diff; //return biggest value of tdiff for that iteration - once per 'i'
},
//reduction function - takes in all the max diffs for each iteration, picks the largest
[&](double a, double b)-> double
{
convergence = std::max(a,b);
return convergence;
}
);
如何让我的代码更有效率?我想减少对 std::max 的调用,但需要保持正确的值。使用 gprof 我得到:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
61.66 3.47 3.47 3330884 0.00 0.00 double const& std::max<double>(double const&, double const&)
38.03 5.61 2.14 5839 0.37 0.96 _ZZ4mainENKUlN3tbb13blocked_rangeImEEdE_clES1_d
ETA:执行我的代码所花费的时间中有 61.66% 是在 std::max 调用上,它调用了超过 300 万次。lambda函数的每个输出都会调用reduce函数,因此减少lambda函数中对std::max的调用次数也会减少对reduce函数的调用次数