gcc LTO:限制优化范围
gcc LTO: Limit scope of optimization
相当大的共享库(许多模板实例化)的 LTO 构建需要相当长的时间(> 10 分钟)。现在我知道了一些关于这个库的事情,并且可以指定某种 "blacklist" 形式的目标文件 不需要 一起分析(因为没有它们之间的调用应该是内联的),或者我可以指定 应该 一起分析的目标文件组。这是否可能(不拆分库)?
您可以完全从 link 时间优化过程中排除对象文件,只需在没有 -flto
的情况下构建它即可。
假设您要将 a.c
和 b.c
作为一组进行优化,将 c.c
和 d.c
作为另一组进行优化。您可以按如下方式使用 -combine
GCC 开关:
$ gcc -O3 -c -combine a.c b.c -o group1.o
$ gcc -O3 -c -combine c.c d.c -o group2.o
请注意,您不需要使用 LTO,因为 -combine
开关在优化代码之前会合并多个源代码文件。
编辑
-combine
目前仅支持 C 代码。实现此目的的另一种方法是使用 #include
指令,如下所示:
// file group1.cpp
#include "a.cpp"
#include "b.cpp"
// file group2.cpp
#include "c.cpp"
#include "d.cpp"
然后可以在不使用 LTO 的情况下编译它们,如下所示:
g++ -O3 group1.cpp group2.cpp
这有效地模拟了分组或部分 LTO。
但是,尚不清楚这种技术还是 中提出的技术编译速度更快。此外,代码可能不会以完全相同的方式进行优化。因此,应比较使用每种技术生成的代码的性能。然后可以使用首选技术。
ld
有一个 little-used 功能,称为 -r
/--relocatable
,可用于将多个目标文件合并为一个,稍后可以链接到最终产品。如果可以让 LTO 在这里发生,但不是以后,您可以拥有您正在寻找的那种 "partial" LTO。
遗憾的是ld -r
行不通;它只是组合了所有 LTO 信息,以便稍后处理。但通过 gcc 驱动程序 (gcc -r
) 调用它似乎有效:
a.c
int a() {
return 42;
}
b.c
int a(void);
int b() {
return a();
}
c.c
int b(void);
int c() {
return b();
}
d.c
int c(void);
int main() {
return c();
}
$ gcc -O3 -flto -c [a-d].c
$ gcc -O3 -r -nostdlib a.o b.o -o g1.o
$ gcc -O3 -r -nostdlib c.o d.o -o g2.o
$ gcc -O3 -fno-lto g1.o g2.o
$ objdump -d a.out
...
00000000000004f0 <main>:
4f0: e9 1b 01 00 00 jmpq 610 <b>
...
0000000000000610 <b>:
610: b8 2a 00 00 00 mov [=14=]x2a,%eax
615: c3 retq
...
所以main()
被优化为return b();
,b()
被优化为return 42;
,但是两组之间没有过程间优化。
相当大的共享库(许多模板实例化)的 LTO 构建需要相当长的时间(> 10 分钟)。现在我知道了一些关于这个库的事情,并且可以指定某种 "blacklist" 形式的目标文件 不需要 一起分析(因为没有它们之间的调用应该是内联的),或者我可以指定 应该 一起分析的目标文件组。这是否可能(不拆分库)?
您可以完全从 link 时间优化过程中排除对象文件,只需在没有 -flto
的情况下构建它即可。
假设您要将 a.c
和 b.c
作为一组进行优化,将 c.c
和 d.c
作为另一组进行优化。您可以按如下方式使用 -combine
GCC 开关:
$ gcc -O3 -c -combine a.c b.c -o group1.o
$ gcc -O3 -c -combine c.c d.c -o group2.o
请注意,您不需要使用 LTO,因为 -combine
开关在优化代码之前会合并多个源代码文件。
编辑
-combine
目前仅支持 C 代码。实现此目的的另一种方法是使用 #include
指令,如下所示:
// file group1.cpp
#include "a.cpp"
#include "b.cpp"
// file group2.cpp
#include "c.cpp"
#include "d.cpp"
然后可以在不使用 LTO 的情况下编译它们,如下所示:
g++ -O3 group1.cpp group2.cpp
这有效地模拟了分组或部分 LTO。
但是,尚不清楚这种技术还是
ld
有一个 little-used 功能,称为 -r
/--relocatable
,可用于将多个目标文件合并为一个,稍后可以链接到最终产品。如果可以让 LTO 在这里发生,但不是以后,您可以拥有您正在寻找的那种 "partial" LTO。
遗憾的是ld -r
行不通;它只是组合了所有 LTO 信息,以便稍后处理。但通过 gcc 驱动程序 (gcc -r
) 调用它似乎有效:
a.c
int a() { return 42; }
b.c
int a(void); int b() { return a(); }
c.c
int b(void); int c() { return b(); }
d.c
int c(void); int main() { return c(); }
$ gcc -O3 -flto -c [a-d].c
$ gcc -O3 -r -nostdlib a.o b.o -o g1.o
$ gcc -O3 -r -nostdlib c.o d.o -o g2.o
$ gcc -O3 -fno-lto g1.o g2.o
$ objdump -d a.out
...
00000000000004f0 <main>:
4f0: e9 1b 01 00 00 jmpq 610 <b>
...
0000000000000610 <b>:
610: b8 2a 00 00 00 mov [=14=]x2a,%eax
615: c3 retq
...
所以main()
被优化为return b();
,b()
被优化为return 42;
,但是两组之间没有过程间优化。