ThinLTO

简介

ThinLTO 编译是一种新型的 LTO,它既可扩展又可增量。LTO(链接时优化)通过全程序分析和跨模块优化来实现更好的运行时性能。但是,单片 LTO 通过将所有输入合并到一个模块中来实现这一点,这在时间或内存方面不可扩展,并且还阻止了快速增量编译。

在 ThinLTO 模式下,与常规 LTO 一样,clang 在编译阶段后发出 LLVM 位码。ThinLTO 位码通过模块的简要摘要进行增强。在链接步骤中,仅读取摘要并将其合并到组合摘要索引中,该索引包括函数位置的索引,以便在以后进行跨模块函数导入。然后对组合摘要索引执行快速有效的全程序分析。

但是,所有转换(包括函数导入)都在以后模块在完全并行后端中优化时发生。默认情况下,链接器 支持 ThinLTO 被设置为在线程中启动 ThinLTO 后端。因此,使用模型不受影响,因为快速串行薄链接步骤和后端之间的区别对用户来说是透明的。

有关 ThinLTO 设计和当前性能的更多信息,请参见 LLVM 博客文章 ThinLTO:可扩展和增量 LTO。虽然调整仍在进行中,但博客文章中的结果表明,ThinLTO 与 LTO 相比已经表现良好,在许多情况下都与性能改进相匹配。

当前状态

Clang/LLVM

clang 的 3.9 版本包含 ThinLTO 支持。但是,ThinLTO 正在积极开发中,并且正在为下一个版本添加新功能、改进和错误修复。有关最新的 ThinLTO 支持,请构建最新版本的 clang 和 LLVM

链接器

目前,ThinLTO 支持以下链接器

用法

基础

要利用 ThinLTO,只需将 -flto=thin 选项添加到编译和链接中。例如

% clang -flto=thin -O2 file1.c file2.c -c
% clang -flto=thin -O2 file1.o file2.o -o a.out

使用 lld-link 时,仅需将 -flto 选项添加到编译步骤中

% clang-cl -flto=thin -O2 -c file1.c file2.c
% lld-link /out:a.exe file1.obj file2.obj

如前所述,默认情况下,链接器将并行启动 ThinLTO 后端线程,并将生成的本机目标文件传递回链接器以进行最终本机链接。因此,使用模型与非 LTO 相同。

使用 gold 时,如果在链接过程中看到以下形式的错误

/usr/bin/ld: error: /path/to/clang/bin/../lib/LLVMgold.so: could not load plugin library: /path/to/clang/bin/../lib/LLVMgold.so: cannot open shared object file: No such file or directory

那么要么 gold 未配置为启用插件,要么 clang 未在构建时正确设置 -DLLVM_BINUTILS_INCDIR。请参阅LLVM gold 插件 的说明。

控制后端并行度

默认情况下,ThinLTO 链接步骤将并行启动与内核数一样多的线程。如果无法为体系结构计算内核数,那么它将并行启动 std::thread::hardware_concurrency 个线程。对于支持超线程的机器,这是虚拟内核的总数。对于某些应用程序和机器配置,这可能过于激进,在这种情况下,可以通过以下方式将并行度减少到 N

  • gold:-Wl,-plugin-opt,jobs=N

  • ld64:-Wl,-mllvm,-threads=N

  • ld.lld、ld64.lld:-Wl,--thinlto-jobs=N

  • lld-link:/opt:lldltojobs=N

N 的其他可能值是

  • 0:每个物理内核使用一个线程(默认)

  • 1:仅使用一个线程(禁用多线程)

  • all:每个逻辑内核使用一个线程(使用所有超线程)

增量

ThinLTO 通过使用缓存来支持快速增量构建,该缓存当前必须通过链接器选项启用。

  • gold(从 LLVM 4.0 开始):-Wl,-plugin-opt,cache-dir=/path/to/cache

  • ld64(从 clang 3.9 和 Xcode 8 开始支持)和 Mach-O ld64.lld(从 LLVM 15.0 开始):-Wl,-cache_path_lto,/path/to/cache

  • ELF ld.lld(从 LLVM 5.0 开始):-Wl,--thinlto-cache-dir=/path/to/cache

  • COFF lld-link(从 LLVM 6.0 开始):/lldltocache:/path/to/cache

