教堂中的正交递归对分(Barnes-Hut算法)

时间:2019-02-26 12:53:06

标签: parallel-processing chapel

我正在Chapel中实现Barnes-Hut n体仿真的分布式版本。我已经实现了GitHub上可用的顺序和共享内存版本。

我正在遵循here(第7章)中概述的算法:

  1. 执行正交递归二等分并分配主体,以使每个过程具有相同的工作量
  2. 在每个流程上构建本地必不可少的树
  3. 计算力量和前进力量

我对如何使用MPI_Allreduce进行二等分和在进程之间进行通信(用于主体传递)的简单消息传递实现C / MPI中的算法有一个很好的想法。而且MPI_Comm_split是一个非常方便的函数,它使我可以在ORB的每个步骤中拆分进程。

我在使用Chapel提供的并行/分布式结构执行ORB时遇到了一些麻烦。我需要某种方式来汇总(减少)跨流程(在Chapel中的语言环境)的工作,将流程分成组,并进行流程间的通信以转移主体。

对于在教堂中如何实施此建议,我将不胜感激。如果另一种方法对Chapel更好,那也将很棒。

1 个答案:

答案 0 :(得分:2)

在发生许多死锁和崩溃之后,我确实设法在Chapel中实现了该算法。可以在这里找到:https://github.com/novoselrok/parallel-algorithms/tree/75312981c4514b964d5efc59a45e5eb1b8bc41a6/nbody-bh/dm-chapel

我无法使用Chapel提供的许多 fancy 并行设备。我仅依靠带有sync元素的块分布式数组。我还复制了SPMD模型。

main.chpl中,我将设置用于传输数据的所有必要数组。每个数组都有一个对应的sync数组用于同步。然后,每个工人都从其身体份额和前面提到的阵列开始。 Worker.chpl包含大部分算法。

我用自定义功能MPI_Comm_split取代了determineGroupPartners功能,在这里我手动执行相同的操作。至于MPI_Allreduce,我发现了一个不错的小图案,可以在任何地方使用:

var localeSpace = {0..#numLocales};
var localeDomain = localeSpace dmapped Block(boundingBox=localeSpace);

var arr: [localeDomain] SomeType;
var arr$: [localeDomain] sync int; // stores the ranks of inteded receivers
var rank = here.id;

for i in 0..#numLocales-1 {
    var intendedReceiver = (rank + i + 1) % numLocales;
    var partner = ((rank - (i + 1)) + numLocales) % numLocales;

    // Wait until the previous value is read
    if (arr$[rank].isFull) {
        arr$[rank];
    }

    // Store my value
    arr[rank] = valueIWantToSend;
    arr$[rank] = intendedReceiver;

    // Am I the intended receiver?
    while (arr$[partner].readFF() != rank) {}

    // Read partner value
    var partnerValue = arr[partner];

    // Do something with partner value

    arr$[partner]; // empty

    // Reset write, which blocks until arr$[rank] is empty
    arr$[rank] = -1;
}

这是实现FIFO通道的一种较为复杂的方法(请参见Julia RemoteChannel,我从中获得了这种“模式”的灵感)。 概述:

  • 首先,每个语言环境都会计算其预期的接收方及其伙伴(该语言环境将从中读取值)

  • 语言环境检查是否读取了先前的值

  • 语言环境存储新值,并通过将arr$[rank]设置为目标接收者来“锁定”该值

  • 语言环境在其伙伴设置值并设置适当的预期接收者时等待

  • 一旦区域设置是预期的接收者,它将读取伙伴值并对其进行一些操作

  • 然后,区域设置通过读取arr$[partner]

  • 来清空/解锁值
  • 最后,它通过写入arr$[rank]重置其-1。这样,我们还可以确保由目标接收者读取由语言环境设置的值

我意识到,对于这个问题,这可能是一个过于复杂的解决方案。可能存在一种更适合Chapels并行计算全局视图的算法。我实现的算法适合SPMD计算模型。

话虽如此,我认为Chapel在性能方面仍然做得很好。 Here是针对Julia和C / MPI的性能基准。随着进程数量的增长,性能会提高很多。我没有机会在具有4个以上节点的集群上运行基准测试,但是我认为Chapel最终将获得可观的基准测试。