LLVM的ThinLTO编译优化技术在Postgresql中的应用

news2024/12/25 8:55:20

部分内容引用:https://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html

LTO是什么?

链接时优化(Link-time optimization,简称LTO)是编译器在链接时对程序进行的一种优化。它适用于以文件为单位编译程序,然后将这些文件链接在一起的编程语言(如C和Fortran),而不是一次性编译(如Java的即时编译(JIT))。

传统上,编译器将所有文件分别编译成目标文件,然后将这些目标文件链接成一个单独的可执行文件。然而,在GNU编译器集合(GCC)和LLVM中实现的LTO中,编译器能够转储其中间表示(IR),即GIMPLE字节码或LLVM字节码,以便在最终链接时将组成单个可执行文件的所有不同编译单元作为单个模块进行优化。这扩大了跨过程优化的范围,涵盖了整个程序(或者更准确地说,链接时可见的所有内容)。通过链接时优化,编译器可以对整个程序应用各种形式的跨过程优化,进行更深入的分析、更多的优化,从而实现更好的程序性能。

实际上,LTO并不总是对整个程序进行优化,特别是动态链接的共享对象等库函数会被有意排除在外,以避免过多的重复和允许更新。静态链接自然适用于LTO的概念,但它只适用于包含IR对象而不是仅包含机器码的库存档文件。由于性能问题,甚至不总是直接使用整个单元,可以将程序分割成类似GCC的WHOPR的分而治之的LTO形式。当构建的程序本身是一个库时,优化会保留每个外部可用(导出的)符号,而不会过于努力地将它们作为DCE的一部分删除。

即使没有LTO,仍然可以使用一种更有限的WPO形式,例如GCC的-fwhole-program开关。这种模式使GCC假设正在编译的模块包含整个程序的入口点,因此其中的其他函数不会被外部使用,可以安全地进行优化。由于它仅适用于单个模块,因此无法真正涵盖整个程序。它可以与LTO结合使用,以一大模块的方式,这在链接器不会向GCC反馈外部使用的入口点或符号时非常有用。

LLVM提供的lto独立工具:

$ llvm-lto --help
OVERVIEW: llvm LTO linker

USAGE: llvm-lto [options] <input bitcode files>

OPTIONS:

Color Options:

  --color                                 - Use colors in output (default=autodetect)

Generic Options:

  --help                                  - Display available options (--help-hidden for more)
  --help-list                             - Display list of available options (--help-list-hidden for more)
  --version                               - Display the version of this program

