【问题标题】:MPI on C, Segmentation fault: 11C 上的 MPI,分段错误:11
【发布时间】:2015-01-26 16:55:48
【问题描述】:

我有 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

此代码应使用 MPI 找到 LU 分解,以便以并行方式进行。

第一个进程初始化数组,然后将其广播给其他进程。

然后我在 raw 中找到最大值并交换那些列。然后我想将该数据广播到每个进程,即使用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|

源矩阵so:

    |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|

你能帮我找出错误吗?提前谢谢你:)

【问题讨论】:

    标签: c parallel-processing segmentation-fault mpi simultaneous


    【解决方案1】:

    您的程序在以下代码部分存在错误:

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

    您在“a”中分配“n”个指针,而不是“n * n”数组。因此,当您执行“a”的“n * n”大小的 MPI_Bcast 时,您是在要求 MPI 从未分配的垃圾内存位置传输。这会导致 MPI 出现段错误。

    您可以将“a”更改为简单的“double *”而不是“double **”,并在其中分配 'n * n' 个双精度来解决此问题。

    【讨论】:

    • 非常感谢,非常有帮助的回答:)
    • @Beraliv,如果这是正确答案,请继续并将其标记为这样,既要感谢 Pavan,又要让我们其他人知道这个问题已经完成。
    • 应该是这样,但它不是唯一的问题,所以我不能将其标记为完整的解决方案,但它可以帮助我明白我犯了一个错误
    【解决方案2】:

    最让我伤心的是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() 正在运行,并且您在尝试并行化它时遇到了麻烦(我猜这就是您现在正在做的事情)。

    不过,这如何导致段错误对我来说并不是很明显。我希望出现浮点异常。

    其他几点:

    • 我对你的内存分配代码不太满意(我可能会使用calloc() 而不是malloc(),并在显式数据类型上使用sizeof() 等...);看到a[i] = malloc(sizeof (*a[i]) * n); 之类的东西让我很害怕,但这只是风格问题,真的。

    • 您似乎进行了适当的边界检查(a 以上的索引始终为正且n)。

    • 哦,你正在重新定义abs(),这可能不是一个好主意。

    • 尝试在调试模式下编译您的代码,并使用gdb 运行它;如果可以的话,也可以通过valgrind 运行它,现在应该支持MacOS X。

    • 您可能应该仔细查看编译器警告;-)

    【讨论】:

    • 首先,非并行版本也未定义。这意味着进程 0 是主进程,它对我来说唯一重要的是返回值。其次,嗯,是的,我在并行化它时遇到了问题。此外,abs 正在重新定义,因为它与我想要获得的值不正确(如果我没记错的话,它是为 int 定义的)。跨度>
    • gdb 与并行程序一起工作,我编译该程序不是gcc ... 而是mpicc ..
    猜你喜欢
    • 1970-01-01
    • 2017-06-25
    • 2016-05-08
    • 2017-07-30
    • 2016-06-08
    • 2016-10-09
    • 2013-10-31
    • 1970-01-01
    • 2014-04-12
    相关资源
    最近更新 更多