#c #debugging #mpi
#c #отладка #mpi
Вопрос:
Я запускаю программу в кластере Linux, используя MPICH2 1.0.6 (на самом деле я не могу обновить ее до MPICH3, поэтому я придерживаюсь этой версии), и без видимой причины программа не выполняется.
Я компилирую его с помощью mpicc -o prog prog.c -lm
и выполняю с mpiexec
Программа представляет собой реализацию алгоритма иерархической агломеративной кластеризации с использованием модели векторного пространства. Сбор данных представляет собой n*m
массив (в программе DOC*MAXWORDS
), который разделен на узлы кластера, как PARTS=DOC/procs
так что каждый узел отвечает за PARTS*MAXWORDS
данные.
Во время отладки на последовательной машине с использованием gdb и ddd я получаю, что программа имеет ошибку сегментации в определенной строке кода, где я не могу найти, что с ней не так. Взгляните.
while(iterations != DOC-k){//bigLoop
iterations ;
x=y=-1;
pos1=pos2=node1=node2=-1;
for(i=0;i<PARTS;i ){//ELEGXOS MEGISTOU TOPIKA
if(max_array[i]>x){
x=max_array[i];
pos1=i;
}
else if(max_array[i]==x){
pos2=i;
} //ELEGXOS META TO LOOP GIA OMOIOTHTES
}
if(max_array[pos1]!=max_array[pos2]){
for(i=0;i<PARTS;i ){
if(max_array[i]>max_array[pos2] amp;amp; i!=pos1)
pos2=1;
}
}
if(MPI_Allgather(amp;x,1,MPI_DOUBLE,
n_max,1,MPI_DOUBLE,MPI_COMM_WORLD) != MPI_SUCCESS) {
printf("Allgather high valuer - error");
exit(1);
}
for(i=0;i<procs;i ){
if(n_max[i]>y){
y=n_max[i];
node1=i;
}
else if(n_max[i]==y){
node2=i;
}
}
for(i=0;i<MAXWORDS;i ){
merger_one[i]=merger_two[i]=0;
}
if(n_max[node1]==n_max[node2]){
if(id==node1){
for(i=0;i<MAXWORDS;i ){
merger_one[i]=vector[node1*PARTS pos1][i];
last_one[i]=vector[(node1*PARTS) texts_vectors[node1]][i];
}
size_one=size_of[pos1];
nn_array[pos1]=nn_array[texts_vectors[node1]];
max_array[pos1]=max_array[texts_vectors[node1]];
size_of[pos1]=size_of[texts_vectors[node1]];
texts_vectors[node1]--;
}
if(id==node2){
for(i=0;i<MAXWORDS;i ){
merger_two[i]=vector[node2*PARTS pos2][i];
last_two[i]=vector[(node2*PARTS) texts_vectors[node2]][i];
}
j=pos2;
pos2=pos1;
pos1=j;
size_two=size_of[pos2];
nn_array[pos2]=nn_array[texts_vectors[node2]];
max_array[pos2]=max_array[texts_vectors[node2]];
size_of[pos2]=size_of[texts_vectors[node2]];
texts_vectors[node2]--;
}
}
else{
node2=node1;
if(id==node1){
for(i=0;i<MAXWORDS;i ){
merger_one[i]=vector[node1*PARTS pos1][i];
merger_two[i]=vector[node2*PARTS pos2][i];
last_one[i]=vector[(node1*PARTS) texts_vectors[node1]][i];/*SIGSEV ERROR*/
last_two[i]=vector[(node2*PARTS) texts_vectors[node2]-1][i];
}
size_one=size_of[pos1];
size_two=size_of[pos2];
nn_array[pos1]=nn_array[texts_vectors[node1]];
max_array[pos1]=max_array[texts_vectors[node1]];
size_of[pos1]=size_of[texts_vectors[node1]];
nn_array[pos2]=nn_array[texts_vectors[node2]-1];
max_array[pos2]=max_array[texts_vectors[node2]-1];
size_of[pos2]=size_of[texts_vectors[node2]-1];
texts_vectors[node1]=texts_vectors[node1]-2;
}
}
MPI_Bcast(amp;pos1, 1, MPI_INT,node1, MPI_COMM_WORLD);
MPI_Bcast(amp;pos2, 1, MPI_INT,node2, MPI_COMM_WORLD);
MPI_Bcast(amp;size_one, 1, MPI_INT,node1, MPI_COMM_WORLD);
MPI_Bcast(amp;size_two, 1, MPI_INT,node2, MPI_COMM_WORLD);
MPI_Bcast(merger_one, MAXWORDS, MPI_INT,node1, MPI_COMM_WORLD);
MPI_Bcast(merger_two, MAXWORDS, MPI_INT,node2, MPI_COMM_WORLD);
MPI_Bcast(last_one, MAXWORDS, MPI_INT,node1, MPI_COMM_WORLD);
MPI_Bcast(last_two, MAXWORDS, MPI_INT,node2, MPI_COMM_WORLD);
MPI_Allgather(amp;texts_vectors,1,MPI_INT,texts_vectors,1,MPI_INT,MPI_COMM_WORLD);
for(i=0;i<MAXWORDS;i ){
vector[node1*PARTS pos1][i]=last_one[i];
vector[node2*PARTS pos2][i]=last_two[i];
}
Pmanager=PARTS 1;
for(i=0;i<procs;i ){
if(texts_vectors[i]<Pmanager)
Pmanager=i;
}
texts_vectors[Pmanager] ;
for(i=0;i<MAXWORDS;i ){
x=merger_one[i]*size_one;
y=merger_two[i]*size_two;
vector[Pmanager*PARTS texts_vectors[Pmanager]][i]=(x y)/(size_one size_two);
}
for(i=id*PARTS; i< (id 1)*texts_vectors[id]; i ){
for(j=0;j<procs;j ){
for(m=j*PARTS;m<j*PARTS texts_vectors[j];m ){
x=0;y=0;z=0;
for(l=0; l < MAXWORDS; l ){
x =vector[i][l]*vector[m][l];
y =vector[i][l]*vector[i][l];
z =vector[m][l]*vector[m][l];
}
if(i!=m){
if(y!=0 amp;amp; z!=0){
sim_matrix[i-(PARTS*id)][m] = x / (sqrt(y) * sqrt(z) );
}
else{
sim_matrix[i-(PARTS*id)][m] = 0.0;
}
}
}
}
}
for(i=0; i<texts_vectors[id]; i ){
x=0.0;
for(j=0;j<DOC;j ){
if(sim_matrix[i][j]>x){
nn_array[i]=j;
max_array[i]=x=sim_matrix[i][j];
}
}
}
}
До этого происходит создание массивов и ввод данных в vector[i][j]
Я создал массивы с помощью malloc :
int **vector = malloc(DOC * sizeof *vector);
for (i = 0; i < DOC; i ){
vector[i] = malloc(MAXWORDS * sizeof **vector);
}
double **sim_matrix = malloc(PARTS * sizeof *sim_matrix);
for (i = 0; i < PARTS; i )
sim_matrix[i] = malloc(DOC * sizeof **sim_matrix);
int *list = malloc(WHOLE * sizeof(int));
int *nn_array = malloc(PARTS * sizeof(int));
double *max_array = malloc(PARTS * sizeof(double));
int *size_of = malloc(PARTS * sizeof(int));
double *n_max = malloc(procs * sizeof(double));
int *texts_vectors = malloc(procs * sizeof(int));
int *merger_one = malloc(MAXWORDS * sizeof(int));
int *merger_two = malloc(MAXWORDS * sizeof(int));
int *last_one = malloc(MAXWORDS * sizeof(int));
int *last_two = malloc(MAXWORDS * sizeof(int));
Строка, в которой проблема сохраняется: last_one[i]=vector[(node1*PARTS) texts_vectors[node1]][i];/*SIGSEV ERROR*/
также выполняется в первой части if-цикла if(n_max[node1]==n_max[node2]){
, но в этом случае ошибки нет.
Единственное, что вызывает некоторое подозрение в этой проблеме, — это texts_vectors[i]
массив, который продолжает подсчитывать количество данных vector[i][j]
типа, которые в данный момент находятся внутри узлов. Но даже с этим, я думаю, я справился.
Я действительно надеюсь, что кто-нибудь мог бы взглянуть на это, потому что это действительно расстраивает, и это нужно сделать.
Если у вас есть лучшее представление о том, что происходит, и вы хотите взглянуть на весь код, я вставил его в зону вставки. Приветствия и заранее спасибо.
Редактировать:
Как выясняется, значение, которое я передал с массивом, text_vectors
где-то превышает границы массива. Поскольку значение выдавало максимальное значение, для фактической последней позиции в массиве я должен вычесть 1. Итак, это было все, ошибка сегментации в последовательных gdb и ddd отсутствует. Однако эта программа теперь не запускается более чем на 2 узлах. Если я выполняю его в 4> узлах, происходит сбой.
Комментарии:
1. Я не уверен, что вы создаете
vector
иsim_matrix
правильно. Строки должны быть:int **vector = malloc(DOC * sizeof(int*));
иfor (i = 0; i < DOC; i ) vector[i] = malloc(MAXWORDS * sizeof(int);
, с соответствующим изменением, сделанным дляsim_matrix
строки. Если я правильно понимаю,vector
иsim_matrix
являются 2D массивами целых чисел и удвоений соответственно. По крайней мере дляsim_matrix
, указатели на удвоения (4 байта) и удвоения (8 байт) имеют разные размеры. Я не думаю, что это решит вашу проблему, но я кое с чем опаздываю, и я лучше рассмотрю ваш код позже.2. Я был бы признателен за это. Что касается распределения для массивов, я использовал этот способ в течение некоторого времени без каких-либо серьезных проблем. Я мог бы быстро изменить его и проверить. Спасибо за ваше время
3. О боже, извините за этот последний комментарий. Я только что понял, что вы разыменовываете, да, ничего плохого в способе создания двумерных массивов
4. Это чертовски много кода, и ваша ссылка для вставки скоро истечет. Это определенно противоречит хорошим способам задавать вопросы на SO.
Ответ №1:
В этой строке содержится несколько ошибок:
MPI_Allgather(amp;texts_vectors,1,MPI_INT,texts_vectors,1,MPI_INT,MPI_COMM_WORLD);
Во-первых, вы предоставляете указатель на указатель на данные в качестве первого аргумента операции сбора для всех. Следовательно, значение, передаваемое каждым рангом, является не первым элементом text_vectors
, а скорее адресом памяти данных (или нижней половиной адреса в 64-разрядных системах LP64 с младшим порядковым номером).
Во-вторых, если вы исправите это, удалив оператор address-off amp;
из начала первого аргумента, вы столкнетесь с другой проблемой. Стандарт MPI не допускает перекрытия буферов источника и назначения в MPI_Allgather
. Некоторые реализации MPI не обеспечивают соблюдения этого требования и автоматически выполняют правильные действия (TM). Некоторые другие реализации MPI попытаются скопировать данные с помощью memcpy
и столкнутся с проблемами с библиотекой C ( memcpy
не допускает перекрытия буферов). И, наконец, некоторые реализации MPI выдадут вам приятное сообщение об ошибке о перекрывающихся буферах и завершат работу вашей программы.
Поскольку вы отправляете один целочисленный элемент, просто скопируйте значение во временную переменную и используйте его адрес в качестве первого аргумента.
Комментарии:
1. Я использовал простое целое число для передачи значения, а также использовал `amp;texts_vectors[id] и по какой-то причине изменил его. Спасибо, что указали на это. Две пары глаз всегда лучше, чем одна. Ошибка все еще сохраняется, хотя
2.
amp;texts_vectors[id]
также неверно. Он по-прежнему указывает на местоположение, которое находится в буфере приема и которое запрещено стандартом MPI.MPI_Allgather
предоставляет специальный режим на месте, который следует использовать вместо этого — смотрите документацию (это из Open MPI, но применимо и к MPICH).3. Возможно, но для некоторых исполнений у меня это сработало. В любом случае, я использую переменную сейчас, но ошибка все еще там. Внутри
else-loop
иif(id==node1)
выражения. Я продолжаю получать ошибку сегментации.4. У вас это работает, потому что вы используете старую версию MPICH. Аналогичная проблема существует в одной из программ, включенных в спецификацию MPI2007, поэтому она не может запускаться в современных реализациях MPI или в современных системах Linux. В любом случае, вам, вероятно, следует использовать какой-нибудь параллельный отладчик, чтобы проверить, как работает ваш код (это возможно и при
printf
отладке).