IBM Support

i Can ... 通过优化函数的参数传递提高程序运行性能

Technical Blog Post


Abstract

i Can ... 通过优化函数的参数传递提高程序运行性能

Body

原文链接 http://ibmsystemsmag.blogs.com/i_can/2010/07/i-can-improve-performance-…
原文作者 Bill Schmidt,IBM i Optimizing Translator team,team leader

        你想要提高你的ILE应用程序的运行性能吗?如果是,那么你应该去看一看IBM i ILE Concepts (SC41-5606-09)中的第13章。该章节详细介绍了多种可供你尝试的优化技巧。而今天,我想要讨论的是其中的一个主题:通过过程(或函数)的参数优化提高过程(或函数)调用的性能。

        如果你有一个或多个过程被频繁调用,并且它们的参数或返回值是space pointers(译注1),那么参数优化对程序的性能的提高会很有帮助。所谓space pointer即是指向程序中的数据的指针;以C或者C++语言为例,int* 和 char* 都算是space pointer。参数优化可以使过程调用中space pointers参数传递更加高效。

在过程调用中space pointers通常必须通过内存(memory)传递。因为space pointers的字长较大(译注2),而且包含了有效性标记以避免恶意或无意识的滥用。与之比较,一个整型的参数则可通过一个寄存器传递。通常访问寄存器要比访问内存快很多。参数优化的主要目的则正是使传递space pointer参数的代价几乎与传递整型参数一样。

基本参数优化

        这样的优化究竟如何完成呢?关键点在于某些时候space pointer里额外的完整性(integrity)信息并不真的需要。对于简单的情况,优化编译器(译注3)能自己证明在某个上下文环境中是否需要一个space pointer的完整性信息。例如,假设存在这样的情况,过程X调用过程Y,X和Y都在同一个模块(module)里面,并且Y的接口没有被导出,也即是Y不能被其他模块调用。当编译处理过程Y时,如果编译器知道Y被调用时其实参是一个space pointer并且实参的值从上一处验证点后没有被修改过,则没有必要在传参中再次对该space pointer进行有效性验证。这种情况下,编译器优化会修改Y,使其接受一个可通过寄存器传递的,格式更简化的形参,同时编译器也会修改X,使其用同样的简化的格式传递相应的实参。

        理想情况下,这样的转换可以使得过程调用的速度显著地加快。而问题是编译器没有足够的信息在每种情况下都能做出优化的决定。就刚才的例子来说,如果Y可以被它们(X和Y)以外的模块调用,则编译器不能确定是否存在其他的调用者会传入错误的指针(译注4),因此该指针参数必须用内存来传递并执行有效性验证。

        IBM提供两种机制以便你能更大范围地在过程调用中使用参数优化技术。两种机制各有优点和缺点,所以你需要根据应用程序的特征来选择使用其中一种或两种都用。下面的表格概述了它们的差异。

图像
  • #pragma argopt

        通过编译指示“#pragma argopt”可以让你有选择地为某个过程或者过程指针加上标注,以告诉编译器需要针对它们使用参数优化技术。你需要把这个pragma放在过程或过程指针的声明或定义后面。如果模块M中的过程X调用了模块N中的过程Y,则必须在两个模块里对过程Y的#pragma argopt标注保持一致。了解详细信息,请查阅 ILE C/C++ Compiler Reference (SC09-4816-05)

