Согласно официальной документации, кажется, что мы используем функцию атрибута и кэширования в 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
, чтобы увидеть, если мы сначала вызываем эту функцию, а после этого мы создаем атрибут. У меня есть несколько вопросов:
- , почему мы можем реализовать коллективную операцию более эффективным образом?
- Какой атрибут я могу предоставить для моей коллективной работы? Например, я хочу вызвать API Allreduce
nt MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
. - Для
gop_stuff_destructor
мы просто проверяем ссылочный номер, как то, что мы имеем дело с общим указателем. Но какова функция gop_stuff_copier
?
Большое вам спасибо!