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

Does C++ optimisation level affect Swig Python module performance

本文关键字:Python Swig 模块 性能 影响 优化 是否 C++      更新时间:2023-10-16

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

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

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

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

因此,如果您的应用程序中没有太多知识,我可能会认为这会影响应用程序的性能。

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

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

但最后,如果你想确切地知道,你应该在不同的级别和概要进行编译。

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

您可以通过检查所选编译器生成的asm来检查差异。其中,我非常了解的那些将对SWIG生成的包装器有害:

  1. 死码消除:

    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
    
  2. 在具有大量局部变量的函数中,寄存器分配将受到不利影响——大多数SWIG包装函数都会受到影响。不过,很难给出一个简洁的例子。

  3. 另一个例子是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
    
  4. 使用-O1g++可以为生成更智能的代码

    %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包装器和任何其他程序都是如此,如果不是更多地考虑到自动生成代码的风格的话。