科学计算中基于任务的共享内存并行库

计算科学 并行计算 软件 高性能计算 图书馆 多核
2021-12-23 05:43:34

近年来,出现了几个库/软件项目,它们提供了某种形式的通用数据驱动的共享内存并行性。

主要思想是,程序员不是编写显式线程代码,而是将他们的算法实现为相互依赖的任务,然后由共享内存机器上的通用中间件动态调度。

此类库的示例有:

  • QUARK:最初是为MAGMA并行线性代数库设计的,似乎也被用于并行快速多极方法

  • Cilk:最初是一个基于 MIT 的项目,现在由 Intel 支持,作为 C 语言/编译器扩展实现,用于Cilkchess计算机国际象棋软件,并在 FFTW 中进行实验

  • SMP 超标量:在巴塞罗那超级计算中心开发,在许多方面类似于 Cilk,基于#pragma扩展。

  • StarPU:基于类似库的“codelet”,可以在包括 GPU 在内的多种不同架构上编译和调度。

  • OpenMP 任务:从 3.0 版开始,OpenMP 引入了可以异步调度的“任务”(参见规范的第 2.7 节)。

  • 英特尔的线程构建块:使用 C++ 类创建和启动异步任务,请参阅教程的第 11 节。

  • OpenCL:支持多核上基于任务的并行性。

虽然有很多文献描述了这些库/语言扩展的内部工作以及它们对特定问题的应用,但我只遇到过很少的例子,它们在科学计算应用程序中被实际使用。

那么问题来了:有没有人知道科学计算代码使用这些库/语言扩展中的任何一个,或类似的,用于共享内存并行?

2个回答

deal.II在整个库中使用线程构建块,总的来说,我们对它相当满意。我们已经研究了一些替代方案,特别是 OpenMP,因为每个人似乎都在使用它来编写更简单的代码,但发现它们缺乏。特别是,OpenMP 有一个巨大的缺点,即它的任务模型不允许您获取您开始的任务的句柄,因此很难访问任务的状态(例如等待它完成)或返回值您在单独的任务上运行的功能。OpenMP 主要适用于并行化最内层的循环,但您可以通过并行化最外层的复杂循环来获得并行效率,而 OpenMP 不是这方面的工具,而 TBB 则相当适合。

在我看来,这些系统相对不成功,主要是由于以下原因。

  • 并行计算的幼稚观点是关于并行化计算(例如触发器),而不是暴露内存局部性和删除同步点。尽管某些问题(例如密集矩阵算法)仍然是 FP 限制的,但只有在仔细考虑了内存子系统并且大多数计算内核(尤其是在 PDE 世界中)对内存更敏感之后才会出现这种情况。工作队列倾向于交换内存位置以获得更好的触发器平衡和更多原子内存操作(由于通过队列同步)。
  • 依赖过度分解来实现动态负载平衡,而牺牲了强大的可扩展性。任务通常具有重叠的数据依赖关系(鬼值)。随着内部尺寸的缩小,鬼影/内部比率增加。即使这并不意味着多余的工作,它也意味着增加了内存移动。通过协作预取等方法可以显着降低内存带宽需求,其中多个线程通过软件预取它们的邻居共享一个 L1 或 L2 缓存(这隐含地保持线程组大致一致)。这与过度分解正好相反。
  • 不可预测的性能,主要是由于上述与内存相关的问题。
  • 缺乏对库友好的组件。这几乎可以概括为没有类似的 anMPI_Comm允许不同的库执行丰富的操作而不会发生冲突,以及在库之间传递上下文并恢复必要的属性。无论使用共享内存还是分布式内存,“通信器”提供的抽象对于库组合都很重要。