Ошибка сегментирования MPI_Scatter

#c #sorting #parallel-processing #mpi

#c #сортировка #параллельная обработка #mpi

Вопрос:

Я работаю над программой параллельной сортировки для изучения MPI, и у меня возникли проблемы с MPI_Scatter. Каждый раз, когда я пытаюсь запустить, я получаю следующее:

 reading input
Scattering input
_pmii_daemon(SIGCHLD): [NID 00012] PE 0 exit signal Segmentation fault
[NID 00012] 2011-03-28 10:12:56 Apid 23655: initiated application termination
  

Общий взгляд на другие вопросы на самом деле не дал ответа на то, почему у меня возникают проблемы — массивы являются смежными, поэтому у меня не должно возникнуть проблем с несмежным доступом к памяти, и я передаю правильные указатели в правильном порядке. У кого-нибудь есть какие-нибудь идеи?

Исходный код приведен ниже — он указан для определенного числа, потому что я пока не хочу иметь дело с вводом переменных и размером ранга.

 #include <mpi.h>

#include <iostream>
using std::endl;

using std::cout;

#include <fstream>
using std::ifstream;
using std::ofstream;
#include <algorithm>
using std::sort;

#define SIZEOF_INPUT 10000000
#define NUMTHREADS 100
#define SIZEOF_SUBARRAY SIZEOF_INPUT/NUMTHREADS

int main(int argc, char** argv){
    MPI_Init(amp;argc, amp;argv);

    int input[SIZEOF_INPUT];
    int tempbuf[SIZEOF_SUBARRAY];

    int myRank;
    MPI_Comm_rank(MPI_COMM_WORLD, amp;myRank);

    /*
            Read input from file
    */
    if(myRank == 0){
            cout << "reading input" << endl;
            ifstream in(argv[1]);
            for(int i = 0; i < SIZEOF_INPUT;   i)
                    in >> input[i];
            cout << "Scattering input" << endl;
    }

    // Scatter, Sort, and Gather again    
    MPI_Scatter(input,SIZEOF_INPUT,MPI_INT,tempbuf,SIZEOF_SUBARRAY,MPI_INT,0,MPI_COMM_WORLD);
    cout << "Rank " << myRank << "Sorting" << endl;
    sort(tempbuf,tempbuf SIZEOF_SUBARRAY);
    MPI_Gather(tempbuf,SIZEOF_SUBARRAY,MPI_INT,input,SIZEOF_INPUT,MPI_INT,0,MPI_COMM_WORLD);

    if(myRank == 0){
            cout << "Sorting final output" << endl;
            // I'm doing a multi-queue merge here using tricky pointer games

            //list of iterators representing things in the queue
            int* iterators[NUMTHREADS];
            //The ends of those iterators
            int* ends[NUMTHREADS];

            //Set up iterators and ends
            for(int i = 0; i < NUMTHREADS;   i){
                    iterators[i] = input   (i*SIZEOF_SUBARRAY);
                    ends[i] = iterators[i]   SIZEOF_SUBARRAY;
            }

            ofstream out(argv[2]);
            int ULTRA_MAX = SIZEOF_INPUT   1;
            int* ULTRA_MAX_POINTER = amp;ULTRA_MAX;
            while(true){
                    int** curr_min = amp;ULTRA_MAX_POINTER;
                    for(int i = 0 ; i < NUMTHREADS;   i)
                            if(iterators[i] < ends[i] amp;amp; *iterators[i] < **curr_min)
                                    curr_min = amp;iterators[i];

                    if(curr_min == amp;ULTRA_MAX_POINTER) break;

                    out << **curr_min << endl;
                      (*curr_min);
            }
    }

    MPI_Finalize();
}
  

Буду признателен за любую помощь.
С уважением,
Зак

Комментарии:

1. Вроде как очевидно, но вы уверены, что запускаете такое же количество процессов, которое используете в коде?

2. @suszterpatt Да, я понимаю. Хорошая мысль, хотя

Ответ №1:

Хах! Мне потребовалось некоторое время, чтобы увидеть это.

Хитрость в том, что в MPI_Scatter количество отправлений — это количество, которое нужно отправить каждому процессу, а не общее количество. То же самое с gather; это сумма, которую нужно получить от каждого. То есть это похоже MPI_Scatterv на подсчеты; подсчет относится к каждому процессу, но в данном случае предполагается, что он одинаковый.

итак, это

 MPI_Scatter(input,SIZEOF_SUBARRAY,MPI_INT,tempbuf,SIZEOF_SUBARRAY,MPI_INT,0,MPI_COMM_WORLD);
cout << "Rank " << myRank << "Sorting" << endl;
MPI_Gather(tempbuf,SIZEOF_SUBARRAY,MPI_INT,input,SIZEOF_SUBARRAY,MPI_INT,0,MPI_COMM_WORLD);
  

у меня работает.

Кроме того, будьте осторожны с выделением таких больших массивов в стеке; я знаю, что это всего лишь пример проблемы, но для меня это сразу же вызвало сбои. Выполнение этого динамически

 int *input = new int[SIZEOF_INPUT];
int *tempbuf = new int[SIZEOF_SUBARRAY];
//....
delete [] input;
delete [] tempbuf;
  

решена эта проблема.

Комментарии:

1. Попробовал это — сработало отлично. Это также решило проблему, которая у меня возникла бы с MPI_Gather. Что касается больших массивов, я делаю это на компьютере Cray, поэтому с памятью проблем нет, но я приму к сведению для будущей работы. Большое спасибо!

Ответ №2:

 int* iterators[NUMTHREADS];
//The ends of those iterators
int* ends[NUMTHREADS];

//Set up iterators and ends
 for(int i = 0; i < NUMTHREADS;   i){
       iterators[i] = input   (i*SIZEOF_SUBARRAY); // problem
       ends[i] = iterators[i]   SIZEOF_SUBARRAY;   // problem
 }
  

Оба iterators and ends представляют собой массив целочисленных указателей, указывающих неизвестно куда, или мусор. Но в цикле for пытается сохранить значения так, как будто они указывают на некоторое местоположение, что приводит к ошибке сегментации. Программа должна должна сначала выделить память, на которую могут указывать итераторы, а затем сохранить значения в местах, указанных ими.

 for( int i=0 ; i < NUMTHREADS;   i )
{
     iterators[i] = new int; 
     end[i] = new int ; 
}
// Now do the earlier operation which caused problem
  

Поскольку программа управляет ресурсами (т. Е. полученными из new ), она должна возвращать ресурсы в бесплатное хранилище с помощью delete[] , когда они больше не нужны. Используйте std::vector вместо самостоятельного управления ресурсами, что очень просто.

Комментарии:

1. Ошибка сегмента в этом случае происходит в MPI_Scatter(), а не в этой строке. Кроме того, итераторы и окончания являются массивами указателей int, которые были выделены в стеке. Они начинаются с ненужных данных, но в последующем цикле for я присваиваю им указатели на фрагменты результирующего массива, предоставленные мне из MPI_Gather(). Это не ответ

2. @Zach H — Насколько я вижу в коде, оба iterator and ends являются неинициализированными массивами указателей на локальные переменные , объявленными в if инструкции.