MPI на C, ошибка сегментации: 11

У меня Mac OS X Yosemite 10.10.1 (14B25).

У меня есть некоторые проблемы с компиляцией кода. Вот:

#include <stdio.h>
#include <mpi.h>

#define n 3
#define repeats 1

double abs(double item)
{
    return (item > 0) ? item : -item;
}

int swap_raws (double **a, int p, int q)
{
    if (p >= 0 && p < n && q >= 0 && q < n)
    {
        if (p == q)
            return 0;    

        for (int i = 0; i < n; i++)
        {
            double temp = a[p][i];
            a[p][i] = a[q][i];
            a[q][i] = temp;
        }

        return 0;
    }
    else
        return -1;
}

double f_column (int rank, int size, double *least)
{
    double t1, t2, tbeg, tend, each_least = 1, least0;
    int map[n];
    double **a = malloc (sizeof (*a) * n);
    int i, j, k;    

    for (i = 0; i < n; i++)
        a[i] = malloc (sizeof (*a[i]) * n);    

    if (rank == 0)
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++)
                a[i][j] = 1.0 / (i + j + 1);

    MPI_Bcast (a, n * n, MPI_DOUBLE, 0, MPI_COMM_WORLD);

    for (i = 0; i < n; i++)
        map[i] = i % size;

    MPI_Barrier (MPI_COMM_WORLD);

    t1 = MPI_Wtime ();

    for (k = 0; k < n - 1; k++)
    {
        double max = abs (a[k][k]);
        int column = k;

        for (j = k + 1; j < n; j++)
        {
            double absv = abs (a[k][j]);

            if (absv > max)
            {
                max = absv;
                column = j;
            }
        }

        if (map[k] == rank && column != k && swap_raws (a, k, column))
        {
            printf("ERROR SWAPPING %d and %d columns\n", k, column);
            return -1;
        }

        MPI_Bcast (&a[k], n, MPI_DOUBLE, map[k], MPI_COMM_WORLD);
        MPI_Bcast (&a[column], n, MPI_DOUBLE, map[k], MPI_COMM_WORLD);

        if (map[k] == rank)
            for (i = k + 1; i < n; i++)
                a[k][i] /= a[k][k];

        MPI_Barrier (MPI_COMM_WORLD);
        MPI_Bcast (&a[k][k+1], n - k - 1, MPI_DOUBLE, map[k], MPI_COMM_WORLD);

        for (i = k + 1; i < n; i++)
            if (map[i] == rank)
                for (j = k + 1; j < n; j++)
                    a[j][i] -= a[j][k] * a[i][j];
    }

    t2 = MPI_Wtime ();

    for (i = 0; i < n; i++)
        if (map[i] == rank)
            for (j = 0; j < n; j++)
            {
                double absv = abs (a[i][j]);

                if (each_least > absv)
                    each_least = absv;

                //printf ("a[%d][%d] = %lg\n", j, i, a[i][j]);
            }

    MPI_Reduce (&each_least, &least0, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD);
    MPI_Reduce (&t1, &tbeg, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD);
    MPI_Reduce (&t2, &tend, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD);

    for (i = 0; i < n; i++)
        free (a[i]);
    free (a);

    if (rank == 0)
    {
        *least = least0;
        return (tend - tbeg);
    }
}

int main (int argc, char *argv[])
{
    int rank, size;
    double min, max, aver, least;

    if (n == 0)
        return 0;

    MPI_Init (&argc, &argv);
    MPI_Comm_rank (MPI_COMM_WORLD, &rank);
    MPI_Comm_size (MPI_COMM_WORLD, &size);

    // It works!
    //double try = f_column_non_parallel (rank, size, &least);
    double try = f_column (rank, size, &least);
    aver = max = min = try;

    for (int i = 1; i < repeats; i++)
    {
        //double try = f_column_non_parallel (rank, size, &least);
        double try = f_column (rank, size, &least);

        if (try < min)
            min = try;
        else if (try > max)
            max = try;

        aver += try;
    }
    aver /= repeats;

    MPI_Finalize ();

    if (rank == 0)
        printf("N: %d\nMIN: %f\nMAX: %f\nAVER: %f\nLEAST: %lg\n", size, min, max, aver, least);

    return 0;
}

