C MPI — Сбой без видимой причины — Программа получила сигнал SIGSEGV

#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 отладке).