一个相当大的共享库(许多模板实例化)的一个 LTO 构建需要相当长的时间(>10 分钟)。现在我了解一些关于该库的信息,并且可以指定某种“黑名单”,以对象文件的形式表示,这些文件 不需要 被一起分析(因为它们之间没有应被内联或其他调用),或者我可以指定应当一起分析的对象文件组。是否有可能在不分割库的情况下实现这一点?
ld
功能,叫做-r
/--relocatable
,可以用来将多个目标文件合并成一个,然后再链接到最终产品中。如果在这里实现LTO(链接时优化),而后面没有实现,那么你就可以得到所需的“部分”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 $0x2a,%eax
615: c3 retq
...
所以main()
被优化为return b();
,而b()
被优化为return 42;
,但是这两组之间没有进行过程序间优化。
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
-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。
然而,尚不清楚这种技术或另一个答案中提出的技术哪个编译速度更快。此外,代码可能没有以完全相同的方式进行优化。因此,应该比较使用每种技术产生的代码的性能。然后可以使用首选技术。
combine
仅适用于C代码,而不适用于C ++。 - Martin Richtarskyld -r
可以与 LTO 一起使用,但并非 OP 想要的方式。它似乎只是将 LTO 信息连接在一起,最终链接器仍会对整个程序进行 LTO。另一方面,gcc -r -nostdlib
貌似可以满足 OP 的需求。 - Tavian Barnesgcc -r -nostdlib
是什么意思?它会生成本地目标文件吗?它能与 LTO 一起使用吗? - Hadi Braisgcc -r
会对所有输入源文件进行LTO优化,并生成一个优化后的本地目标文件?因为这正是OP所需要的。 - Hadi Braisgcc -r
无法工作,这将是一个替代方案。 - Martin Richtarsky您可以通过不使用-flto
选项来完全排除目标文件参与链接时优化的过程。
LTO
,只有在发布候选版本时才打开它。 - Galik-flto=8
(或任何数字或-flto=jobserver
)来获取一些并行性吗? - Marc Glisse-flto=40
了 :) LTO的操作在这里有描述: https://gcc.gnu.org/onlinedocs/gccint/LTO-Overview.html 它分为三个阶段:LGEN、WPA和LTRANS。WPA对代码进行分区,然后LTRANS并行运行在这些分区上。我可以看到在LTRANS阶段大约有15个线程在运行,但应该还有更多。我需要明确指导WPA的分区以改变这种情况。 - Martin Richtarsky