Как я могу понять атрибут и кэширование в MPI? - PullRequest
0 голосов
/ 04 апреля 2020

Согласно официальной документации, кажется, что мы используем функцию атрибута и кэширования в MPI для более эффективной реализации коллективной операции связи, как в следующем примере.

#include "mpi.h"

static int gop_key = MPI_KEYVAL_INVALID;

typedef struct {
    int ref_count;
    // there should be other stuff that we want
} gop_stuff_type;

void Eifficient_Collective_OP(MPI_Comm comm, ...) {
    gop_stuff_type* gop_stuff;
    MPI_Group group;
    int foundFlag;

    MPI_Comm_group(comm, &group);

    if (gop_key == MPI_KEYVAL_INVALID) {
        // this is the first time we call this function
        if (!MPI_Comm_create_keyval(gop_stuff_copier, gop_stuff_destructor, &gop_key, (void *)0)) {
            // get the key while assigning its copy and delete callback behavior
        } else {
            MPI_Abort(comm, 99);
        }
    }

    MPI_Comm_get_attr(comm, gop_key, &gop_stuff, &foundflag);
    if (foundflag) {
        // this module has executed in this group before
        // we will use the cached information
    } else {
        // this is a group that we have not yet cached anything
        gop_stuff = (gop_stuff_type *)malloc(sizeof(gop_stuff_type));
        if (gop_stuff == nullptr) {
            // out of memory error
        }

        gop_stuff -> ref_count = 1;

        // fill in *gop_stuff with whatever we want

        // store gop_stuff as the attribute value
        MPI_Comm_set_attr(comm, gop_key, gop_stuff);
    }
    // in any case, use contents of *gop_stuff to do the global op

}

int gop_stuff_destructor(MPI_Comm comm, int keyval, void *gop_stuffp, void *extra) {
    gop_stuff_type *gop_stuff = (gop_stuff_type *)gop_stuffP;
    if (keyval != gop_key) {
        // programming error
    }

    gop_stuff -> ref_count -= 1;

    if (gop_stuff -> ref_count == 0) {
        free((void *)gop_stuff);
    }
    return MPI_SUCCESS;
}

int gop_stuff_copier(MPI_Comm comm, int keyval, void *extra, void *gop_stuff_inP, 
                    void *gop_stuff_outP, int *flag) {
    gop_stuff_type *gop_stuff_int = (gop_stuff_type *)gop_stuff_inP;
    gop_stuff_type **gop_stuff_out = (gop_stuff_type **)gop_stuff_outP;
    if (keyval != gop_key) {
        // programming error
    }

    gop_stuff_in -> ref_count += 1;
    *gop_stuff_out = gop_stuff_in;

    return MPI_SUCCESS;
}

В этом примере мы сначала проверяем значение gop_key, чтобы увидеть, если мы сначала вызываем эту функцию, а после этого мы создаем атрибут. У меня есть несколько вопросов:

  1. , почему мы можем реализовать коллективную операцию более эффективным образом?
  2. Какой атрибут я могу предоставить для моей коллективной работы? Например, я хочу вызвать API Allreduce nt MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm).
  3. Для gop_stuff_destructor мы просто проверяем ссылочный номер, как то, что мы имеем дело с общим указателем. Но какова функция gop_stuff_copier?

Большое вам спасибо!

...