Ошибка сегментации после разброса

     /**
     * BLOCK_LOW
     * Returns the offset of a local array
     * with regards to block decomposition
     * of a global array.
     *
     * @param  (int) process rank
     * @param  (int) total number of processes
     * @param  (int) size of global array
     * @return (int) offset of local array in global array
     */
    #define BLOCK_LOW(id, p, n) ((id)*(n)/(p))

    /**
     * BLOCK_HIGH
     * Returns the index immediately after the
     * end of a local array with regards to
     * block decomposition of a global array.
     *
     * @param  (int) process rank
     * @param  (int) total number of processes
     * @param  (int) size of global array
     * @return (int) offset after end of local array
     */
    #define BLOCK_HIGH(id, p, n) (BLOCK_LOW((id)+1, (p), (n)))

    /**
     * BLOCK_SIZE
     * Returns the size of a local array
     * with regards to block decomposition
     * of a global array.
     *
     * @param  (int) process rank
     * @param  (int) total number of processes
     * @param  (int) size of global array
     * @return (int) size of local array
     */
    #define BLOCK_SIZE(id, p, n) ((BLOCK_HIGH((id), (p), (n))) - (BLOCK_LOW((id), (p), (n))))

    /**
     * BLOCK_OWNER
     * Returns the rank of the process that
     * handles a certain local array with
     * regards to block decomposition of a
     * global array.
     *
     * @param  (int) index in global array
     * @param  (int) total number of processes
     * @param  (int) size of global array
     * @return (int) rank of process that handles index
     */
    #define BLOCK_OWNER(i, p, n) (((p)*((i)+1)-1)/(n))



    /*Matricefilenames:
      small matrix A.bin of dimension 100 × 50
      small matrix B.bin of dimension 50 × 100
      large matrix A.bin of dimension 1000 × 500
      large matrix B.bin of dimension 500 × 1000

    An MPI program should be implemented such that it can
    • accept two file names at run-time,
    • let process 0 read the A and B matrices from the two data files,
    • let process 0 distribute the pieces of A and B to all the other processes,
    • involve all the processes to carry out the the chosen parallel algorithm
    for matrix multiplication C = A * B ,
    • let process 0 gather, from all the other processes, the different pieces
    of C ,
    • let process 0 write out the entire C matrix to a data file.
    */


    #include <stdio.h>
    #include <stdlib.h>
    #include <mpi.h>
    #include "mpi-utils.c"
    void read_matrix_binaryformat (char*, double***, int*, int*);
    void write_matrix_binaryformat (char*, double**, int, int);
    void create_matrix (double***,int,int);
    void matrix_multiplication (double ***, double ***, double ***,int,int, int);

    int main(int argc, char *argv[]) {
        int id,p; // Process rank and total amount of processes
        int rowsA, colsA, rowsB, colsB; // Matrix dimensions
        double **A; // Matrix A
        double **B; // Matrix B
        double **C; // Result matrix C : AB
        int local_rows; // Local row dimension of the matrix A
        double **local_A; // The local A matrix
        double **local_C;  // The local C matrix

        MPI_Init (&argc, &argv);
        MPI_Comm_rank (MPI_COMM_WORLD, &id);
        MPI_Comm_size (MPI_COMM_WORLD, &p);

        if(argc != 3) {
            if(id == 0) {
                printf("Usage:\n>> %s matrix_A matrix_B\n",argv[0]);
            }       
            MPI_Finalize();
            exit(1);
        }

        if (id == 0) {
            read_matrix_binaryformat (argv[1], &A, &rowsA, &colsA);
            read_matrix_binaryformat (argv[2], &B, &rowsB, &colsB);
        }

        if (p == 1) {
            create_matrix(&C,rowsA,colsB);
            matrix_multiplication (&A,&B,&C,rowsA,colsB,colsA);

            char* filename = "matrix_C.bin";
            write_matrix_binaryformat (filename, C, rowsA, colsB);
            free(A);
            free(B);
            free(C);
            MPI_Finalize();
            return 0;
        }


        // For this assignment we have chosen to bcast the whole matrix B:
        MPI_Bcast (&B, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); 
        MPI_Bcast (&colsA, 1, MPI_INT, 0, MPI_COMM_WORLD);
        MPI_Bcast (&colsB, 1, MPI_INT, 0, MPI_COMM_WORLD);
        MPI_Bcast (&rowsA, 1, MPI_INT, 0, MPI_COMM_WORLD);
        MPI_Bcast (&rowsB, 1, MPI_INT, 0, MPI_COMM_WORLD);

        local_rows = BLOCK_SIZE(id, p, rowsA);


        /*    SCATTER VALUES    */

        int *proc_elements = (int*)malloc(p*sizeof(int)); // amount of elements for each processor
        int *displace = (int*)malloc(p*sizeof(int)); // displacement of elements for each processor
        int i;
        for (i = 0; i<p; i++) {
            proc_elements[i] = BLOCK_SIZE(i, p, rowsA)*colsA;
            displace[i] = BLOCK_LOW(i, p, rowsA)*colsA;
        }

        create_matrix(&local_A,local_rows,colsA);

        MPI_Scatterv(&A[0],&proc_elements[0],&displace[0],MPI_DOUBLE,&local_A[0],
                     local_rows*colsA,MPI_DOUBLE,0,MPI_COMM_WORLD);

        /*    END  SCATTER  VALUES  */  

        create_matrix (&local_C,local_rows,colsB);
        matrix_multiplication (&local_A,&B,&local_C,local_rows,colsB,colsA);

        /*    GATHER VALUES    */

        MPI_Gatherv(&local_C[0], rowsA*colsB, MPI_DOUBLE,&C[0],
              &proc_elements[0],&displace[0],MPI_DOUBLE,0, MPI_COMM_WORLD);

        /*    END  GATHER VALUES  */

        char* filename = "matrix_C.bin";
        write_matrix_binaryformat (filename, C, rowsA, colsB);  

        free (proc_elements);
        free (displace);    
        free (local_A);
        free (local_C);
        free (A);
        free (B);
        free (C);   
        MPI_Finalize ();
        return 0;
    }

    void create_matrix (double ***C,int rows,int cols) {
        *C = (double**)malloc(rows*sizeof(double*));
        (*C)[0] = (double*)malloc(rows*cols*sizeof(double));
        int i;
        for (i=1; i<rows; i++)
            (*C)[i] = (*C)[i-1] + cols;
    }

    void matrix_multiplication (double ***A, double ***B, double ***C, int rowsC,int colsC,int colsA) {
        double sum;
        int i,j,k;
        for (i = 0; i < rowsC; i++) {
            for (j = 0; j < colsC; j++) {
                sum = 0.0;
                for (k = 0; k < colsA; k++) {
                    sum = sum + (*A)[i][k]*(*B)[k][j];
                }
                (*C)[i][j] = sum;
            }
        }
    }

    /* Reads a 2D array from a binary file*/ 
    void read_matrix_binaryformat (char* filename, double*** matrix, int* num_rows, int* num_cols) {
        int i;
        FILE* fp = fopen (filename,"rb");
        fread (num_rows, sizeof(int), 1, fp);
        fread (num_cols, sizeof(int), 1, fp);
        /* storage allocation of the matrix */
        *matrix = (double**)malloc((*num_rows)*sizeof(double*));
        (*matrix)[0] = (double*)malloc((*num_rows)*(*num_cols)*sizeof(double));
        for (i=1; i<(*num_rows); i++)
            (*matrix)[i] = (*matrix)[i-1]+(*num_cols);
        /* read in the entire matrix */
        fread ((*matrix)[0], sizeof(double), (*num_rows)*(*num_cols), fp);
        fclose (fp);
    }

    /* Writes a 2D array in a binary file */
    void write_matrix_binaryformat (char* filename, double** matrix, int num_rows, int num_cols) {
      FILE *fp = fopen (filename,"wb");
      fwrite (&num_rows, sizeof(int), 1, fp);
      fwrite (&num_cols, sizeof(int), 1, fp);
      fwrite (matrix[0], sizeof(double), num_rows*num_cols, fp);
      fclose (fp);
    }

