C++优化级别是否影响Swig Python模块性能?

4

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

如果我关闭优化(-O0),那么二进制文件大小为40MiB,编译需要44秒。

使用-O0编译包装器是否会显著影响Python模块的性能?在我分析不同优化级别下模块性能之前,是否有人做过这种分析或者有任何见解呢?

2个回答

3
-O0会关闭gcc执行的所有优化。而优化对性能至关重要。
因此,如果您的应用程序没有很多知识,我建议这将损害您的应用程序的性能。
通常安全的优化级别是-O2。
您可以在以下网址中检查GCC执行的优化类型: http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
但最终,如果您想确切知道该如何编译不同级别并进行分析。

谢谢,我明白了。我想知道是否有人在Swig包装器优化方面有具体经验。谷歌搜索没有显示任何已发布的内容。 - elesueur

2

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

您可以通过检查所选编译器生成的汇编代码来检查差异。其中一些我知道很容易对SWIG生成的包装器造成负面影响:

  1. Dead code elimination:

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

    With -O1 this entirely pointless code gets totally removed:

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

    whereas with -O0 it becomes:

    foo:
            pushl   %ebp
            movl    %esp, %ebp
            subl    $16, %esp
            movl    $1, -4(%ebp)
            movl    $0, -4(%ebp)
            leave
            ret
    
  2. Register allocation will be detrimentally impacted in functions with lots of local variables - most SWIG wrapper functions will see a hit from this. It's hard to show a concise example of this though.

  3. Another example, the output from gcc compiling the SWIG wrapper for the prototype:

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

    Generates with -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
    

    Compared to -O1 which generates just:

    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
    
  4. With -O1 g++ can generate far smarter code for:

    %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更小。我将更仔细地检查生成的代码并回报。 - elesueur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接