18

很多时候我使用优化的代码(有时甚至涉及矢量化循环),其中包含错误等。如何调试这样的代码?我正在寻找任何类型的工具或技术。我使用以下(可能已过时)工具,因此我正在寻求升级。

我使用以下内容:

  • 由于使用 ddd,您看不到代码,因此我使用 gdb+ dissambler 命令并查看生成的代码;我无法真正使用它来逐步完成程序。
  • 无意识

谢谢

4

4 回答 4

21

调试优化程序总是很困难,但总有办法。一些额外的提示:

  • 进行调试构建,看看您是否在调试构建中遇到相同的错误。如果不需要,调试优化版本是没有意义的。
  • 如果在支持它的平台上使用 valgrind。您看到的错误可能更难理解,但及早发现问题通常会简化调试。
  • printf 调试是原始的,但如果您遇到仅在优化构建中出现的复杂问题,有时它是最简单的方法。
  • 如果您怀疑存在时间问题(尤其是在多线程程序中),请滚动您自己的 assert 版本,如果违反条件则中止或打印,并在几个选定的地方使用它,以排除可能的问题。
  • 看看你是否可以在不使用 -fomit-frame-pointers 的情况下重现问题,因为这使得代码很难调试,并且启用了 -O2 或 -O3。这可能会为您提供足够的信息来找到问题的原因。
  • 隔离代码的一部分,构建一个测试套件,看看你是否能识别出任何失败的测试用例。调试一个函数比调试整个程序要容易得多。
  • 尝试使用 -fno-X 选项一一关闭优化。这可能会帮助您找到常见问题,例如严格的别名问题。
  • 打开更多编译器警告。有些事情,比如严格的别名问题,如果它们在不同的优化级别之间造成行为差异,就会产生编译器警告。
于 2009-09-07T02:48:49.957 回答
7

在调试发布版本时,您可以输入 __asm nops; 作为断点的占位符(int 3)。这很好,因为您可以保证断点位置而不会弄乱编译器优化或编写 printf/cout 语句。

于 2009-09-07T02:56:33.907 回答
1

当然,调试非优化版本总是更容易。如果做不到这一点,反汇编代码可能会有所帮助。我使用的其他技术包括通过强制打印或记录中间结果来部分反优化代码,或者将关键变量更改为“易失性”,这样我至少可以在调试器中查看该值。

于 2009-09-07T02:50:52.667 回答
0

有可能你所说的优化代码被打乱以减少周期(这使得调试变得困难),但实际上并不是非常优化。这是我的意思的一个例子。

我会关闭编译器优化,自己调试和调整它,然后如果代码的热点实际上在编译器看到的代码中(而不是在外部库中),则重新打开编译器优化。(我将热点定义为经常发现 PC 的代码的一部分。它会自动排除包含函数调用的循环,因为它们会偷走 PC。)

于 2009-09-25T14:11:44.013 回答