LTO Options:

  -O <char>                               - Optimization level. [-O0, -O1, -O2, or -O3] (default = '-O2')
  --check-for-objc                        - Only check if the module has objective-C defined in it
  --disable-verify                        - Do not run the verifier during the optimization pipeline
  --dso-symbol=<string>                   - Symbol to put in the symtab in the resulting dso
  --exported-symbol=<string>              - List of symbols to export from the resulting object file
  -j <uint>                               - Number of backend threads
  --list-dependent-libraries-only         - Instead of running LTO, list the dependent libraries in each IR file
  --list-symbols-only                     - Instead of running LTO, list the symbols in each IR file
  --lto-freestanding                      - Enable Freestanding (disable builtins / TLI) during LTO
  -o <filename>                           - Override output filename
  --print-macho-cpu-only                  - Instead of running LTO, print the mach-o cpu in each IR file
  --restore-linkage                       - Restore original linkage of globals prior to CodeGen
  --save-linked-module                    - Write linked LTO module to file before optimize
  --save-merged-module                    - Write merged LTO module to file before CodeGen
  --set-merged-module                     - Use the first input module as the merged module
  --thinlto                               - Only write combined global index for ThinLTO backends
  --thinlto-action=<value>                - Perform a single ThinLTO stage:
    =thinlink                             -   ThinLink: produces the index by linking only the summaries.
    =distributedindexes                   -   Produces individual indexes for distributed backends.
    =emitimports                          -   Emit imports files for distributed backends.
    =promote                              -   Perform pre-import promotion (requires -thinlto-index).
    =import                               -   Perform both promotion and cross-module importing (requires -thinlto-index).
    =internalize                          -   Perform internalization driven by -exported-symbol (requires -thinlto-index).
    =optimize                             -   Perform ThinLTO optimizations.
    =codegen                              -   CodeGen (expected to match llc)
    =run                                  -   Perform ThinLTO end-to-end
  --thinlto-cache-dir=<string>            - Enable ThinLTO caching.
  --thinlto-cache-entry-expiration=<uint> - Set ThinLTO cache entry expiration time.
  --thinlto-cache-max-size-bytes=<ulong>  - Set ThinLTO cache pruning directory maximum size in bytes.
  --thinlto-cache-max-size-files=<int>    - Set ThinLTO cache pruning directory maximum number of files.
  --thinlto-cache-pruning-interval=<int>  - Set ThinLTO cache pruning interval.
  --thinlto-index=<string>                - Provide the index produced by a ThinLink, required to perform the promotion and/or importing.
  --thinlto-index-stats                   - Print statistic for the index in every input files
  --thinlto-module-id=<string>            - For the module ID for the file to process, useful to match what is in the index.
  --thinlto-prefix-replace=<string>       - Control where files for distributed backends are created. Expects 'oldprefix;newprefix' and if path prefix of output file is oldprefix it will be replaced with newprefix.
  --thinlto-save-objects=<string>         - Save ThinLTO generated object files using filenames created in the given directory.
  --thinlto-save-temps=<string>           - Save ThinLTO temp files using filenames created by adding suffixes to the given file path prefix.
  --use-diagnostic-handler                - Use a diagnostic handler to test the handler interface

那么thinlto是什么?

LTO背景和动机

LTO(Link Time Optimization)是通过整个程序分析和跨模块优化来实现更好的运行时性能的一种方法。在编译阶段,clang会生成LLVM字节码而不是目标文件。链接器识别这些字节码文件,并在链接过程中调用LLVM来生成构成可执行文件的最终对象。LLVM实现会加载所有输入的字节码文件,并将它们合并成一个单独的模块。在这个庞大的模块上,进行了跨过程的分析(IPA)和跨过程的优化(IPO),这些优化是串行进行的。

在这里插入图片描述
在实践中,这意味着LTO通常需要大量的内存(一次性保存所有IR)并且非常慢。而且,如果通过-g启用了调试信息,IR的大小和所需的内存要求会显著增加。即使没有调试信息,这对于非常大的应用程序或在内存受限的机器上进行编译也是不可行的。这也使得增量构建变得不太有效,因为当任何输入源发生变化时,从LTO步骤开始的所有内容都必须重新执行。

ThinLTO是什么?

ThinLTO是一种新的方法,旨在像非LTO构建一样具有可扩展性,同时保留了完整LTO的大部分性能优势。

在ThinLTO中,串行步骤非常轻量且快速。这是因为它不是加载bitcode并合并单个庞大模块来执行这些分析,而是在串行链接步骤中利用每个模块的摘要进行全局分析,以及用于后续跨模块导入的函数位置索引。函数导入和其他IPO转换是在模块在完全并行的后端进行优化时执行的。

ThinLTO全局分析所启用的关键转换是函数导入,只有可能进行内联的函数被导入到每个模块中。这最大程度地减少了每个ThinLTO后端的内存开销,同时最大化了最有影响力的跨模块优化机会。因此,IPO转换是在每个扩展了其导入函数的模块上执行的。

ThinLTO过程分为3个阶段:

  1. 编译:生成带有模块摘要的IR,与完整LTO模式相同,
  2. Thin链接:thin链接器插件层,用于合并摘要并执行全局分析
  3. ThinLTO后端:基于摘要的导入和优化的并行后端(默认情况下,支持ThinLTO的链接器被设置为在线程中启动ThinLTO后端。因此,第二阶段和第三阶段之间的区别对用户来说是透明的)
    在这里插入图片描述

