【问题标题】:MPI_Barrier doesn't seem to work, reordering printf (stdout) messages [duplicate]MPI_Barrier 似乎不起作用,重新排序 printf (stdout) 消息 [重复]
【发布时间】:2017-08-02 06:10:18
【问题描述】:

下面是一个非常基本的 MPI 程序

#include <mpi.h>
#include <stdio.h>

int main(int argc, char * argv[]) {
    int rank;
    int size;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    MPI_Barrier(MPI_COMM_WORLD);
    printf("Hello from %d\n", rank);
    MPI_Barrier(MPI_COMM_WORLD);
    printf("Goodbye from %d\n", rank);
    MPI_Barrier(MPI_COMM_WORLD);
    printf("Hello 2 from %d\n", rank);
    MPI_Barrier(MPI_COMM_WORLD);
    printf("Goodbye 2 from %d\n", rank);
    MPI_Finalize();
    return 0;
}

您会期望输出是(对于 2 个进程)

Hello from 0
Hello from 1
Goodbye from 1
Goodbye from 0
Hello 2 from 1
Hello 2 from 0
Goodbye 2 from 0
Goodbye 2 from 1

或类似的东西(问候和再见应该分组,但不能保证流程顺序)。

这是我的实际输出:

Hello from 0
Goodbye from 0
Hello 2 from 0
Goodbye 2 from 0
Hello from 1
Goodbye from 1
Hello 2 from 1
Goodbye 2 from 1

我是否从根本上误解了 MPI_Barrier 应该做什么?据我所知,如果我只使用一次,那么它会给我预期的结果,但除此之外,它似乎完全没有任何作用。

我知道之前有人问过很多类似的问题,但是我查看的问题中的提问者误解了 MPI_Barrier 的功能。

【问题讨论】:

  • @Zulan,我认为你是对的。我已将我的问题标记为重复。

标签: c mpi


【解决方案1】:

你好和再见应该分组

他们不应该,printf 函数内部有额外的(MPI 异步)缓冲,另一个缓冲是 stdout 从多个 MPI 进程收集到单个用户终端。

printf 只是打印到 libc (glibc) 的内存缓冲区中,有时会刷新到真实文件描述符(stdout;使用 fflush 刷新缓冲区);而fprintf(stderr,...) 的缓冲通常比stdout

远程任务由 mpirun/mpiexec 启动,通常使用 ssh 远程 shell,它执行 stdout/stderr 转发。 ssh(以及 TCP)将缓冲数据,当来自 ssh 的数据被 mpirun/mpiexec 或其他实体(多个数据流复用为一个)显示在您的终端时,可能会重新排序。

你得到的是第一个进程的 4 个字符串在其出口处被缓冲和刷新(所有字符串都打印到stdout,通常有几千字节的缓冲区);来自第二个进程的另外 4 个字符串也被缓冲直到退出。所有 4 个字符串都由 ssh 或其他启动方法作为单个“数据包”发送到您的控制台,并且您的控制台仅以某种顺序显示两个数据包,每个数据包 4 行,或者“4_lines_packet_from_id_0; 4_lines_packet_from_id_1;”或“4_lines_packet_from_id_1;4_lines_packet_from_id_0;”。

MPI_Barrier 应该做什么?

MPI_Barrier 同步部分代码,但它不能禁用 libc/glibc 打印和文件 I/O 功能中的任何缓冲,也不能禁用 ssh 或其他远程 shell。

如果您的所有进程都在具有同步系统时钟的机器上运行(它们将在您有单台机器时运行,并且应该在集群上有 ntpd 时运行),您可以将时间戳字段添加到每个 printf 到检查真实订单是否符合您的障碍(gettimeofday 查找当前时间,并且没有额外的缓冲)。即使printfssh 将重新排序消息,您也可以对带时间戳的输出进行排序。

#include <mpi.h>
#include <sys/time.h>
#include <stdio.h>

void print_timestamped_message(int mpi_rank, char *s);
{
    struct timeval now;
    gettimeofday(&now, NULL);
    printf("[%u.%06u](%d): %s\n", now.tv_sec, now.tv_usec, mpi_rank, s);
}

int main(int argc, char * argv[]) {
    int rank;
    int size;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    MPI_Barrier(MPI_COMM_WORLD);
    print_timestamped_message(rank, "First Hello");
    MPI_Barrier(MPI_COMM_WORLD);
    print_timestamped_message(rank, "First Goodbye");
    MPI_Barrier(MPI_COMM_WORLD);
    print_timestamped_message(rank, "Second Hello");
    MPI_Barrier(MPI_COMM_WORLD);
    print_timestamped_message(rank, "Second Goodbye");
    MPI_Finalize();
    return 0;
}

【讨论】:

  • 我不认为关于gettimeofday 的假设适用于许多分布式系统。 NTP 绝对不够准确。如果您必须进行排序,只需在每个屏障上增加一个计数器。
  • 祖蓝,Barrier 有多快,NTP 在典型集群中有多准确?
  • 屏障通常为 10-100 us (ieeexplore.ieee.org/document/5493494),NTP 在理想条件下大约有 1ms (eecis.udel.edu/~mills/exec.html)。
猜你喜欢
  • 2019-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-06
  • 2013-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多