У меня есть матрица Гилберта. a(i)(j) = 1 / (i + j + 1) для i,j от 0 до n

Этот код должен найти декомпозицию LU с использованием MPI, чтобы сделать это параллельно.

Первый процесс инициализирует массив, а затем передает его другим процессам.

Затем я нахожу максимум в сырье и меняю местами эти столбцы. Затем я хотел бы передать эти данные для каждого процесса, то есть с использованием MPI_Barrier (MPI_COMM_WORLD); но это говорит:

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

Если вы найдете решение, пример должен работать так (я сам его вычислял, вы тоже можете проверить, но я могу признать, что это правда). Матрица (здесь j и i по вертикали и по горизонтали соответственно, она не очень удобна для людей, но вы должны взять ее):

1   1/2 1/3    1   1/2  1/3     1   1/2  1/3      |1   1/2  1/3  |
1/2 1/3 1/4 -> 1/2 1/12 1/12 -> 1/2 1/12 1     -> |1/2 1/12 1/12 | <- answer
1/3 1/4 1/5    1/3 1/12 4/45    1/3 1/12 1/180    |1/3 1    1/180|

Исходная матрица такова:

    |1   0 0|   |1 1/2  1/3  |   |1   1/2 1/3|
A = |1/2 1 0| * |0 1/12 1/12 | = |1/2 1/3 1/4|
    |1/3 1 1|   |0 0    1/180|   |1/3 1/4 1/5|

Можете ли вы помочь мне выяснить допущенную ошибку? Заранее спасибо:)

2 ответа

Решение

В вашей программе есть ошибка в следующей части кода:

double **a = malloc (sizeof (*a) * n);
[...snip...]
MPI_Bcast (a, n * n, MPI_DOUBLE, 0, MPI_COMM_WORLD);

Вы размещаете указатели 'n' в массиве 'a', а не в массиве 'n * n'. Поэтому, когда вы делаете MPI_Bcast размером "n * n", равный "a", вы запрашиваете перенос MPI из неиспользуемых областей памяти мусора. Это заставляет MPI к segfault.

Вы можете изменить "a" на просто "double *" вместо "double **" и выделить там "n * n" double, чтобы решить эту проблему.

Больше всего меня огорчает то, что f_column() должен возвращать double, но возвращаемое значение не определено, когда rank != 0,

Этот комментарий привлек мое внимание:

// It works!
//double try = f_column_non_parallel (rank, size, &least);
double try = f_column (rank, size, &least);

Это говорит о том, что предыдущая версия f_column() работал, и что вы столкнулись с проблемами при попытке распараллелить его (я думаю, это то, что вы делаете сейчас).

Как это может привести к segfault, мне не сразу понятно. Я ожидаю исключения с плавающей запятой.

Пара других моментов:

  • Я не слишком доволен вашим кодом выделения памяти (вероятно, я бы использовал calloc() вместо malloc(), а также sizeof() о явных типах данных и т.д...); это просто пугает меня, чтобы увидеть такие вещи, как a[i] = malloc(sizeof (*a[i]) * n);но это просто вопрос стиля, правда.

  • У вас, кажется, есть правильная проверка границ (индексы более a всегда позитивны и < n).

  • Ох, и вы переопределяете abs()что, вероятно, не очень хорошая идея.

  • Попробуйте скомпилировать код в режиме отладки и запустить его с gdb; также, если возможно, запустите его через valgrind, MacOS X должна поддерживаться.

  • Вы, вероятно, должны внимательно посмотреть на предупреждения вашего компилятора;-)

Другие вопросы по тегам