有助于调试优化代码的一个编译器选项

面向 IBM XL C/C++ 和 XL Fortran 的增强

调试优化代码一直是一个具有挑战性的任务,因为它可能使程序状态对调试器不可用。优化可以改变操作顺序、添加或删除代码、更改可变数据位置,并执行难以使生成代码与原始源代码语句关联的其他转换。在本文中,Daniel Chen 和 Tommy Hoffner 介绍了一个有助于调试优化代码的编译器选项。

Daniel Chen, 软件开发人员, IBM

Daniel Chen 是 IBM 在加拿大的一名 Fortran 编译器前端开发人员。



Tommy Hoffner, 软件开发人员, IBM

Tommy Hoffner 是 IBM 在加拿大的一名 C/C++ 和 Fortran 编译器后端开发人员。



2012 年 10 月 22 日

免费下载:IBM® XL® C/C++ for IBM AIX 编译器  |  IBM® XL® C/C++ for Linux 编译器
免费下载:IBM® XL® Fortran for IBM AIX 编译器  |  IBM® XL® Fortran for Linux 编译器
下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。

调试优化代码的挑战

调试优化代码一直是一个具有挑战性的任务,因为它可以使程序状态对调试器不可用。优化可以改变操作顺序、添加或删除代码、更改可变数据位置,并执行难以使生成代码与原始源代码语句关联的其他转换。例如,如果一个变量只用于计算另一个表达式,编译器可以选择直接生成最终表达式的值,不需要在任何点显式生成变量值。这可能会降低调试的可用性,因为程序员期望看到的变量在优化后的程序中已不再可用。


在 IBM XL C/C++ 和 XL Fortran 中的当前调试支持

IBM® XL C/C++ 和 XL Fortran 为调试支持提供了一套机制:

  • 编译器选项 –g 生成由符号调试器使用的调试信息。虽然它提供了对 no-opt 的完整调试支持,但它并不能真正很好地处理优化过的代码。正如我们在上一节中所述,由于优化,导致无法捕获程序状态。
  • 编译器选项 –qkeepparm 特别针对过程参数。即使在优化过程中,它也可以确保过程参数的初始值对调试器可用。这对执行性能的影响很小。然后,-qkeepparm 选项只需将这些值保留在堆栈上,就可以为调试器提供传入参数值的访问权限。
  • 完成一些高级转换后,编译器选项 -qoptdebug 创建一个修改后的源代码,与优化后的代码相匹配。这种伪代码可以比原始源代码更加紧密地映射到优化程序的指令和值。当使用该选项编译的程序被加载到调试器时,您将调试伪代码,而不是原始的源代码。

面向调试优化代码的增强

增强调试选项 -g 后可控制调试支持,并使调试优化代码更容易,尤其在使用 -O2 时更容易。当 -O2 优化级别生效时,调试功能会得到完全支持。当高于 -O2 的优化级别生效时,调试功能会受到限制。调试选项 -g 的级别范围是从 0 到 9。

  • -g0: 不生成调试信息。不保存程序状态(最佳性能)。
  • -g1: 生成有关行号和源文件名的调试信息。不保存程序状态。
  • -g2: 生成有关类型、行号、源文件名的调试信息,以及有关变量的仅查看调试信息。优化代码时,不保证提供程序状态。
  • -g3, -g4: 与 –g2 的行为相同,加上在每个过程开始时向调试器提供过程参数值。
  • -g5, -g6, -g7: 与 –g3 和 –g4 的行为相同,加上在 –O2 级别时,在以下选定的语言结构中向调试器提供程序状态:
    • 在循环之前和之后
    • 在条件分支语句之前和之后
    • 在函数调用以及函数的第一个可执行语句之前和之后。
  • -g8: 与 –g3 和 –g4 的行为相同,加上在 –O2 级别时,在每个可执行语句的开始时向调试器提供程序状态。
  • -g9: 与 –g8 的行为相同,加上在 –O2 级别时,用户可以在调试器中修改变量。能够在调试器中修改变量,这也是调试 no-opt 代码的默认行为(最佳调试支持)。

在 -g5 及以上级别,优化代码的调试支持得到了增强,其中,在 -O2 优化级别,可提供程序状态。例如,在 -g8 调试下面的测试案例:

	T1 = X * Y - 1;
	T2 = X * Y * 3;
	Q = T1 + T2;

在 –O2 没有调试支持时,编译器可能生成以下代码,其中 GRX 和 GRY 是寄存器:

	GRX = X * Y;
	GRY = GRX << 2;
	Q = GRY – 1;

因为程序从不计算 T1 和 T2 的值,调试器可能无法显示正确的 T1 和 T2 值。

在 –O2 –g8,编译器生成类似于下面的代码:

	GRX = X * Y;
	GRY = GRX << 2;
	T1 = GRY – 1;
	T2 – GRY – GRX;
	Q = GRY – 1;

程序将 T1 和 T2 的值重新存储在内存中,这样就可将它们提供给调试器。


调试内联函数

函数内联 是常用优化技术之一。调试这样的函数也会引起许多麻烦。调试器甚至不承认这是一个内联函数,因为只生成了行号项。内联后,内联函数的形式参数和局部变量可能无法向调试器提供。

作为调试支持的一个改进,编译器显式指明内联函数的范围,这样用户就可以逐步了解函数主体。用户还可以检查内联函数的形式参数和局部变量。然而,用户目前不能够 “停止使用函数” 并让调试器查找内联函数的任何内联实例。


性能考虑因素

即使调试能力的增强对性能产生负面影响(因为保存程序状态会消除了一些优化机会),编译器仍然可在 –O2 级别生成完全可调式的优化代码。正如我们在 -g8 -O2 级别所测量的,当编译时间增加 14% 时,我们可获得平均 80% 的 -O2 执行时间。当然,执行和编译时间的下降在很大程度上取决于应用程序。

为了限制对性能的影响,您也可以尝试不同的 -g 级别。例如,因为循环是大量应用优化技术的地方,-g5 旨在只保存计算循环前后的程序状态,使调试信息不会干扰应用于循环主体的优化算法。


结束语

对调试优化代码的支持已经得到了改进。现在,允许您在调试能力和性能之间进行优化扩展。目前,只有 -O2 级别的优化可以得到全面的调试支持。我们将继致力于为更高的优化级别的优化提供调试支持的改进。

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=843919
ArticleTitle=有助于调试优化代码的一个编译器选项
publish-date=10222012