Что такое аргумент displs в MPI_Scatterv?

displs аргумент от MPI_Scatterv() Функция называется «целочисленным массивом (с размером группы длины). я указывает смещение (относительно 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};

Это верно? Я знаю, что это тривиальный вопрос, но по какой-то причине Интернет вообще не помогает. Там нет хороших примеров, поэтому мой вопрос.

3

Решение

Да, смещения дают корневую информацию информацию о том, какие элементы отправить для конкретной задачи — смещение исходного элемента. Так что в большинстве простых случаев (например, вы бы использовали 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
2

Другие решения

Да, ваши рассуждения верны — для смежный данные. Суть displacements параметр в MPI_Scatterv это также позволяет strided данные, означающие, что в sendbuf между кусками.

Вот пример для достоверных данных. Официальная документация на самом деле содержит хорошее примеры для полученных данных.

0

По вопросам рекламы [email protected]