MPI Spawn: корневой процесс не связывается с дочерними процессами - PullRequest
8 голосов
/ 02 апреля 2012

(вопрос для начинающих) Я пытаюсь динамически порождать процессы, используя MPI_Comm_Spawn, а затем транслировать сообщение дочерним процессам, но программа останавливается в трансляции от корневого процесса к дочерним процессам. Я следую за документацией http://www.mpi -forum.org / docs / docs.html , но не могу заставить ее работать. Кто-нибудь может мне помочь, пожалуйста?

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

int main(int argc, char *argv[])
{
    MPI_Init(&argc, &argv);
    MPI_Comm parentcomm;

    MPI_Comm_get_parent( &parentcomm );

    if (parentcomm == MPI_COMM_NULL) {
        MPI_Comm intercomm;
        MPI_Status status;
        char msg_rec[1024];
        char msg_send[1024];
        int size, i;

        int np = (argc > 0) ? atoi(argv[1]) : 3;

        printf("Spawner will spawn %d processes\n", np);
        MPI_Comm_spawn( argv[0], MPI_ARGV_NULL, np, MPI_INFO_NULL, 0, MPI_COMM_SELF, &intercomm, MPI_ERRCODES_IGNORE );
        MPI_Comm_size(intercomm, &size);

        sprintf(msg_send, "Hello!");
        printf("Spawner will broadcast '%s'\n", msg_send);
        MPI_Bcast( (void*)msg_send, 1024, MPI_CHAR, 0, intercomm);

        printf("Spawner will receive answers\n");
        for (i=0; i < size; i++) {
            MPI_Recv( (void*)msg_rec, 1024, MPI_CHAR, i, MPI_ANY_TAG, intercomm, &status);
            printf("Spawner received '%s' from rank %d\n", msg_rec, i);
        };       

    } else {
        int rank, size;
        char msg_rec[1024];
        char msg_send[1024];

        MPI_Comm_rank(parentcomm, &rank);
        MPI_Comm_size(parentcomm, &size);

        printf("  Rank %d ready\n", rank);

        MPI_Bcast( (void*)msg_rec, 1024, MPI_CHAR, 0, parentcomm);

        printf("  Rank %d received '%s' from broadcast!\n", rank, msg_rec);
        sprintf(msg_send, "Hi there from rank %d!\n", rank);
        MPI_Send( (void*)msg_send, 1024, MPI_CHAR, 0, rank, parentcomm);
    };
    MPI_Finalize();
    return 0;
};

Я не знаю, имеет ли это значение, но я использую Ubuntu 11.10 и Hidra Process Manager.

Ответы [ 3 ]

3 голосов
/ 21 августа 2012

Как отметил @suszterpatt, вы работаете с "Интеркоммуникатором" (не "Интракоммуникатором"). Зная это и глядя на MPI_Bcast , мы видим:

Если comm является интеркоммуникатором, то вызов включает все процессы в интеркоммуникаторе, но с одной группой (группа A), определяющей корневой процесс. Все процессы в другой группе (группа B) передают одно и то же значение в аргументе root, который является рангом корня в группе A. Корень передает значение MPI_ROOT в корне. Все остальные процессы в группе A передают значение MPI_PROC_NULL в корень. Данные передаются из корня всем процессам в группе B. Аргументы буфера приема процессов в группе B должны соответствовать аргументу буфера отправки корня.

Это означает, что вам нужно только заменить широковещательный вызов в родительском:

MPI_Bcast( (void*)msg_send, 1024, MPI_CHAR, MPI_ROOT, intercomm);

Несколько других ошибок:

  • Проверка количества аргументов должна быть argc > 1.
  • MPI_Comm_size(intercomm, &size) вернет 1. Вместо этого вы захотите использовать MPI_Comm_remote_size(intercomm, &size).
2 голосов
/ 21 августа 2013

Если вы не хотите иметь дело с интеркоммуникатором после того, как вы породили свои дочерние процессы, вы можете использовать MPI_Intercomm_merge для создания интракоммуникатора из вашего интеркоммуникатора. По сути, это будет выглядеть так:

Spawner:

MPI_Comm_spawn( argv[0], MPI_ARGV_NULL, np, MPI_INFO_NULL, 0, MPI_COMM_SELF, &intercomm, MPI_ERRCODES_IGNORE );
MPI_Intercomm_merge(intercomm, 0, &intracomm);

Spawnee:

MPI_Intercomm_merge(parentcomm, 1, &intracomm);

После этого вы можете продолжать использовать intracomm (или как вы хотите это называть), как если бы это был обычный внутриобщительный коммуникатор. В этом случае порождающие процессы будут иметь ранги низкого порядка, а новые процессы будут иметь более высокие ранги, но вы можете изменить это также со вторым аргументом.

0 голосов
/ 03 апреля 2012

Коллективные вызовы, такие как Bcast(), требуют наличия внутриобщинного коммуникатора: вы пытаетесь использовать интеркоммуникатор (как intercomm, так и parentcomm).Вам нужно будет использовать методы создания группы, чтобы определить группу, которая охватывает родительский процесс и все дочерние процессы, а затем создать новый внутрикоммуникатор для этой группы.

...