我正在尝试设置一个在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
就头部和工作节点之间的差异而言,除了内核版本之外,它们是相同的:
我累了的事情:
-V
传递环境)ssh worker
直接在工作节点上运行,并导出与头节点上相同的所有环境变量任何帮助将不胜感激!以下几个问题,我认为得到答案可以帮助我缩小原因:
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)
答案 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
包来允许连接。
最后,由于文件结构的差异非常具有误导性,因此需要一段时间才能弄明白。虽然关键文件夹不在节点之间共享,但内容看起来与包的旧/新版本具有完全相同的文件结构完全相同,只是修改了内容。
对于系统管理员来说,这可能是非常明显的,但是你去了。