Простая попытка MPI_Scatter

Я только учусь OpenMPI. Попробовал простой MPI_Scatter пример:

#include <mpi.h>

using namespace std;

int main() {
int numProcs, rank;

MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);

int* data;
int num;

data = new int[5];
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 3;
data[4] = 4;
MPI_Scatter(data, 5, MPI_INT, &num, 5, MPI_INT, 0, MPI_COMM_WORLD);
cout << rank << " recieved " << num << endl;

MPI_Finalize();
return 0;
}

Но это не сработало, как ожидалось …

Я ожидал что-то вроде

0 received 0
1 received 1
2 received 2 ...

Но то, что я получил, было

32609 received
1761637486 received
1 received
33 received
1601007716 received

Что со странными рядами? Кажется, что-то связано с моим разбросом? Кроме того, почему sendcount а также recvcount тот же самый? Сначала я подумал, так как я разбрасываю 5 элементов на 5 процессоров, каждый получит 1? Так что я должен использовать:

MPI_Scatter(data, 5, MPI_INT, &num, 1, MPI_INT, 0, MPI_COMM_WORLD);

Но это дает ошибку:

[JM:2861] *** An error occurred in MPI_Scatter
[JM:2861] *** on communicator MPI_COMM_WORLD
[JM:2861] *** MPI_ERR_TRUNCATE: message truncated
[JM:2861] *** MPI_ERRORS_ARE_FATAL: your MPI job will now abort

Однако мне интересно, зачем мне нужно различать корневые и дочерние процессы? Похоже, в этом случае источник / root также получит копию? Другое дело, что другие процессы тоже будут разбегаться? Наверное, нет, но почему? Я думал, что все процессы будут запускать этот код, так как он не в типичном, если я вижу в программах MPI?

if (rank == xxx) {

ОБНОВИТЬ

Я заметил, что для запуска, отправки и получения буфер должен быть одинаковой длины … и данные должны быть объявлены следующим образом:

int data[5][5] = { {0}, {5}, {10}, {3}, {4} };

Заметьте, столбцы объявлены как длина 5, но я только инициализировал 1 значение? Что на самом деле здесь происходит? Этот код правильный? Предположим, я хочу, чтобы каждый процесс получал только 1 значение.

1

Решение

sendcount количество элементов, которые вы хотите отправить каждый процесс, а не количество элементов в буфере отправки. MPI_Scatter просто возьму sendcount * [количество процессов в коммуникаторе] элементов из буфера отправки из корневого процесса и его рассредоточение по всем процессам в коммуникаторе.

Таким образом, чтобы отправить 1 элемент каждому из процессов в коммуникаторе (предположим, что есть 5 процессов), установите sendcount а также recvcount быть 1.

MPI_Scatter(data, 1, MPI_INT, &num, 1, MPI_INT, 0, MPI_COMM_WORLD);

Существуют ограничения на возможные пары типов данных, и они такие же, как и для операций точка-точка. Карта типов recvtype должен быть совместим с картой типа sendtypeто есть они должны иметь один и тот же список базовых базовых типов данных. Также приемный буфер должен быть достаточно большим, чтобы содержать полученное сообщение (оно может быть больше, но не меньше). В большинстве простых случаев тип данных на отправляющей и получающей сторонах одинаков. Так sendcountrecvcount пара и sendtyperecvtype Пара обычно заканчивается тем же. Пример, в котором они могут различаться, — это когда пользователь использует типы данных с обеих сторон:

MPI_Datatype vec5int;

MPI_Type_contiguous(5, MPI_INT, &vec5int);
MPI_Type_commit(&vec5int);

MPI_Scatter(data, 5, MPI_INT, local_data, 1, vec5int, 0, MPI_COMM_WORLD);

Это работает, так как отправитель создает сообщения из 5 элементов типа MPI_INT в то время как каждый получатель интерпретирует сообщение как отдельный экземпляр 5-элементного целочисленного вектора.

(Обратите внимание, что вы указываете максимальное количество элементов, которые будут получены в MPI_Recv и полученная сумма может быть меньше, что может быть получено MPI_Get_count, Напротив, вы предоставляете ожидаемое количество элементов, которые будут получены в recvcount из MPI_Scatter поэтому ошибка будет выдана, если полученная длина сообщения не именно так так же, как и обещал.)

Возможно, вы уже знаете, что распечатка странного ранга вызвана повреждением стека, так как num может содержать только 1 int но 5 int получены в MPI_Scatter,

Однако мне интересно, зачем мне нужно различать корневые и дочерние процессы? Похоже, в этом случае источник / root также получит копию? Другое дело, что другие процессы тоже будут разбегаться? Наверное, нет, но почему? Я думал, что все процессы будут запускать этот код, так как он не в типичном, если я вижу в программах MPI?

В некоторых операциях, таких как Scatter и Gather, необходимо различать корень и другие процессы в коммуникаторе (они не являются дочерними процессами корня, поскольку они могут находиться на отдельном компьютере), поскольку это коллективное общение (групповое общение), но с одним источником / местом назначения. Поэтому один источник / назначение (нечетный) называется корневым. Всем процессам необходимо знать источник / назначение (корневой процесс), чтобы правильно настроить отправку и получение.

Корневой процесс, в случае Scatter, также получит часть данных (от себя), а в случае Gather также включит свои данные в окончательный результат. Для корневого процесса нет исключений, если не используются операции «на месте». Это также относится ко всем функциям коллективного общения.

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

Все процессы в коммуникаторе будут запускать функцию (попробуйте исключить один процесс в коммуникаторе, и вы получите тупик). Вы можете представить процессы на разных компьютерах, выполняющие один и тот же код вслепую. Однако, поскольку каждый из них может принадлежать к разной группе коммуникаторов и иметь разный ранг, функция будет работать по-разному. Каждый процесс знает, является ли он членом коммуникатора, и каждый знает свой ранг и может сравнивать его с рангом корневого процесса (если таковой имеется), чтобы они могли установить связь или выполнить дополнительные действия соответственно.

5

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

Других решений пока нет …

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