c ++ runtime_error在集群节点之间捕获不一致

时间:2017-07-12 15:02:23

标签: c++ linux gcc

问题

我正在尝试设置一个在Redhat scientific linux(v5.11)集群上运行的c ++程序。我已经能够编译软件,它在头节点上运行完美,但在任何工作节点上运行时都会崩溃。

我已将问题跟踪到部分代码,如果某些条件返回false,则抛出std::runtime_error。这是故意的,因为当软件正确运行时,它会被捕获并继续迭代。在工作节点上,软件在首次抛出错误时中止。 abort代码和backtrace如下所示。

因为它适用于一个节点但不适用于其他节点,我的猜测是这是gcc版本的问题。为了编译我必须yum install devtoolset-2并使用gcc 4.8.2 (Red Hat 4.8.2-15)构建软件,因为系统gcc 4.1.2 (Red Hat 4.1.2-55)太旧而无法正确编译。当我在两个节点上启动应用程序时,我有以下内容:

which gcc > /opt/rh/devtoolset-2/root/usr/bin/gcc
which c++ > /opt/rh/devtoolset-2/root/usr/bin/c++
which g++ > /opt/rh/devtoolset-2/root/usr/bin/g++
which gfortran > /opt/rh/devtoolset-2/root/usr/bin/gfortran
$LD_LIBRARY_PATH > /opt/rh/devtoolset-2/root/usr/lib64:/opt/rh/devtoolset-2/root/usr/lib

就头部和工作节点之间的差异而言,除了内核版本之外,它们是相同的:

  • 负责人:Linux address.com 2.6.18-419.el5#1 SMP x86_64 x86_64 x86_64 GNU / Linux
  • 工作人员:Linux address.com 2.6.18-164.11.1.el5#1 SMP x86_64 x86_64 x86_64 GNU / Linux

我累了的事情:

  • 使用SGE队列提交在工作节点上运行(使用-V传递环境)
  • 通过ssh worker直接在工作节点上运行,并导出与头节点上相同的所有环境变量
  • 在工作节点上编译并运行

任何帮助将不胜感激!以下几个问题,我认为得到答案可以帮助我缩小原因:

  1. 是否可以追求内核版本的差异?
  2. 这看起来像库和路径而不是代码的问题吗?
  3. 库版本之间的c ++错误处理方式是否有变化?
  4. 我是否有更多的调试方法可以尝试找到原因?
  5. 额外信息

    abort如下:

    terminate called after throwing an instance of 'std::runtime_error'
      what():  'custom error message'
    
    Program received signal SIGABRT, Aborted.
    0x00000038b6830265 in raise () from /lib64/libc.so.6
    

    backtrace如下:

    #0  0x00000038b6830265 in raise () from /lib64/libc.so.6
    #1  0x00000038b6831d10 in abort () from /lib64/libc.so.6
    #2  0x00000038bb0bec44 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib64/libstdc++.so.6
    #3  0x00000038bb0bcdb6 in ?? () from /usr/lib64/libstdc++.so.6
    #4  0x00000038bb0bcde3 in std::terminate() () from /usr/lib64/libstdc++.so.6
    #5  0x00000038bb0bceca in __cxa_throw () from /usr/lib64/libstdc++.so.6
    #6  0x00002aaaab074bdc in Some::Function::Name() () from path/to/file.so
    

    我必须承认我对c ++的了解非常有限,尽管过去两天我一直试图改进这个问题。下面是抛出并捕获错误的代码的简化示例(这显然是重复调用Func1的更大进程的一部分):

    double Func1(int a, double b, int c)
      {
    
      for (bool OK = true ; OK && d > e && f < a ; f++)
        {
        try
          {
          for (d = 0, g = 1 ; g < 10 ; g *= 2)
            {
            Func2() ;
            }
          }
        catch (runtime_error problem)
          {
          *log << problem.what() ;
          OK = false ;
          }
        if (c > 1)
          {
          *log << f << d;
          }
        }
    
    void Func2()
      {
      for (int j = 0 ; j < ny && (x & 5) > 0 ; j++)
        {
        if (Func3(j) <= 0.0)
          {
          throw runtime_error("custom error message") ;
          }
        Func4[j] = j ;
        }
      }
    

    在已编译的程序上运行ldd(在头节点上运行,在工作节点上缺少第1行):

    linux-vdso.so.1 =>  (0x00007fff2b6e7000)
    /users/username/software/version/Part1/Part1Extra.so (0x00002b3543587000)
    libgfortran.so.3 => /usr/lib64/libgfortran.so.3 (0x00002b354385b000)
    libm.so.6 => /lib64/libm.so.6 (0x0000003cc2000000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000315f800000)
    libc.so.6 => /lib64/libc.so.6 (0x0000003cc1c00000)
    /users/username/software/version/Part2/Part2.so (0x00002b3543b4f000)
    /users/username/software/version/Part3/Part3.so (0x00002b3543d9b000)
    libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x0000003160000000)
    /lib64/ld-linux-x86-64.so.2 (0x0000003cc1800000)
    /users/username/software/version/Part3/Part3Extra.so (0x00002b3543fb2000)
    

1 个答案:

答案 0 :(得分:2)

最后成功解决了发生的事情......

对于那些发现与c ++代码相关的意外错误的人来说,即使系统共享一个公共文件结构,c ++代码在一个多节点系统的一部分上正常运行而在其他部分也没有,但这最后一点可能会产生误导,尽管我对于那些更熟悉系统管理的人来说,这一点非常明显。

最初我的印象是head和worker / computation节点共享整个文件结构。这只是部分正确,因为工作节点可以访问文件系统的某些部分,但重要的是不是核心文件,例如/lib/lib64.基本上所有通过yum安装的软件包都是独立于每个计算节点。将头节点更新为正确的gcc版本(在此实例中为devtoolset-2)后,我的印象是每个工作节点也都已更新。此情况并非如此。

基础问题

使用gcc 4.8.2 (Red Hat 4.8.2-15)编译的c ++代码在头节点上工作,该节点在捕获libstdc++.x86_64 (v4.1.2-55.el5)错误时遇到std::runtime_error。在工作节点上运行时,未正确捕获此错误。

问题是工作节点系统libstdc++.x86_64版本已经过时(遗憾的是我不记得究竟是哪个版本),这意味着错误没有被捕获。某个版本的libstdc++似乎无法捕获使用gcc 4.8.2编译的代码中的错误。

解决方案

必须使用yum手动更新每个工作节点,以使其libstdc++版本足以解决此问题(在我们的案例中为v4.1.2-55.el5)。更新libstdc++解决了问题。

额外信息

在我们的案例中,工作节点无法直接连接到互联网,因此yum必须通过代理完成。我们的yum版本也太旧了,无法使用socks5h自动ssh隧道代理方法。因此,我们必须使用头节点上的squid包来允许连接。

最后,由于文件结构的差异非常具有误导性,因此需要一段时间才能弄明白。虽然关键文件夹不在节点之间共享,但内容看起来与包的旧/新版本具有完全相同的文件结构完全相同,只是修改了内容。

对于系统管理员来说,这可能是非常明显的,但是你去了。