【问题标题】:Segmentation fault(core dumped) using openmp使用 openmp 的分段错误(核心转储)
【发布时间】:2019-07-23 00:10:51
【问题描述】:

我目前正在一个程序中工作,该程序在 c 中乘以矩阵,它在同一执行行中接收矩阵的大小,该程序适用于大小 900 以下的矩阵,但当达到大小超过 900 的矩阵时,我'我收到错误segmentation fault(core dumped)

在检查了互联网上的许多可用资源后,我仍然无法解决问题,这是我正在使用的代码:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <sys/time.h>

int main(int argc, char* argv[]) 
{
    int tam = atoi(argv[1]);
    int first[tam][tam];
    int second[tam][tam];
    int third[tam][tam];
    int i,j,k,l,f;
    srand(time(NULL));
    omp_set_num_threads(omp_get_num_procs());
    for (i= 0; i< tam; i++)
        for (j= 0; j< tam; j++)
    {
            l = rand();
            f = rand();
            first[i][j] = l;
            second[i][j] = f;
    }
    #pragma omp parallel for private(i,j,k) shared(first,second,third)
    for (i = 0; i < tam; ++i) {
        for (j = 0; j < tam; ++j) {
            for (k = 0; k < tam; ++k) {
                third[i][j] += first[i][k] * second[k][j];
            }
        }
    }

}

非常感谢您的帮助,并感谢您抽出宝贵时间阅读我的问题。

【问题讨论】:

  • 您是否使用过调试器来准确查看其段错误的位置?我不确定,但也许 OpenMP 不喜欢变长数组?
  • 你有一个竞争条件。
  • @HenriMenke 哪里有竞争条件?我没有看到一个。唯一的写入是third[i][j],任何两个线程都不会同时写入相同的i
  • @Zulan 好吧,我实际上并不完全确定,但如果 OpenMP 折叠三个嵌套循环(我不知道它是否默认发生),third[i][j] += ... 将会竞争。跨度>
  • @HenriMenke OpenMP 默认不折叠循环。

标签: c parallel-processing openmp


【解决方案1】:

[segfault] 的根本原因不是 OpenMP,而是巨大的 STACK 分配

您可能已经注意到,900 并不是发生 [segfault] 崩溃的固定阈值。

然而,让我们展示几种前进方式之一:将数据放在 HEAP 上,而不是让它在 STACK 上分配:

TiO.RUN 在线可运行验证演示已准备好单击并运行 here(随着运行时的增长,超过 ~ 8000 x 8000 x 8-B x 3 矩阵的数组大小开始被平台软删除超过了大约 1 分钟 CPU 时间的在线平台演示配额)。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <sys/time.h>

#define             cTAM 1234
static int m3[cTAM][cTAM],              // HEAP-allocated data does not devastate STACK-resources
           m2[cTAM][cTAM],              // HEAP-allocated data does not devastate STACK-resources
           m1[cTAM][cTAM];              // HEAP-allocated data does not devastate STACK-resources

int main(int argc, char* argv[]) 
{
    int             tam = cTAM;         // proxy for not accessible command-line parameter passing
//  int first[ tam][tam];
//  int second[tam][tam];
//  int third[ tam][tam];

    int i,j,k,l,f;

    srand(time(NULL));
// ------------------------------------ // root-cause problem is NOT related to the art of OpenMP
//  omp_set_num_threads(omp_get_num_procs());
    for     ( i = 0; i < tam; i++ )
        for ( j = 0; j < tam; j++ )
    {
            l = rand();
            f = rand();
        //  first[i][j] = l;
        //  second[i][j] = f;
            m1[i][j] = l;
            m2[i][j] = f;
    }
// ------------------------------------ // root-cause problem is NOT related to the art of OpenMP
//  #pragma omp parallel for private(i,j,k) shared(first,second,third)
    for         ( i = 0; i < tam; ++i ) {
        for     ( j = 0; j < tam; ++j ) {
            for ( k = 0; k < tam; ++k ) {
            //   third[i][j] += first[i][k] * second[k][j];
                 m3[i][j]    += ( m1[i][k]
                                + m2[   k][j]
                                  );
            }
        }
    }
    return( 1 );
}

进一步的 OpenMP 技巧是另一个主题,与 [segfaults] 无关

  • 重构索引,以便更好的缓存行对齐处理重新使用已获取的缓存行“邻居”中的逐行数据元素,并且最好完全避免对第三[][]-cells 的共享访问(性能提升将奖励这些努力)
  • 如果first[][](或上面的m1[][])被转置,性能将会得到提升,因为迭代将遵循已经预取到缓存行中的逐行内存块(数据访问成本将下降从大约~1E2 [ns] 到缓存命中的~0.5 [ns],即~ 200 X

不要犹豫,阅读更多内容并了解有关缓存层次结构、合并内存访问模式以及智能缓存行技巧以增加缓存行重用而不是重新获取数据所需的技术细节这曾经只是通过索引迭代的不良顺序获取的。您在使用 GPU 内核代码时遇到了同样的问题,因此确实值得花几天时间深入研究这个技术技巧,因为它对您有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 2021-06-03
    相关资源
    最近更新 更多