缓存修剪

为了帮助控制缓存的大小,ThinLTO 支持缓存修剪。缓存修剪在 gold、ld64 和 lld 中受支持,但目前只有 gold 和 lld 允许您使用策略字符串来控制策略。缓存策略必须使用链接器选项指定。

  • gold(从 LLVM 6.0 开始):-Wl,-plugin-opt,cache-policy=POLICY

  • ELF ld.lld(从 LLVM 5.0 开始)、Mach-O ld64.lld(从 LLVM 15.0 开始):-Wl,--thinlto-cache-policy=POLICY

  • COFF lld-link(从 LLVM 6.0 开始):/lldltocachepolicy:POLICY

策略字符串是一系列由 : 字符分隔的键值对。可能的键值对是

  • cache_size=X%:缓存目录的最大大小是磁盘可用空间的 X%。设置为 100 表示没有限制,设置为 50 表示缓存大小不会超过磁盘可用空间的一半。大于 100 的值无效。值为 0 表示禁用基于百分比大小的修剪。默认值为 75%。

  • cache_size_bytes=Xcache_size_bytes=Xkcache_size_bytes=Xmcache_size_bytes=Xg:将缓存目录的最大大小设置为 X 字节(或 KB、MB、GB 分别)。超过磁盘可用空间的值将减少到磁盘可用空间的值。值为 0 表示禁用基于字节大小的修剪。默认情况下没有基于字节大小的修剪。

    请注意,ThinLTO 将同时应用两种基于大小的修剪策略,更改一种策略不会影响另一种策略。例如,仅 cache_size_bytes=1g 的策略会导致应用 1GB 和默认的 75% 策略,除非覆盖了默认的 cache_size

  • cache_size_files=X:设置缓存目录中的最大文件数。设置为 0 表示没有限制。默认值为 1000000 个文件。

  • prune_after=Xsprune_after=Xmprune_after=Xh:将缓存文件的过期时间设置为 X 秒(或分钟、小时分别)。当文件未被访问 prune_after 秒时,它将从缓存中删除。值为 0 表示禁用基于过期时间的修剪。默认值为 1 周。

  • prune_interval=Xsprune_interval=Xmprune_interval=Xh:将修剪间隔设置为 X 秒(或分钟、小时分别)。这旨在用于避免过于频繁地扫描目录。它不会影响修剪哪些文件的决定。值为 0 表示强制进行扫描。默认值为每 20 分钟。

Clang 自举

要使用 ThinLTO 自举 clang/LLVM,请按照以下步骤操作

  1. 主机编译器 必须是支持 ThinLTO 的 clang 版本。

  2. 主机链接器 必须支持 ThinLTO(并且在 gold 的情况下,必须配置为启用插件)。

  3. 在配置自举编译器构建时,使用以下附加CMake 变量

  • -DLLVM_ENABLE_LTO=Thin

  • -DCMAKE_C_COMPILER=/path/to/host/clang

  • -DCMAKE_CXX_COMPILER=/path/to/host/clang++

  • -DCMAKE_RANLIB=/path/to/host/llvm-ranlib

  • -DCMAKE_AR=/path/to/host/llvm-ar

或者,在 Windows 上

  • -DLLVM_ENABLE_LTO=Thin

  • -DCMAKE_C_COMPILER=/path/to/host/clang-cl.exe

  • -DCMAKE_CXX_COMPILER=/path/to/host/clang-cl.exe

  • -DCMAKE_LINKER=/path/to/host/lld-link.exe

  • -DCMAKE_RANLIB=/path/to/host/llvm-ranlib.exe

  • -DCMAKE_AR=/path/to/host/llvm-ar.exe

  1. 要使用其他链接器参数来控制后端并行度 或启用自举编译器的增量 构建,在配置构建后,修改构建目录中生成的 CMakeCache.txt 文件。在 CMAKE_EXE_LINKER_FLAGS:STRING= 之后指定任何其他链接器选项。请注意,如果在前面的步骤中直接指定了链接器插件选项,则配置可能会失败。

BOOTSTRAP_LLVM_ENABLE_LTO=Thin 将为阶段 2 和阶段 3 启用 ThinLTO,以防用于阶段 1 的编译器不支持 ThinLTO 选项。

更多信息