我如何确定 MPI_Barrier 动作正确?测试的方法是什么?
谢谢
3 回答
我认为要确保 MPI_Barrier 正常工作,您必须编写一个程序,保证工作和非工作障碍的行为不同。
我不认为@Neeraj 的回答一定会如此。如果屏障正常工作,则所有进程都将在写入第二个输出行之前写入它们的第一个输出行。但是,即使在没有障碍的情况下(或者如果您想这样想,障碍完全失效)也有可能发生这种情况。我的断言并不依赖于他建议的非常短的睡眠时间(5ms等级)。即使您假设进程等待(5s等级),在没有障碍的情况下,语句也可能以障碍强加的顺序出现。我不太可能授予您,但并非不可能,尤其是当您必须考虑 o/s 如何缓冲对 stdout 的多次写入时——您实际上可能正在测试该过程而不是障碍。 哦即使是最不准确的计算机时钟,您也会哭泣,这将导致进程 1 等待的时间比进程 2 等待的时间要少,以显示屏障的正确工作。 如果 o/s 抢占处理器 1(进程 1 试图在哪个进程上运行)持续 10 秒,则不会。
依赖板载时钟进行同步实际上降低了程序的确定性。所有处理器都有自己的时钟,硬件不保证它们都以完全相同的速率或完全相同的滴答长度进行滴答。
该测试也没有充分探索屏障的所有失效模式。充其量它只探索完全的失败;如果实现实际上是一个泄漏的屏障,那么偶尔会有一个进程在最后一个进程到达屏障之前通过怎么办?一个错误在程序中非常普遍。或者,屏障代码可能是 3 年前编写的,并且只有足够的内存来记录例如 2^12==4096 个进程的到来,而您将它放在具有 2^18 个处理器的全新机器上;屏障更像是堰而不是水坝。
直到现在我还没有深入思考过这个问题,我从来没有怀疑过我使用的任何 MPI 实现都有错误的屏障,所以我没有关于如何彻底测试屏障的好建议。我倾向于使用并行调试器并通过屏障检查程序的执行,但这并不能保证正确的行为。
这是一个有趣的问题。
Allen Downey 在他的书The Little Book of Semaphores 中这样说(关于他提出的可重用屏障算法):
不幸的是,这个解决方案是大多数非平凡同步代码的典型:很难确定一个解决方案是正确的。通常,通过程序的特定路径可能会以一种微妙的方式导致错误。
更糟糕的是,测试解决方案的实现并没有多大帮助。该错误可能很少发生,因为导致它的特定路径可能需要非常不幸的环境组合。此类错误几乎不可能通过常规方式重现和调试。
唯一的选择是仔细检查代码并“证明”它是正确的。我将“证明”放在引号中,因为我并不一定意味着您必须编写正式的证明(尽管有些狂热者鼓励这种疯狂)。
#include <mpi.h>
int main (int argc , char *argv[])
{
int rank;
MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
sleep(5*rank); // make sure each process waits for different amount of time
std::cout << "Synchronization point for:" << rank << std::endl ;
MPI_Barrier(MPI_COMM_WORLD) ;
std::cout << "After Synchronization, id:" << rank << std::endl ;
MPI_Finalize();
return 0;
}