В MPI я выполняю операцию уменьшения (минимум) значения. Это прекрасно работает, но как мне получить номер процессора, из которого получен минимум, и запросить у этого процессора дополнительную информацию (или отправить дополнительные данные с помощью операции сокращения)?
MPI Получить процессор с минимальным значением
Ответы (1)
Если вы не возражаете против локального сопоставления каждого значения с целочисленным индексом (в данном случае заполненным значением локального ранга), вы можете использовать MPI_MINLOC или MPI_MAXLOC встроенные операции для сокращения; или довольно легко написать свой собственный оператор сокращения MPI, включающий такие вещи, как несколько индексов и т. д.
Добавлено добавление: со встроенными операторами MINLOC или MAXLOC вместо передачи одного значения для поиска минимума вы передаете его плюс целочисленный индекс. Этот индекс может иметь любое значение, которое вы хотите, но он «следует» за другим значением. MPI имеет встроенные "парные" типы данных - MPI_DOUBLE_INT для двойного числа + целое число или MPI_2INT для двух целых чисел, которые вы можете использовать.
Допустим, вы хотите найти минимум целочисленного массива и в какой задаче MPI он находится. Как обычно, вы находите свой локальный минимум для каждой задачи и выполняете сокращение; но на этот раз вы также соединяете его с целым числом, в данном случае с вашим рангом:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc, char **argv) {
int rank, size;
const int locn=5;
int localarr[locn];
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
srand(rank);
for (int i=0; i<locn; i++)
localarr[i] = rand() % 100;
for (int proc=0; proc<size; proc++) {
if (rank == proc) {
printf("Rank %2d has values: ",rank);
for (int i=0; i<locn; i++)
printf(" %d ", localarr[i]);
printf("\n");
}
MPI_Barrier(MPI_COMM_WORLD);
}
int localres[2];
int globalres[2];
localres[0] = localarr[0];
for (int i=1; i<locn; i++)
if (localarr[i] < localres[0]) localres[0] = localarr[i];
localres[1] = rank;
MPI_Allreduce(localres, globalres, 1, MPI_2INT, MPI_MINLOC, MPI_COMM_WORLD);
if (rank == 0) {
printf("Rank %d has lowest value of %d\n", globalres[1], globalres[0]);
}
MPI_Finalize();
return 0;
}
И запустив вы получите:
$ mpirun -np 5 ./minloc
Rank 0 has values: 83 86 77 15 93
Rank 1 has values: 83 86 77 15 93
Rank 2 has values: 90 19 88 75 61
Rank 3 has values: 46 85 68 40 25
Rank 4 has values: 1 83 74 26 63
Rank 4 has lowest value of 1
Если значение, которое вы уменьшаете, не является целым числом (скажем, двойным), вы создаете структуру, содержащую значение сокращения и целочисленный индекс, и используете соответствующий тип данных пары MPI. (например, MPI_DOUBLE_INT).
Далее обновлено: Хорошо, просто для удовольствия, проделав это с нашей собственной операцией редукции и нашим собственным типом для реализации двух индексов:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
typedef struct dbl_twoindex_struct {
double val;
int rank;
int posn;
} dbl_twoindex;
void minloc_dbl_twoindex(void *in, void *inout, int *len, MPI_Datatype *type){
/* ignore type, just trust that it's our dbl_twoindex type */
dbl_twoindex *invals = in;
dbl_twoindex *inoutvals = inout;
for (int i=0; i<*len; i++) {
if (invals[i].val < inoutvals[i].val) {
inoutvals[i].val = invals[i].val;
inoutvals[i].rank = invals[i].rank;
inoutvals[i].posn = invals[i].posn;
}
}
return;
}
int main(int argc, char **argv) {
int rank, size;
const int locn=5;
double localarr[locn];
dbl_twoindex local, global;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
/* create our new data type */
MPI_Datatype mpi_dbl_twoindex;
MPI_Datatype types[3] = { MPI_DOUBLE, MPI_INT, MPI_INT };
MPI_Aint disps[3] = { offsetof(dbl_twoindex, val),
offsetof(dbl_twoindex, rank),
offsetof(dbl_twoindex, posn), };
int lens[3] = {1,1,1};
MPI_Type_create_struct(3, lens, disps, types, &mpi_dbl_twoindex);
MPI_Type_commit(&mpi_dbl_twoindex);
/* create our operator */
MPI_Op mpi_minloc_dbl_twoindex;
MPI_Op_create(minloc_dbl_twoindex, 1, &mpi_minloc_dbl_twoindex);
srand(rank);
for (int i=0; i<locn; i++)
localarr[i] = 1.*rand()/RAND_MAX;
for (int proc=0; proc<size; proc++) {
if (rank == proc) {
printf("Rank %2d has values: ",rank);
for (int i=0; i<locn; i++)
printf(" %8.4lf ", localarr[i]);
printf("\n");
}
MPI_Barrier(MPI_COMM_WORLD);
}
local.val = localarr[0];
local.posn = 0;
for (int i=1; i<locn; i++)
if (localarr[i] < local.val) {
local.val = localarr[i];
local.posn = i;
}
local.rank = rank;
MPI_Allreduce(&local, &global, 1, mpi_dbl_twoindex, mpi_minloc_dbl_twoindex, MPI_COMM_WORLD);
if (rank == 0) {
printf("Rank %d has lowest value of %8.4lf in position %d.\n", global.rank, global.val, global.posn);
}
MPI_Op_free(&mpi_minloc_dbl_twoindex);
MPI_Type_free(&mpi_dbl_twoindex);
MPI_Finalize();
return 0;
}
Бег дает
$ mpirun -np 5 ./minloc2
Rank 0 has values: 0.8402 0.3944 0.7831 0.7984 0.9116
Rank 1 has values: 0.8402 0.3944 0.7831 0.7984 0.9116
Rank 2 has values: 0.7010 0.8097 0.0888 0.1215 0.3483
Rank 3 has values: 0.5614 0.2250 0.3931 0.4439 0.2850
Rank 4 has values: 0.9165 0.1340 0.1912 0.2601 0.2143
Rank 2 has lowest value of 0.0888 in position 2.
void*
к dbl_twoindex*
без приведения?
- person SAAD; 09.05.2014