Моя задача состоит в том, чтобы выполнить параллельное матричное умножение матриц A и B и собрать результаты в матрице C.

Я делаю это, разделяя матрицу A на части по строкам, и каждый процесс будет использовать свою часть, чтобы умножить матрицу B, и получить свою часть от умножения. Затем я соберу все части процессов и сложу их в матрицу C.

Я уже публиковал аналогичный вопрос, но этот код улучшен, и я продвинулся вперед, но после вызова scatterv я все еще получаю ошибку сегментации.


person footman    schedule 20.05.2012    source источник
comment
Пожалуйста, используйте отладчик, чтобы определить, где именно возникает ошибка. SO не является вашим личным отладчиком.   -  person Mat    schedule 20.05.2012
comment
Я заменил код, который считывает матрицы из файлов, на код, который просто выделяет для них место, оставляя случайные значения. Запустите программу... Program exited normally. (gdb) quit ... мы даже не можем воспроизвести ошибку.... по поводу этого кода, вы уверены, что ваши данные декодируются правильно (код игнорирует, как справиться с определенным порядком байтов данных, и даже при правильном размере данных... например, sizeof(int) не обязательно должно совпадать с машиной, сгенерировавшей двоичный файл матрицы...   -  person ShinTakezou    schedule 20.05.2012


Ответы (2)


Итак, я вижу сразу несколько проблем:

    MPI_Bcast (&B, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); 

Здесь вы передаете не указатель на двойные значения, а указатель на указатель на указатель на двойное значение (B определяется как double **B) и указываете MPI следовать этому указателю и отправлять оттуда 1 двойное значение. Это не сработает.

Вы можете подумать, что здесь вы отправляете указатель на матрицу, из которой все задачи могут считывать массив — это не работает. Процессы не имеют общего пространства памяти (поэтому MPI называется программированием с распределенной памятью), и указатель никуда не уходит. На самом деле вам придется отправить содержимое матрицы,

    MPI_Bcast (&(B[0][0]), rowsB*colsB, MPI_DOUBLE, 0, MPI_COMM_WORLD); 

и вам нужно заранее убедиться, что другие процессы правильно выделили память для матрицы B.

В другом месте есть аналогичные проблемы с указателем:

    MPI_Scatterv(&A[0], ..., &local_A[0]

Опять же, A является указателем на указатель на удвоения (double **A), как и local_A, и вам нужно указывать MPI на указатель на удвоения, чтобы это работало, что-то вроде

    MPI_Scatterv(&(A[0][0]), ..., &(local_A[0][0])

эта ошибка, по-видимому, присутствует во всех подпрограммах связи.

Помните, что все, что выглядит как (buffer, count, TYPE) в MPI, означает, что подпрограммы MPI следуют указателю buffer и отправляют туда следующие count фрагментов данных типа TYPE. MPI не может следовать указателям в отправленном вами буфере, потому что обычно он не знает, что они там есть. Он просто берет следующие (count * sizeof(TYPE)) байтов из указателя buffer и выполняет с ними все необходимые действия. Поэтому вам нужно передать ему указатель на поток данных типа TYPE.

Сказав все это, было бы намного легче работать с вами над этим, если бы вы немного сузили круг вопросов; прямо сейчас программа, которую вы опубликовали, включает в себя множество операций ввода-вывода, которые не имеют отношения к делу, и это означает, что никто не может просто запустить вашу программу, чтобы посмотреть, что происходит, без предварительного выяснения формата матрицы, а затем создания двух матриц самостоятельно. Когда вы публикуете вопрос об исходном коде, вы действительно хотите опубликовать (а) небольшой фрагмент исходного кода, который (б) воспроизводит проблему и (в) полностью автономен.

person Jonathan Dursi    schedule 20.05.2012

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

Учитывая это, вы должны заменить:

MPI_Scatterv(&A[0],&proc_elements[0],&displace[0],MPI_DOUBLE,&local_A[0],
             local_rows*colsA,MPI_DOUBLE,0,MPI_COMM_WORLD);

с

MPI_Scatterv(A[0],&proc_elements[0],&displace[0],MPI_DOUBLE,local_A[0],
             local_rows*colsA,MPI_DOUBLE,0,MPI_COMM_WORLD);

A[0] уже указывает на начало данных матрицы и делать на него указатель не нужно. То же самое касается local_A[0], а также параметров вызова MPI_Gatherv().

Уже много раз было сказано - MPI не занимается поиском указателей и работает только с плоскими буферами.

Так же заметил еще одну ошибку в вашем коде - память под ваши матрицы освобождается неправильно. Вы освобождаете только массив указателей, а не сами данные матрицы:

free(A);

должен действительно стать

free(A[0]); free(A);
person Hristo Iliev    schedule 20.05.2012