Jen*_*das 12 c++ compiler-construction performance c++11
考虑以下方案.我们有3个文件:
main.cpp中:
int main() {
clock_t begin = clock();
int a = 0;
for (int i = 0; i < 1000000000; ++i) {
a += i;
}
clock_t end = clock();
printf("Number: %d, Elapsed time: %f\n",
a, double(end - begin) / CLOCKS_PER_SEC);
begin = clock();
C b(0);
for (int i = 0; i < 1000000000; ++i) {
b += C(i);
}
end = clock();
printf("Number: %d, Elapsed time: %f\n",
a, double(end - begin) / CLOCKS_PER_SEC);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
class.h:
#include <iostream>
struct C {
public:
int m_number;
C(int number);
void operator+=(const C & rhs);
};
Run Code Online (Sandbox Code Playgroud)
class.cpp
C::C(int number)
: m_number(number)
{
}
void
C::operator+=(const C & rhs) {
m_number += rhs.m_number;
}
Run Code Online (Sandbox Code Playgroud)
使用clang ++和flags编译文件-std=c++11 -O3.
我所期望的是非常相似的性能结果,因为我认为编译器会优化运算符而不是作为函数调用.虽然现实有点不同,但结果如下:
Number: -1243309312, Elapsed time: 0.000003
Number: -1243309312, Elapsed time: 5.375751
Run Code Online (Sandbox Code Playgroud)
我玩了一下,发现,如果我将类.*中的所有代码粘贴到main.cpp中,速度会大大提高,结果非常相似.
Number: -1243309312, Elapsed time: 0.000003
Number: -1243309312, Elapsed time: 0.000003
Run Code Online (Sandbox Code Playgroud)
我意识到这种行为可能是由于main.cpp和class.cpp的编译完全分离,因此编译器无法执行足够的优化.
我的问题:有没有办法保持3文件方案并仍然达到优化级别,好像文件合并为一个而不是编译?我读过一些关于"统一构建"的内容,但这似乎有些过分.
gex*_*ide 18
你想要的是链接时间优化.试试这个问题的答案.即,尝试:
clang++ -O4 -emit-llvm main.cpp -c -o main.bc
clang++ -O4 -emit-llvm class.cpp -c -o class.bc
llvm-link main.bc class.bc -o all.bc
opt -std-compile-opts -std-link-opts -O3 all.bc -o optimized.bc
clang++ optimized.bc -o yourExecutable
Run Code Online (Sandbox Code Playgroud)
您应该看到您的表现达到了将所有内容粘贴到您的表现时的表现main.cpp.
问题是编译器无法在链接期间内联您的重载操作符,因为它不再以可用于内联它的形式定义其定义(它不能内联裸机器代码).因此,操作符调用main.cpp将保留对声明的函数的实际函数调用class.cpp.与简单的内联添加相比,函数调用非常昂贵,其可以进一步优化(例如,矢量化).
启用链接时优化时,编译器可以执行此操作.如上所述,您首先创建llvm中间表示字节代码(.bc文件,我将在下文中简称为llvm代码)而不是机器代码.然后,您将这些文件链接到一个新.bc文件,该文件仍然包含llvm代码而不是机器代码.与机器代码相比,编译器能够在llvm代码上执行内联.opt是llvm优化器(确保安装llvm),它执行内联和进一步的链接时间优化.然后,我们调用clang++最后一次从优化的llvm代码生成可执行的机器代码.
上面的答案仅适用于铿锵声.GCC(g ++)用户必须-flto在编译期间和链接期间使用该标志以启用链接时间优化.它比clang更简单,只需添加-flto到处:
g++ -c -O2 -flto main.cpp
g++ -c -O2 -flto class.cpp
g++ -o myprog -flto -O2 main.o class.o
Run Code Online (Sandbox Code Playgroud)