Еквивалентно на MPI_Reduce_scatter, но разпръскване сред подмножество от процесори

Има ли MPI функция, еквивалентна на MPI_Reduce_scatter, която извършва разпръскването само между подгрупа от процесори? В случай че няма такава функция, коя е най-ефективната последователност от MPI извиквания?


За по-голяма яснота да предположим, че операцията за намаляване е сумата. от

proc    sendbuf
1       a1 | b1
2       a2 | b2
3       a3 | b3
4       a4 | b4 

искам да получа

proc    recvbuf
1       a
2       b
3       
4       

Където a = a1 + a2 + a3 + a4 и b = b1 + b2 + b3 + b4.


Заобиколни решения

  • Използване на две MPI_Reduce. Първият намалява as и има 1 като основен процесор. Вторият намалява bs и има 2 като основен процесор. Става тежко обаче, когато има много "букви" (и много процесори).
  • MPI_Reduce_scatter и задайте recv_count[proc] различно от нула само ако proc принадлежи към подгрупата от процесори. Въпреки това, при разпръскване на съобщението ще има n_proc квадратни ръкостискания (повечето от тях са безполезни, защото всъщност не се изпраща съобщение).

mpi
person dPol    schedule 18.06.2014    source източник


Отговори (2)


Съгласен съм, че две MPI_REDUCE повиквания вероятно са толкова добри, колкото ще получите, ако искате MPI да направи намаляването вместо вас (което вероятно правите в мащаб).

person Wesley Bland    schedule 19.06.2014
comment
Можете ли да коментирате и второто ми предположение? - person dPol; 19.06.2014
comment
ах Това е по-добрият начин да го направите. Забравих за този. - person Wesley Bland; 19.06.2014

Може да прекалявате с това - в случая по-горе можете да го направите с едно намаление и една двойка изпращане/приемане:

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

int main(int argc, char **argv) {

    int data[2], result[2];
    int rank, size;
    const int amaster=0, bmaster=1;

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

    data[0] = 2*rank;
    data[1] = 3*rank;

    MPI_Reduce(data, result, 2, MPI_INT, MPI_SUM, amaster, MPI_COMM_WORLD);
    if (rank == amaster) {
        int tota = result[0];
        printf("%d: Total a = %d, expected = %d\n", rank, tota, 2*size*(size-1)/2);
        MPI_Send(&(result[1]), 1, MPI_INT, bmaster, 0, MPI_COMM_WORLD);
    }
    if (rank == bmaster) {
        int totb;
        MPI_Recv(&totb, 1, MPI_INT, amaster, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        printf("%d: Total b = %d, expected = %d\n", rank, totb, 3*size*(size-1)/2);
    }

    MPI_Finalize();
    return 0;
}

И естественото обобщение за множество части от данни е разсейването, така че вашата интуиция за MPI_Reduce_scatter е правилна, но тук, тъй като двете групи задачи се припокриват (така че не можете да използвате интеркомуникатор), но не са еднакви, ще имате за да направите намаление, последвано от скатер, като скатерът ще трябва да бъде на друг комуникатор:

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

int main(int argc, char **argv) {

    const int ndata = 5;
    int data[ndata], result[ndata];
    int rank, size;
    const int amaster=0;
    MPI_Comm  scattercomm;

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

    if (size < ndata) {
        if (rank == 0) fprintf(stderr,"Too few ranks; exiting\n");
        MPI_Abort(MPI_COMM_WORLD,1);
    }

    for (int i=0; i<ndata; i++)
        data[i] = (i+2)*rank;

    /* create scatter communicator; all  of comm world must participate */
    MPI_Group basegrp, scattergrp;

    MPI_Comm_group(MPI_COMM_WORLD, &basegrp);

    int mpiranks[ndata];
    for (int i=0; i<ndata; i++)
        mpiranks[i] = i;

    MPI_Group_incl(basegrp, ndata, mpiranks, &scattergrp);
    MPI_Comm_create(MPI_COMM_WORLD, scattergrp, &scattercomm);

    MPI_Reduce(data, result, ndata, MPI_INT, MPI_SUM, amaster, MPI_COMM_WORLD);
    if (rank < ndata) {
        int item;
        MPI_Scatter(result, 1, MPI_INT, &item, 1, MPI_INT, amaster, scattercomm);

        printf("%d: Total = %d, expected = %d\n", rank, item, (rank+2)*size*(size-1)/2);
    }

    MPI_Finalize();
    return 0;
}
person Jonathan Dursi    schedule 19.06.2014