Что такое аргумент displs в MPI Scatterv?
Аргумент displs
из функции MPI_Scatterv()
называется "целочисленным массивом (размером группы длины). Запись i задает смещение (относительно sendbuf, из которого следует принимать исходящие данные для обработки i".
Предположим, что у меня есть sendcounts
аргумент
int sendcounts[7] = {3,3,3,3,4,4,4};
Я рассуждаю так, что массив displs
всегда должен начинаться со значения 0, так как смещение первой записи равно 0 относительно sendbuf
, поэтому в моем примере выше displs
должен выглядеть например:
int displs[7] = {0,3,6,9,13,17,21};
Верно ли это? Я знаю, что это тривиальный вопрос, но по какой-то причине сеть не помогает вообще. Там нет хороших примеров, поэтому мой вопрос.
2 ответа:
Да, смещения дают корневой информации информацию о том, какие элементы для отправки в конкретную задачу-смещение исходного элемента. Поэтому в большинстве простых случаев (например, вы используете
MPI_Scatter
, но подсчеты не делятся равномерно) это может быть немедленно вычислено из информации о подсчетах:Но это не обязательно должно быть так; единственное ограничение заключается в том, что данные, которые вы посылаете, не могут перекрываться. Вы также можете считать со спины:displs[0] = 0; // offsets into the global array for (size_t i=1; i<comsize; i++) displs[i] = displs[i-1] + counts[i-1];
displs[0] = globalsize - counts[0]; for (size_t i=1; i<comsize; i++) displs[i] = displs[i-1] - counts[i];
Или любой произвольный приказ будет работать, как хорошо.
И вообще вычисления могут быть более сложными, потому что типы буфера отправки и буфера приема должны бытьсогласованными , но не обязательно одинаковыми - вы часто получаете это, например, при отправке многомерных срезов массива.
В качестве примера простых случаев ниже приведены прямые и обратные случаи:
#include <iostream> #include <vector> #include "mpi.h" int main(int argc, char **argv) { const int root = 0; // the processor with the initial global data size_t globalsize; std::vector<char> global; // only root has this const size_t localsize = 2; // most ranks will have 2 items; one will have localsize+1 char local[localsize+2]; // everyone has this int mynum; // how many items MPI_Init(&argc, &argv); int comrank, comsize; MPI_Comm_rank(MPI_COMM_WORLD, &comrank); MPI_Comm_size(MPI_COMM_WORLD, &comsize); // initialize global vector if (comrank == root) { globalsize = comsize*localsize + 1; for (size_t i=0; i<globalsize; i++) global.push_back('a'+i); } // initialize local for (size_t i=0; i<localsize+1; i++) local[i] = '-'; local[localsize+1] = '\0'; int counts[comsize]; // how many pieces of data everyone has for (size_t i=0; i<comsize; i++) counts[i] = localsize; counts[comsize-1]++; mynum = counts[comrank]; int displs[comsize]; if (comrank == 0) std::cout << "In forward order" << std::endl; displs[0] = 0; // offsets into the global array for (size_t i=1; i<comsize; i++) displs[i] = displs[i-1] + counts[i-1]; MPI_Scatterv(global.data(), counts, displs, MPI_CHAR, // For root: proc i gets counts[i] MPI_CHARAs from displs[i] local, mynum, MPI_CHAR, // I'm receiving mynum MPI_CHARs into local */ root, MPI_COMM_WORLD); // Task (root, MPI_COMM_WORLD) is the root local[mynum] = '\0'; std::cout << comrank << " " << local << std::endl; std::cout.flush(); if (comrank == 0) std::cout << "In reverse order" << std::endl; displs[0] = globalsize - counts[0]; for (size_t i=1; i<comsize; i++) displs[i] = displs[i-1] - counts[i]; MPI_Scatterv(global.data(), counts, displs, MPI_CHAR, // For root: proc i gets counts[i] MPI_CHARAs from displs[i] local, mynum, MPI_CHAR, // I'm receiving mynum MPI_CHARs into local */ root, MPI_COMM_WORLD); // Task (root, MPI_COMM_WORLD) is the root local[mynum] = '\0'; std::cout << comrank << " " << local << std::endl; MPI_Finalize(); }
Бег дает:
In forward order 0 ab 1 cd 2 ef 3 ghi In reverse order 0 hi 1 fg 2 de 3 abc
Да, ваше рассуждение верно-длясмежных данных. Смысл параметра
displacements
вMPI_Scatterv
также состоит в том, чтобы разрешить шаговые данные, что означает наличие неиспользуемых пробелов памяти вsendbuf
между блоками.Вот примердля смежных данных . Официальная документация фактически содержит хорошие примерыдля пошаговых данных .