这个过程的关键是在第一阶段发出的摘要。

这些摘要使用位码格式发出,但设计得可以单独加载,而不涉及LLVMContext或任何其他昂贵的构造。每个全局变量和函数在模块摘要中都有一个条目。条目包含抽象描述该符号的元数据。例如,函数使用其链接类型、包含的指令数量和可选的分析信息(PGO)进行抽象化。此外,还记录了对其他全局变量的每个引用(地址引用、直接调用)。这些信息在Thin链接阶段期间构建了完整的引用图,并使用全局摘要信息进行快速分析。

总结:

ThinLTO的核心思想是将程序分为多个模块,每个模块都可以独立地进行编译和优化。然后,通过使用一个索引文件(称为"summary")来跟踪每个模块的信息,以便在链接阶段进行全局的优化。这种方式可以减少编译时间和内存消耗,同时仍能够实现类似于WPO的优化效果。

Postgresql中使用thinlto技术生成带有模块摘要的IR

PG根目录下的Makefile.golbal.in中增加了对LLVM的支持,位置:

# Install LLVM bitcode module (for JITing).
#
# The arguments are:
# $(1) name of the module (e.g. an extension's name or postgres for core code)
# $(2) source objects, with .o suffix
#
# The many INSTALL_DATA invocations aren't particularly fast, it'd be
# good if we could coalesce them, but I didn't find a good way.
#
# Note: blank line at end of macro is necessary to let it be used in foreach
define install_llvm_module
$(MKDIR_P) '$(DESTDIR)${bitcodedir}/$(1)'
$(MKDIR_P) $(sort $(dir $(addprefix '$(DESTDIR)${bitcodedir}'/$(1)/, $(2))))
$(foreach obj, ${2}, $(INSTALL_DATA) $(patsubst %.o,%.bc, $(obj)) '$(DESTDIR)${bitcodedir}'/$(1)/$(dir $(obj))
)
cd '$(DESTDIR)${bitcodedir}' && $(LLVM_BINPATH)/llvm-lto -thinlto -thinlto-action=thinlink -o $(1).index.bc $(addprefix $(1)/,$(patsubst %.o,%.bc, $(2)))

endef

install_llvm_module函数中调用了llvm-lto -thinlto -thinlto-action=thinlink生成摘要文件:postgres.index.bc
在这里插入图片描述
postgres.index.bc只有2.7MB显然没有保存所有bitcode。通过llvm-dis反解成ll看下里面保存了什么:
在这里插入图片描述
在这里插入图片描述

  • 索引文件前半部分中保存了文件的bc路径、bc的moduleid。
  • 索引文件后半部分保存了全局变量、函数的信息,包括自身的全局guid、所属bc的moduleid、函数的连接类型、可见性、能否内联、能否抛出异常等等信息。

Postgresql如何加载使用postgres.index.bc

在llvm_load_summary中使用getModuleSummaryIndex加载postgres.index.bc,最后读取到defaultSearchPath中使用。

static std::unique_ptr<llvm::ModuleSummaryIndex>
llvm_load_summary(llvm::StringRef path)
{
	llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer> > MBOrErr =
		llvm::MemoryBuffer::getFile(path);

	if (std::error_code EC = MBOrErr.getError())
	{
		ilog(DEBUG1, "failed to open %s: %s", path.data(),
			 EC.message().c_str());
	}
	else
	{
		llvm::MemoryBufferRef ref(*MBOrErr.get().get());

		llvm::Expected<std::unique_ptr<llvm::ModuleSummaryIndex> > IndexOrErr =
			llvm::getModuleSummaryIndex(ref);
		if (IndexOrErr)
			return std::move(IndexOrErr.get());
		elog(FATAL, "failed to load summary \"%s\": %s",
			 path.data(),
			 toString(IndexOrErr.takeError()).c_str());
	}
	return nullptr;
}

