我有一个大的 Swig Python 模块。C++ 包装器最终大约是 320,000 LoC(包括我猜的标头)。我目前使用 -O1 编译它,g++ 生成一个大小为 44MiB 的二进制文件,编译大约需要 3 分钟。
如果我关闭优化 (-O0),则二进制文件的大小为 40MiB,编译需要 44 秒。
使用 -O0 编译包装器会显着损害 python 模块的性能吗?在我去分析模块在不同优化级别的性能之前,有没有人做过这种分析或者对它是否重要有任何见解?
我有一个大的 Swig Python 模块。C++ 包装器最终大约是 320,000 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 生成的包装器有害:
死码消除:
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 包装器和任何其他程序一样都是如此,如果不是更多的话,因为自动生成的代码的风格。