我目前正在研究一个C ++稀疏矩阵/数学/迭代求解器库,用于我管理的仿真工具。我宁愿使用现有的包装,但经过广泛的调查后,没有发现任何适合我们的模拟器(我们看过它们,它们是++,PetSC,eigen和其他几种)。好消息是我的求解器和稀疏矩阵结构现在非常高效和稳健。坏消息是,我现在正在研究使用OpenMP进行并行化,学习曲线有点陡峭。
我们解决的域可以分解为子域,这些子域以块对角格式组合在一起。因此,我们的存储方案最终看起来像一个较小的方形矩阵(块[])数组,每个矩阵具有适合于子域的格式(例如压缩行存储:CRS,压缩对角存储:CDS,密集等等),和背景矩阵(当前使用CRS),用于解释子域之间的连接。
大多数(全部?)迭代求解器中的“热点”是矩阵向量乘法运算,对于我的库来说也是如此。因此,我一直致力于优化我的MxV例程。对于块对角线结构,M * x = b的伪代码如下:
b=background_matrix*x
start_index = 1;
end_index = 0;
for(i=1:number of blocks) {
end_index=start_index+blocks[i].numRows();
b.range(start_index, end_index) += blocks[i] * x.range(start_index, end_index);
start_index = end_index+1;
}
其中background_matrix是背景(CRS)矩阵,blocks是子域矩阵的数组,而.range返回从起始索引到结束索引的向量部分。
显然,循环可以(并且已经)并行化,因为操作独立于循环的其他迭代(范围是非重叠的)。由于我们在典型系统中有10-15个块,因此4个线程实际上会产生显着差异。
并行化被认为是一个很好的选择的另一个地方是每个子域存储方案的MxV操作(在上面的代码中调用第1行和第6行)。有很多关于并行化CRS,CDS和密集矩阵MxV操作的东西。通常情况下,使用2个线程可以获得很好的提升,随着更多线程的添加,回报会大大减少。
我正在设想一个方案,其中4个线程将在块循环中用于上述代码,并且每个线程将使用2个线程用于子域求解。但是,我不确定如何使用OpenMP来管理线程池 - 是否可以限制openmp for循环中的线程数量?这种多层次的并行性在实践中是否有意义?关于我在这里建议的任何其他想法将不胜感激(并感谢阅读一直到最后!)
答案 0 :(得分:4)
请注意,我描述的所有内容都取决于实现。
是否可以限制openmp for循环中的线程数?
是。有不同的方法可以做到这一点。设置omp_set_nested(1);
并在内循环中使用类似#pragma omp parallel for num_threads(4)
或类似内容的内容和#pragma omp parallel for num_threads(2)
指令。这应该给你8个线程(取决于实现,如果你的内核少于8个,你可能还需要设置OMP_THREAD_LIMIT
)
或者,您可以手动展开循环,例如使用像
这样的东西#pragma omp parallel sections {
#pragma omp section
do your stuff for the first part, nest parallel region again
#pragma omp section
and so on for the other parts
}
您可以使用#pragma omp task
在OpenMP 3.0中更有效地执行相同的操作。
或者您启动8个线程并获取并行部分中的当前线程编号,并根据线程编号手动调度。
最后,如果你有一个完美的嵌套循环(循环完全嵌套,如果实际赋值只发生在最里面的循环中),你可以将所有内容重写为一个循环。基本上将两个迭代器i
和j
打包到一个大迭代器(i, j)
中。请注意,这可能会降低位置,从而降低性能
这种多层次的并行性在实践中是否有意义?
这取决于你必须找到自己。通常,多级并行性使您的问题更具可伸缩性。但是,调度可能更复杂。这个paper可能很有趣。
关于手动设置线程数:设置线程数的主要优点是您可以在计划时使用有关问题的特定知识。 因此,您可以减少开销并获得正在执行的代码的更高位置,从而实现更多缓存命中和更少的主内存I / O.
在嵌套并行性中手动设置线程数的主要缺点是最内层循环中的线程可能在隐式屏障上空闲等待,而另外的工作可以完成(example)。此外,粗粒度并行性不能很好地扩展。因此,如果您的外部循环在循环中具有非常不同的运行时,您希望更灵活地安排,而不是简单地分成4个线程。
任何其他想法
您是否考虑过使用SIMD进行MxV。根据架构,这可以提供2-4的加速。我很快就用谷歌搜索了presentation。
对于MxV,loop tiling,register and cache blocking和相关技术可以增加数据位置并减少其他问题,例如虚假分享。这个book,第11章(你可以预览它),可能会给你一些关于如何重组数据访问的其他想法。
答案 1 :(得分:0)
为什么不在OpenMP.org上询问专家