C++ 优化级别会影响 Swig Python 模块性能吗

Posted

技术标签:

【中文标题】C++ 优化级别会影响 Swig Python 模块性能吗【英文标题】:Does C++ optimisation level affect Swig Python module performance 【发布时间】:2012-12-09 20:40:01 【问题描述】:

我有一个大型 Swig Python 模块。 C++ 包装器最终大约为 320,000 LoC(包括我猜的标头)。我目前使用 -O1 编译它,g++ 生成一个大小为 44MiB 的二进制文件,编译大约需要 3 分钟。

如果我关闭优化 (-O0),二进制输出为 40MiB,编译需要 44 秒。

使用 -O0 编译包装器会显着损害 python 模块的性能吗?在我去分析模块在不同优化级别的性能之前,有没有人做过这种分析或者对它是否重要有任何见解?

【问题讨论】:

【参考方案1】:

-O0 禁用 gcc 执行的所有优化。优化很重要。

因此,如果对您的应用程序没有太多了解,我可能会建议这会损害您的应用程序的性能。

使用的通常安全的优化级别是 -O2。

您可以在以下位置查看 GCC 执行的优化类型: http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html.

但最后,如果您想确切知道,您应该在不同的级别和配置文件上进行编译。

【讨论】:

谢谢,我明白了。我想知道是否有人对 Swig 包装器优化有任何具体经验。 Google 搜索未显示任何已发布的内容。【参考方案2】:

无论是否使用 SWIG 模块,这都是不好的。即使使用gcc -O1 也会发生许多优化,如果您阻止它们发生,您将错过这些优化。

您可以通过检查您选择的编译器生成的 asm 来检查差异。其中我知道的这些将对 SWIG 生成的包装器有害:

    死代码消除:

    void foo() 
      int a = 1;
      a = 0;
    
    

    使用 -O1,这个完全没有意义的代码将被完全删除:

    foo:
            pushl   %ebp
            movl    %esp, %ebp
            popl    %ebp
            ret
    

    而使用 -O0 则变为:

    foo:
            pushl   %ebp
            movl    %esp, %ebp
            subl    $16, %esp
            movl    $1, -4(%ebp)
            movl    $0, -4(%ebp)
            leave
            ret
    

    在具有大量局部变量的函数中,寄存器分配将受到不利影响 - 大多数 SWIG 包装函数都会因此受到影响。不过,很难给出一个简洁的例子。

    另一个例子,gcc 为原型编译 SWIG 包装器的输出:

    int foo(unsigned int a, unsigned int b, unsigned int c,  unsigned int d);
    

    使用-O0 生成:

    Java_testJNI_foo:
            pushl   %ebp
            movl    %esp, %ebp
            subl    $88, %esp
            movl    16(%ebp), %eax
            movl    %eax, -48(%ebp)
            movl    20(%ebp), %eax
            movl    %eax, -44(%ebp)
            movl    24(%ebp), %eax
            movl    %eax, -56(%ebp)
            movl    28(%ebp), %eax
            movl    %eax, -52(%ebp)
            movl    32(%ebp), %eax
            movl    %eax, -64(%ebp)
            movl    36(%ebp), %eax
            movl    %eax, -60(%ebp)
            movl    40(%ebp), %eax
            movl    %eax, -72(%ebp)
            movl    44(%ebp), %eax
            movl    %eax, -68(%ebp)
            movl    $0, -32(%ebp)
            movl    -48(%ebp), %eax
            movl    %eax, -28(%ebp)
            movl    -56(%ebp), %eax
            movl    %eax, -24(%ebp)
            movl    -64(%ebp), %eax
            movl    %eax, -20(%ebp)
            movl    -72(%ebp), %eax
            movl    %eax, -16(%ebp)
            movl    -16(%ebp), %eax
            movl    %eax, 12(%esp)
            movl    -20(%ebp), %eax
            movl    %eax, 8(%esp)
            movl    -24(%ebp), %eax
            movl    %eax, 4(%esp)
            movl    -28(%ebp), %eax
            movl    %eax, (%esp)
            call    foo
            movl    %eax, -12(%ebp)
            movl    -12(%ebp), %eax
            movl    %eax, -32(%ebp)
            movl    -32(%ebp), %eax
            leave
            ret
    

    -O1 相比,它只生成:

    Java_testJNI_foo:
            pushl   %ebp
            movl    %esp, %ebp
            subl    $24, %esp
            movl    40(%ebp), %eax
            movl    %eax, 12(%esp)
            movl    32(%ebp), %eax
            movl    %eax, 8(%esp)
            movl    24(%ebp), %eax
            movl    %eax, 4(%esp)
            movl    16(%ebp), %eax
            movl    %eax, (%esp)
            call    foo
            leave
            ret
    

    使用-O1 g++ 可以生成更智能的代码:

    %module test
    
    %
    int value()  return 100; 
    %
    
    %feature("compactdefaultargs") foo;
    
    %inline %
      int foo(int a=value(), int b=value(), int c=value()) 
        return 0;
      
    %
    

简短的回答是完全禁用优化 GCC 生成极其幼稚的代码 - 与任何其他程序一样,SWIG 包装器也是如此,如果不是更多考虑到自动生成代码的样式的话。

【讨论】:

感谢您的详细回答。我仍然对为什么 -O0 产生比 -O1 更小的二进制文件感到困惑。我会更仔细地检查生成的代码并报告。

以上是关于C++ 优化级别会影响 Swig Python 模块性能吗的主要内容,如果未能解决你的问题,请参考以下文章

SWIG:你能否使用 SWIG 专门使用 C++ 头文件使 C++ 在 Python 中可用?

SWIG:将其参数从 c++ 修改为 python 的函数

无法使用 SWIG 在 Python 中实例化 C++ 类(获取属性错误)

如何使用 SWIG 在 C++ API 上生成 C 包装器? [复制]

在 SWIG 中携带自定义 Python 数据的 C++ 对象

SWIG 将 C++ 扩展到 Python,未定义的枚举