代码流程:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1646178.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

博客系统项目测试报告

文章目录 一.报告概要二.测试环境三.手工测试用例四.编写测试用例五.自动化测试Selenium测试项目主要特点 一.报告概要 项目概要 本项目是一个全功能的个人博客系统&#xff0c;旨在提供一个用户友好、功能全面的平台&#xff0c;允许用户注册、登录、浏览博客、查看详细内容、…

嵌入式学习

笔记 作业 有如下结构体 struct Student{ char name[16]; int age; double math_score; double chinese_score; double english_score; double physics_score; double chemistry…

Linux用户日志审计系统

标题日期版本说明作者 用户日志审计系统 2024.05.06v.0.0.1权限lgb 测试环境&#xff1a;CentOS Stream 9 测试过程&#xff1a; 测试开始前&#xff0c;首先我们先建立一个用户。 将文件备份。 我们通过vim编辑器&#xff0c;打开 /etc/profile 文件进行编辑。 将提前编辑好…

【C语言】第一个C程序:hello world

printf简介 printf是C语言提供的库函数&#xff0c;可以在屏幕上打印格式化数据。这里不作展开&#xff0c;只需要知道&#xff0c;如果要打印hello world&#xff0c;就把双引号引起来的"hello world"作为参数传给printf就行了。如果想要在打印后换行&#xff0c;要…

Scratch编程v3.29.1少儿编程工具

软件介绍 SCRATCH是一款由麻省理工学院&#xff08;MIT&#xff09;媒体实验室开发的图形化编程语言和集成开发环境&#xff08;IDE&#xff09;。它的目标是让编程变得有趣、直观且易学&#xff0c;尤其是针对儿童和青少年群体。通过SCRATCH&#xff0c;用户可以通过拖放代码…

python安装问题及解决办法(pip不是内部或外部命令也不是可运行)

pip是python的包管理工具&#xff0c;使python可在cmd&#xff08;命令行窗口&#xff0c;WinR后输入cmd&#xff09;中执行 针对 “pip不是内部或外部命令也不是可运行” 问题&#xff0c;需要在安装的时候将python添加到环境变量中 上图第三个选项必须勾选才能在cmd中使用pi…

今日详解,教你如何不直播在视频号卖货

大家好&#xff0c;我是电商笨笨熊 视频号作为背靠微信的平台&#xff0c;从不需要考虑自身的流量问题&#xff0c; 因此在视频号推出之后就有大批的主播从其他平台转入视频号&#xff1b; 而这时候很多普通人应该也发现了新的机会&#xff0c;不再去内卷抖音、快手直播&…

(论文阅读-优化器)Orca: A Modular Query Optimizer Architecture for Big Data

目录 摘要 一、简介 二、背景知识 2.1 大规模并行处理 2.2 SQL on Hadoop 三、Orca架构 四、查询优化 4.1 优化工作流 4.2 并行查询优化 五、Metadata Exchange 六、可行性 6.1 Minimal Repros 6.2 优化器准确性测试 七、实验 八、相关工作 8.1 查询优化基础 8…

语音识别简介

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计3077字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

微积分 --- 偏导数,方向导数与梯度(二)

方向导数 上图为一温度图&#xff0c;所反映的是加利福利亚洲和内华达州在十月的一天下午三点的温度。其中&#xff0c;图中的每一点都是温度T关于x,y的函数&#xff0c;即T(x,y)。对于图中的Reno市而言&#xff0c;沿着x方向的偏导反映的是温度沿着x方向&#xff0c;即沿着东方…

虚拟化之---virtio通信

一、理解virtio的背景 我们知道虚拟化hypervisor大的类型分为两种&#xff0c;全虚拟化和半虚拟化。 在全虚拟化的解决方案中&#xff0c;guest VM 要使用底层 host 资源&#xff0c;需要 Hypervisor 来截获所有的请求指令&#xff0c;然后模拟出这些指令的行为&#xff0c;这样…

深度神经网络中的不确定性研究综述

A.单一确定性方法 对于确定性神经网络&#xff0c;参数是确定的&#xff0c;每次向前传递的重复都会产生相同的结果。对于不确定性量化的单一确定性网络方法&#xff0c;我们总结了在确定性网络中基于单一正向传递计算预测y *的不确定性的所有方法。在文献中&#xff0c;可以找…

5-在Linux上部署各类软件

1. MySQL 数据库安装部署 1.1 MySQL 5.7 版本在 CentOS 系统安装 注意&#xff1a;安装操作需要 root 权限 MySQL 的安装我们可以通过前面学习的 yum 命令进行。 1.1.1 安装 配置 yum 仓库 # 更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022# 安装Mysql…

性能优化 | el-table中内嵌大量el-input控件导致渲染卡顿的问题

场景 项目中有一个应用场景&#xff0c;用户需要在表单中大量使用选择框以及输入框填写数据&#xff08;每一行大概有三十几个输入框&#xff09;&#xff0c;当选择框与输入框达到一定数量的时候&#xff0c;页面会出现输入不连续、卡顿的现象&#xff0c;如下图&#xff1a;…

纯血鸿蒙APP实战开发——自定义视图实现Tab效果

介绍 本示例介绍使用Text、List等组件&#xff0c;添加点击事件onclick,动画&#xff0c;animationTo实现自定义Tab效果。 效果预览图 使用说明 点击页签进行切换&#xff0c;选中态页签字体放大加粗&#xff0c;颜色由灰变黑&#xff0c;起到强调作用&#xff0c;同时&…

FreeRTOS资源管理

1.以前临界资源的保护方式 有使用过静态局部变量来保护临界资源&#xff0c;也有用队列&#xff0c;信号量&#xff0c;互斥量来保护临界资源。这些都是在多个任务会共同使用临界资源的情况下我们的保护方式。 问题提出&#xff1a;如果有个传感器在读取数据时有严格的时序&a…

2路模拟音频光端机 JR-CA02

概述 JR-CA02光端机由发送机JR-CA02 Tansmitter和接收机JR-CA02 Receiver组成&#xff0c;通过一定距离长度的光纤相连接&#xff0c;传输2路Audio模拟音频&#xff08;即1路立体声&#xff09;。且每路音频分配输出。 JR-CA02光端机具有运行主要技术参数的监测功能&#xff…

Java的java.util.concurrent.ExecutorService简介

在Java并发编程的璀璨星空中&#xff0c;ExecutorService无疑是那颗最耀眼的明星。它不仅是Java并发编程的核心组件之一&#xff0c;更是构建高并发、高性能应用的秘密武器。今天&#xff0c;我们就来一场说走就走的探索之旅&#xff0c;揭开它的神秘面纱&#xff01; &#x1…

【高校科研前沿】中国科学院地理资源所钟帅副研究员研究组博士生朱屹东为一作在Top期刊发文:从潜力到利用:探索西藏风能资源开发的技术路径优化布局

01 文章简介 论文名称&#xff1a;From potential to utilization: Exploring the optimal layout with the technical path of wind resource development in Tibet&#xff08;从潜力到利用:探索西藏风能资源开发的技术路径优化布局&#xff09; 文章发表期刊&#xff1a;《…

盘一盘接口测试的那些痛点,你现在会解决了吗

前言 说到接口测试&#xff0c;想必大家一定不会陌生。接口测试就是测试系统组件间&#xff0c;接口对接是否顺畅的一种测试。包括测试数据能否交换、能否传递、能否正常控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系&#xff0c;等等。 由于接口测试主要是检测系统…