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

0

Я пытаюсь разбросать значения между процессами, принадлежащими группе гиперкубов (проект quicksort). В зависимости от количества процессов я либо создаю новый коммуникатор, исключая чрезмерные процессы, либо дублирую 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
    Я бы добавил проверку ошибок ко всем операциям, которые могут потерпеть неудачу, и кучу отладочных выводов (printf или аналогичных). Существует множество массивов, которые могут быть переполнены, если значения не соответствуют вашим ожиданиям или если операция не выполнена. Наличие нескольких процессов значительно затрудняет или делает невозможным отладку, читая код вручную.
Теги:
scatter
openmpi
scatterview

1 ответ

1
Лучший ответ

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

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

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

Другая ошибка - это код, который прерывает if (mpiWorldRank >= p) процессы: он должен читать 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_Scatter(v):

MPI_Scatterv(&values[0], ...);
  • 0
    Спасибо, это работает, и это было очень полезно!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню