MPI_Scatterv: ошибка сегментации 11 только для процесса 0

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

В обоих случаях процессы, отличные от 0, получают свои данные, но:
— В первом сценарии процесс 0 вызывает ошибку сегментации 11
— Во втором сценарии ничего не выходит из строя, но полученные значения процесса 0 являются бессмысленными.

ПРИМЕЧАНИЕ: если я попробую обычный MPI_Scatter, все будет хорошо.

//Input
vector<int> LoadFromFile();

int d;                      //dimension of hypercube
int p;                      //active processes
int idle;                   //idle processes
vector<int> values;         //values loaded
int arraySize;              //number of total values to distribute

int main(int argc, char* argv[])
{
int mpiWorldRank;
int mpiWorldSize;

int mpiRank;
int mpiSize;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &mpiWorldRank);
MPI_Comm_size(MPI_COMM_WORLD, &mpiWorldSize);
MPI_Comm MPI_COMM_HYPERCUBE;

d = log2(mpiWorldSize);
p = pow(2, d);                  //Number of processes belonging to the hypercube
idle = mpiWorldSize - p;        //number of processes in excess
int toExclude[idle];            //array of idle processes to exclude from communicator
int sendCounts[p];              //array of values sizes to be sent to processes

//
int i = 0;
while (i < idle)
{
toExclude[i] = mpiWorldSize - 1 - i;
++i;
}

//CREATING HYPERCUBE GROUP: Group of size of power of 2 -----------------
MPI_Group world_group;
MPI_Comm_group(MPI_COMM_WORLD, &world_group);

// Remove excessive processors if any from communicator
if (idle > 0)
{
MPI_Group newGroup;
MPI_Group_excl(world_group, 1, toExclude, &newGroup);
MPI_Comm_create(MPI_COMM_WORLD, newGroup, &MPI_COMM_HYPERCUBE);
//Abort any processor not part of the hypercube.
if (mpiWorldRank > p)
{
cout << "aborting: " << mpiWorldRank <<endl;
MPI_Finalize();
return 0;
}
}
else
{
MPI_Comm_dup(MPI_COMM_WORLD, &MPI_COMM_HYPERCUBE);
}

MPI_Comm_rank(MPI_COMM_HYPERCUBE, &mpiRank);
MPI_Comm_size(MPI_COMM_HYPERCUBE, &mpiSize);
//END OF: CREATING HYPERCUBE GROUP --------------------------

if (mpiRank == 0)
{
//STEP1: Read input
values = LoadFromFile();
arraySize = values.size();
}

//Transforming input vector into an array
int valuesArray[values.size()];
if(mpiRank == 0)
{
copy(values.begin(), values.end(), valuesArray);
}

//Broadcast input size to all processes
MPI_Bcast(&arraySize, 1, MPI_INT, 0, MPI_COMM_HYPERCUBE);

//MPI_Scatterv: determining size of arrays to be received and displacement
int nmin = arraySize / p;
int remainingData = arraySize % p;
int displs[p];
int recvCount;

int k = 0;
for (i=0; i<p; i++)
{
sendCounts[i] = i < remainingData
? nmin+1
: nmin;
displs[i] = k;
k += sendCounts[i];
}

recvCount = sendCounts[mpiRank];
int recvValues[recvCount];

//Following MPI_Scatter works well:
// MPI_Scatter(&valuesArray, 13, MPI_INT, recvValues , 13, MPI_INT, 0, MPI_COMM_HYPERCUBE);

MPI_Scatterv(&valuesArray, sendCounts, displs, MPI_INT, recvValues , recvCount, MPI_INT, 0, MPI_COMM_HYPERCUBE);

int j = 0;
while (j < recvCount)
{
cout << "rank " << mpiRank << " received: " << recvValues[j] << endl;
++j;
}

MPI_Finalize();
return 0;
}

0

Решение

Прежде всего, вы предоставляете неверные аргументы MPI_Group_excl:

MPI_Group_excl(world_group, 1, toExclude, &newGroup);
//                          ^

Второй аргумент указывает количество записей в списке исключений и поэтому должен быть равен idle, Поскольку вы исключаете только один ранг, результирующая группа имеет mpiWorldSize-1 ряды и, следовательно, MPI_Scatterv ожидает, что оба sendCounts[] а также displs[] есть так много элементов. Только из тех p элементы правильно инициализированы, а остальные случайны, поэтому MPI_Scatterv вылетает в корне.

Другая ошибка — код, который прерывает бездействующие процессы: он должен прочитать if (mpiWorldRank >= p),

Я бы порекомендовал заменить весь код исключения одним вызовом MPI_Comm_split вместо:

MPI_Comm comm_hypercube;
int colour = mpiWorldRank >= p ? MPI_UNDEFINED : 0;

MPI_Comm_split(MPI_COMM_WORLD, colour, mpiWorldRank, &comm_hypercube);
if (comm_hypercube == MPI_COMM_NULL)
{
MPI_Finalize();
return 0;
}

Когда нет процесса поставки MPI_UNDEFINED как его цвет, вызов эквивалентен MPI_Comm_dup,

Обратите внимание, что вы должны избегать использования в ваших кодовых именах, начинающихся с MPI_ поскольку те могли столкнуться с символами от реализации MPI.

Дополнительное примечание: std::vector<T> использует непрерывное хранилище, поэтому вы можете обойтись без копирования элементов в обычный массив и просто предоставить адрес первого элемента в вызове MPI_Scatter(v):

MPI_Scatterv(&values[0], ...);
1

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


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