在condor上运行时解决Mystery Segfault的方法/工具

时间:2010-09-10 01:32:40

标签: c memory-corruption condor

我正在编写一个在应用程序集群中运行的C应用程序(使用condor)。我已经尝试了很多方法来揭示有问题的代码,但无济于事。

线索:

  • 平均当我在15台机器上运行代码2天时,我得到两个或三个段错误(信号11)。
  • 当我在本地运行代码时,我没有遇到段错误。我在家用机器上跑了将近3个星期。

尝试:

  • 我在valGrind中运行了四天的代码,没有内存错误。
  • 我通过定义自己的信号处理程序捕获了segfault信号,以便输出一些程序状态。
  • 现在当发生段错误时,我可以使用backtrace打印出当前堆栈。
  • 我可以打印出变量值。
  • 我创建了一个设置为当前行号的变量。
  • 还尝试过对代码块进行评论,希望如果问题消失,我会发现段错误。

可悲的是,输出的行号相当随机。我不完全确定我能用stacktrace做什么。假设它只记录发生段错误的函数的地址,我是否正确?

猜疑:

  • 我怀疑condor用来跨机器移动作业的检查指向系统对内存损坏更敏感,这就是我在本地看不到它的原因。
  • 这些索引被bug破坏了,这些索引导致了段错误。这可以解释段错误发生在相当随机的行号上的事实。

更新

再研究一下,我发现了以下链接:

更新2

Greg建议查看condor日志并“将segfaults关联到condor从检查点重新启动可执行文件”。查看日志后,segfaults会在重新启动后立即发生。当作业从一种类型的机器切换到另一种类型时,似乎会发生所有故障。

更新3

段错误是由主机之间的差异引起的,通过在condor提交文件中设置'requiremets'字段使问题完全消失。

可以设置单独的机器:

requirements = machine == "hostname1" || machine == "hostname2"

或整类机器:

requirements = classOfMachinesName

请参阅要求示例here

5 个答案:

答案 0 :(得分:2)

如果可以,请使用调试进行编译,然后在gdb下运行。 或者,将核心转储并加载到调试器中。

mpich有内置调试器,或者你可以购买商用并行调试器。

然后,您可以单步执行代码以查看调试器中发生的事情

http://nmi.cs.wisc.edu/node/1610

http://nmi.cs.wisc.edu/node/1611

答案 1 :(得分:2)

当您的段错误发生时,您可以创建核心转储吗?然后,您可以调试此转储以尝试在崩溃时找出代码的状态。

看看导致故障的指令。它甚至是一个有效的指令还是你试图执行数据?如果有效,它试图访问什么内存?这个指针来自哪里。您需要缩小故障的位置(堆栈损坏,堆损坏,未初始化的指针,访问无效的内存)。如果它是一个腐败,看看是否在损坏的区域中有任何告诉数据(指向符号的指针,看起来像你的结构中的数据,......)。您的内存分配器可能已具有内置功能来调试某些损坏(请参阅Linux上的MALLOC_CHECK_或Mac OS上的MallocGuardEdges)。这些的常见情况是使用free()的内存,因此记录malloc()/ free()对可能有所帮助。

答案 2 :(得分:1)

如果您使用condor_compile工具使用condor检查点代码重新链接代码,那么它与普通链接的做法有所不同。最重要的是,它静态链接您的代码,并使用它自己的malloc。另一个很大的区别是,condor会在外国机器上运行它,在那里环境可能与你预期的问题不同。

condor_compile生成的可执行文件可作为condor系统之外的独立二进制文件运行。如果你在condor之外本地运行从condor_compile发出的二进制文件,你还能看到段错误吗?

如果没有,是否可以将段错误关联到condor从检查点重新启动可执行文件时(用户日志会告诉您何时发生这种情况)。

答案 3 :(得分:0)

你已经尝试了我想到的大部分内容。我建议的另一件事是开始添加大量的日志记录代码,并希望你可以缩小发生错误的位置。

答案 4 :(得分:0)

您没有说的一件事是您有多大的灵活性来解决问题。 例如,您是否可以暂停系统并运行您的应用程序? 这些崩溃还有多重要?

我假设大部分时间你这样做。这可能需要大量资源。

短期步骤是对每个变量放置大量“断言”(半手写) 当你不想要它时,确保它没有改变。这可以在您经历长期过程时继续工作。

长期 - 尝试在两个群集(可能是您的家用计算机和VM)上运行它。 你还看到段错误吗?如果在您开始看到段错误之前不增加簇大小。

以最低配置运行它(以获取段错误)并记录所有输入直到崩溃。使用您记录的输入自动运行系统,对其进行调整,直到您能以最小的输入一致地获得崩溃。

此时环顾四周。如果您仍然找不到该错误,那么您将不得不再次询问您使用这些运行收集的一些额外数据。