“#pragma argopt”的参数优化方式的主要优点是它可以对函数指针式间接调用使用参数优化。这包括了大量的C++虚函数调用场景(译注6)。如我们下面将看到的,ARGOPT(*YES)的参数优化方式不能用在间接过程调用上。而“#pragma argopt”的参数优化方式的缺点则是它要求对源代码修改,以及只有ILE C 和 C++ 编译器支持该编译指示方式。

  • 高级参数优化

        高级参数优化是在6.1版本时被引入IBM i操作系统的。前面提到优化编译器可以在一些简单的情况下,通过分析某过程的所有可能的调用者,自动地对该过程进行参数优化。高级参数优化是将这种自动的参数优化技术扩展到整个程序(program)或服务程序(service program)。(译注7)

        你可以在 CRTPGM 和 CRTSRVPGM 命令上指定 ARGOPT(*YES) 参数来要求高级参数优化。然后系统将分析绑定到程序或服务程序中的所有模块的全部过程调用。这样一来,参数优化将被应用在几乎全部的被绑定进来的过程调用上。主要的例外情况是,某些过程可以被外部的程序或服务程序访问到,那么这些过程则不能进行参数优化。因为,同样,我们不能确定它的所有调用者都能传入正确有效的space pointers。

        高级参数优化不能对虚函数调用进行优化,也不能对其他通过过程指针的间接调用进行优化。因为使用过程指针,很难(或者不可能)证明哪一个过程将会通过这些指针被调用。因此,如果你的代码中包含间接调用,即使你已经使用了ARGOPT(*YES),你仍需要对间接调用的过程使用 #pragma argopt。

        高级参数优化的主要优点是不需要修改源代码,而且所有的ILE语言都支持。而它的缺点是不能用于间接的过程调用,还有创建程序或者修改程序所需要的时间会更长。因为它需要更多的时间扫描全部的模块,以及分析哪些过程调用可以做参数优化。

  • 我应该使用参数优化吗?

        参数优化是否能提高性能取决于你的程序的特性。其关键问题是,你的程序中是否有频繁被调用的过程。如果是,并且那些过程是以space pointers作为参数或者返回space pointers给调用者,那么参数优化技术能提高你的应用程序的性能。

        值得注意的是,如果你在创建模块时使用了 DTAMDL(*LLP64) 参数(译注8),你的应用程序可能不会从参数优化中得到很明显的性能提升。因为在该数据模型下,程序中的数据指针已经使用了一种更小字长的,更高效的形式,并且在参数传递中已经使用了寄存器传递方式。不过某些应用程序可能会在 DTAMDL(*LLP64) 的模块中显示地使用16字节的space pointers(译注9)。因此,你仍然可能会从参数优化中得到一些好处。

        我希望这些信息能对你们中的部分人有用。在下一次博客文章中,我将讨论另一个高级优化技术:程序剖析(Program Profiling)。



-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

译注:
#1. 在ILE C/C++ 程序中可以使用 _SPCPTR 来声明一个space pointer。例如 _SPCPTR spcp; /* A space pointer. */
#2. 在SLS(Single Level Store)中space pointer是16字节。因此,指针的读取和写回操作相对于其他数据类型的开销会更大。
#3. 这里实际是 optimizing translator。Optimizing Translator 主要关注于编译过程中与目标机器相关的部分。这本文中为了描述方便笼统地称之优化编译器。
#4. ILE编译的基本单元是一个模块,所以在编译时编译器无法知道其他模块的信息。
#5. 间接函数调用一般指通过函数指针调用。
#6. C++编译器通过建立虚函数表和虚函数指针实现多态的语言特性。
#7. 基本参数优化的应用范围仅限于一个模块;高级参数优化的应用范围可以是多个模块绑定组成的程序或服务程序。
#8. DTAMDL参数是指定C和C++程序中变量的长度;DTAMDL(*LLP64)是指定C/C++程序中int,long,pointer的字节长度分别是4,4,8。该选项通常是在 CRTCMOD/CRTCPPMOD/CRTBNDC/CRTBNDCPP 命令中被指定。在默认情况下 该选项的值是 DTAMDL(*P128),意味着int,long,pointer的字节长度分别是4,4,16。
#9. ILE C/C++ 语言提供了两个新的修饰符关键字 __ptr128 和 __ptr64。使用__ptr128可以显示地指定一个指针的长度是16字节;同理,__ptr64可以显示地指定一个指针的长度是8字节。例如 int * __ptr128 p; /* space pointer p is 16 bytes in size */

[{"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SWG60","label":"IBM i"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB57","label":"Power"}}]

UID

ibm11146262