#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
инструкции.