MPI_Test没有获得完整的MPI_Send

时间:2014-11-11 17:28:08

标签: interrupt openmpi

我花了三天时间寻找答案,所以如果已经解决这个问题,我希望你能忍受我,并且我已经找到了解决方案。 我正在使用Fortran(eugh!)但这是一个通用的MPI查询。

场景(本例简化):

  • 进程0和1与进程2进行通信(但不是彼此进行通信)
  • 0& 1做很多发送/接收
  • 2会进行大量的接收/处理/发送(但每对完成两次以便 拿起0& 1)
  • 0& 1最终会停止 - 我不知道什么时候! - 所以我在适当时使用第3个进程的rank(filter_rank_id = 2)和特殊标记(c_tag_open_rcv = 200)从缓冲区(end_of_run)中使用逻辑TRUE进行MPI_Send。像这样:

CALL MPI_SEND(end_of_run, 1, MPI_LOGICAL, filter_rank_id, c_tag_open_rcv, mpi_coupling_comms, mpi_err)

问题出现在进程2中...它忙于执行MPI_Recv / MPI_Send对,我无法摆脱它。我为其他两个进程设置了一个非阻塞接收并存储了请求句柄:

    DO model_rank_id= 0, 1
        !Set up a non-blocking receive to get notification of end of model run for each model
        end_run = end_model_runs(model_rank_id) !this is an array of booleans initialised to FALSE
        CALL MPI_IRECV(end_run, 1, MPI_LOGICAL, model_rank_id, &
                       c_tag_open_rcv, coupling_comms, mpi_request_handle, mpi_err)
        !store the handle in an array
        request_handles(model_rank_id) = mpi_request_handle                
    END DO

其中model_rank_id是MPI通信器中的进程号,即0或1。

稍后,忙着做所有那些接收/发送对,我总是检查是否有任何东西到达缓冲区:

    DO model_rank_id= 0, 1
        IF (end_model_runs(model_rank_id) .EQV. .FALSE.) THEN
            CALL MPI_TEST(request_handles(model_rank_id), run_complete, mpi_status, mpi_err)
            IF (run_complete .eqv. .FALSE.) THEN
                !do stuff... receive/process/send
            ELSE
                !run is complete
                !___________removed this as I realised it was incorrect__________
                !get the stop flag for the specific process
                CALL MPI_RECV(end_run, 1, MPI_LOGICAL, model_rank_id, &
                                    c_tag_open_rcv, coupling_comms, mpi_err)
                !____________end_________________________________________________
                !store the stop flag so I can do a logical 'AND' on it and break out when
                !both processes have sent their message
                end_model_runs(model_rank_id) = end_run
            END IF
        END IF
    END DO

请注意,此代码段包含在循环中,该循环一直持续到所有停止标志为TRUE。

我知道它相当复杂,但这不是那么难,可以吗?如果有人能够看到错误的错误,甚至建议更好的方法来做到这一点。

提前非常感谢。

2 个答案:

答案 0 :(得分:0)

您的计划可能会停留在MPI_RECV来电。原因是MPI_TEST返回的肯定完成标记表示MPI_IRECV 已收到消息。除非发件人发送另一条带有相同标签的邮件,否则MPI_RECV只会阻止并等待,在您的情况下可能无限期。除此之外,您发出两个具有相同接收缓冲区的MPI_IRECV调用,这可能不是您真正想要做的,因为end_run = end_model_runs(model_rank_id)不会将数组元素的地址复制到end_run而是它的价值。

您的代码应如下所示:

DO model_rank_id= 0, 1
    !Set up a non-blocking receive to get notification of end of model run for each model
    CALL MPI_IRECV(end_model_runs(model_rank_id), 1, MPI_LOGICAL, model_rank_id, &
                   c_tag_open_rcv, coupling_comms, request_handle, ierr)
    !store the handle in an array
    request_handles(model_rank_id) = request_handle                
END DO

...

DO model_rank_id= 0, 1
    IF (end_model_runs(model_rank_id) .EQV. .FALSE.) THEN
        CALL MPI_TEST(request_handles(model_rank_id), run_complete, status, ierr)
        IF (run_complete .eqv. .FALSE.) THEN
            !do stuff... receive/process/send
        ELSE
            !run is complete
            !the stop flag is ALREADY in end_model_runs(model_rank_id)
            !do a logical 'AND' on it and break out when
        END IF
    END IF
END DO

作为旁注,使用您自己的以mpi_开头的标识符是个糟糕的主意,因为它们可能会与MPI库提供的符号发生冲突。您应该将mpi_视为保留前缀,并在命名自己的变量,子例程等时不要使用它。我已在上面的代码中为您修复了这个。

答案 1 :(得分:0)

经过大量的实验,我最终解决了这个问题,实际上很简单(不是一直都是这样吗?)

问题是由于流程0& 1可以结束并发布他们的“我已经完成”的消息OK,但是进程2处于如此紧密的循环中进行测试和recv / send对(为了清晰起见,在原始的过去中省略了两组send / recv的外部循环) ,测试将失败,并且该过程将粘在阻塞MPI_RECV

首先我尝试了睡眠(3)使其工作,但它无法在每个循环上睡觉而没有对性能产生真正的不良影响,然后我尝试了MPI_IPROBE但遇到与测试相同的问题。最后,围绕MPI_IPROBE的超时做了伎俩,因此:

        DO iter1 = 1, num_models

            !Test each model in turn and ensure we do the comms until it has finished
            IF (end_model_runs(iter1) .EQV. .FALSE.) THEN                        
                model_rank_id= models(iter1)
                now = TIME()
                DO WHILE (TIME() .LT. now + timeout)
                    msg_flag = .FALSE.
                    CALL MPI_IPROBE(model_rank_id, c_tag, coupling_comms, &
                                msg_flag, empi_status, empi_err)
                    IF (msg_flag .EQV. .TRUE.) THEN
                        !Message waiting
                        EXIT
                    END IF
                END DO

                IF (msg_flag .EQV. .TRUE.) THEN
                    CALL MPI_RECV(state_vector, num_state_params, MPI_DOUBLE_PRECISION, &
                                  model_rank_id, c_tag, coupling_comms, empi_status, empi_err)
                ELSE !no message waiting, flag should be False, i.e. the run *has* finished
                    end_model_runs(iter1) = .NOT. msg_flag
                END IF
            END IF
        END DO

这个代码在一个循环中,一旦end_model_runs的所有成员都是TRUE就会中断。

我希望这可以帮助别人 - 并为他们节省三天的努力!