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

部分内容引用: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 linkerUSAGE: 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 programLTO 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.mzph.cn/news/832477.shtml

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

相关文章

触摸OpenNJet,感悟云原生

小程一言 云原生使得应用充分利用云计算、容器化和微服务架构等现代技术来构建和运行应用程序。 云原生技术的用处在于提高应用程序的可靠性、可伸缩性和灵活性&#xff0c;加快开发和部署速度&#xff0c;降低成本&#xff0c;提升整体的效率和竞争力。通过采用云原生技术&a…

mysql使用索引。并未命中

今天在给项目看板查询语句增加索引的时候&#xff0c;发现了一个很有趣的问题。如下&#xff1a; 我这样创建索引&#xff0c;就可以使用&#xff0c;但是我另外一个查询语句&#xff0c;需要使用到factory_id和plan_start_date。于是我就移动了索引顺序&#xff0c;这样遵守左…

若依前后端分离部署nginx

1、v.sj 2、生产环境修改 3、退出登录修改 4、路由改为hash模式 5、nginx配置 location /gldhtml/ {alias D:/java/tool/nginx-1.19.6/project/jxal/html/; } location /jxal/ {proxy_pass http://localhost:8081/; }

蓝牙连接手机播放音乐的同时传输少量数据,那些蓝牙芯片可以实现呢

简介 蓝牙连接手机播放音乐的同时连接另一蓝牙芯片传输少量数据&#xff0c;那些蓝牙芯片可以实现呢&#xff1f; 这个需求&#xff0c;其实就是双模的需求 简单描述就是:播放音乐的同时&#xff0c;还可以连接ble&#xff0c;进行数据的传输。二者同时进行&#xff0c;互不…

标准IO学习

思维导图&#xff1a; 有如下结构体 struct Student{ char name[16]; int age; double math_score; double chinese_score; double english_score; double physics_score; double chemistry_score; double bio_score; }; 申请该结构体数组&#xff0c;容量为5&#xff0c;初始…

uniapp 应用闪退、崩溃异常日志捕获插件(可对接网络上报)插件 Ba-Crash

应用闪退、崩溃异常日志捕获插件&#xff08;可对接网络上报&#xff09; Ba-Crash 简介&#xff08;下载地址&#xff09; Ba-Crash 是一款uniapp应用闪退、崩溃异常日志捕获插件&#xff0c;支持对接网络上报、设置提示等等&#xff0c;方便对一些远程问题、原生问题进行分…

Linux-信号概念

1. 什么是信号 信号本质是一种通知机制&#xff0c;用户or操作系统通过发送信号通知进程&#xff0c;进程进行后续处理 在日常生活中就有很多例子&#xff0c;比如打游戏方面王者荣耀的“进攻”&#xff0c;“撤退”&#xff0c;“请求集合”&#xff0c;“干得漂亮&#xff01…

【数据结构】有关环形链表题目的总结

文章目录 引入 - 快慢指针思考 - 快慢指针行走步数进阶 - 寻找环形链表的头 引入 - 快慢指针 141-环形链表 - Leetcode 关于这道题&#xff0c;大家可以利用快慢指针&#xff0c;一个每次走两步&#xff0c;一个每次走一步&#xff0c;只要他们有一次相撞了就代表说这是一个链…

ue引擎游戏开发笔记(33)——武器与角色的匹配,将新武器装备到角色身上

1.需求分析&#xff1a; 武器能出现在世界中&#xff0c;完成了第一步&#xff0c;下一步需要角色和武器适配&#xff0c;即不论角色跑动&#xff0c;射击等&#xff0c;武器和角色都相匹配&#xff0c;将武器装备到角色身上。 2.操作实现&#xff1a; 1.首先先把角色原有的武…

如何保证Redis双写一致性?

目录 数据不一致问题 数据库和缓存不一致解决方案 1. 先更新缓存&#xff0c;再更新数据 该方案数据不一致的原因 2. 先更新数据库&#xff0c;再更新缓存 3. 先删除缓存&#xff0c;再更新数据库 延时双删 4. 先更新数据库&#xff0c;再删除缓存 该方案数据不一致的…

LeetCode 226.翻转二叉树(全网最多的解法)

LeetCode 226.翻转二叉树 1、题目 题目链接&#xff1a;226. 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#…

Sentinel流量防卫兵

1、分布式服务遇到的问题 服务可用性问题 服务可用性场景 服务雪崩效应 因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程&#xff0c;就叫服务雪崩效应导致服务不可用的原因&#xff1a; 在服务提供者不可用的时候&#xff0c;会出现大量重试的情况&…

Flink时间语义 | 大数据技术

⭐简单说两句⭐ ✨ 正在努力的小叮当~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &a…

爬虫学习(2)破解百度翻译

代码 import requests import jsonif __name__ "__main__":url https://fanyi.baidu.com/sug#post请求参数处理&#xff08;同get请求一致&#xff09;headers {"User-Agent": Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, …

基于Springboot的果蔬作物疾病防治系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的果蔬作物疾病防治系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

ICode国际青少年编程竞赛- Python-1级训练场-识别循环规律1

ICode国际青少年编程竞赛- Python-1级训练场-识别循环规律1 1、 for i in range(4):Dev.step(6)Dev.turnLeft()2、 for i in range(3):Dev.turnLeft()Dev.step(2)Dev.turnRight()Dev.step(2)3、 for i in range(3):Spaceship.step(5)Spaceship.turnLeft()Spaceship.step(…

Linux字符设备驱动(一) - 框架

字符设备是Linux三大设备之一(另外两种是块设备&#xff0c;网络设备)&#xff0c;字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备&#xff0c;常见的字符设备包括鼠标、键盘、显示器、串口等等&#xff0c;当我们执行ls -l /dev的时候&#xff0c;就能看到大量…

2024年5月6日优雅草蜻蜓API大数据服务中心v2.0.3更新

v2.0.3更新 2024年5月6日优雅草蜻蜓API大数据服务中心v2.0.3更新-修复改版后搜索框漏掉的bug-增加搜索框 提示&#xff1a;优雅草大数据中心已经 上线137天 稳定运行 1181555 次 累积调用 目前大数据中心用户呈现增长趋势&#xff0c;目标2024年11月底突破1亿次调用&#xf…

021、Python+fastapi,第一个Python项目走向第21步:ubuntu 24.04 docker 安装mysql8集群、redis集群(二)

系列文章目录 pythonvue3fastapiai 学习_浪淘沙jkp的博客-CSDN博客https://blog.csdn.net/jiangkp/category_12623996.html 前言 安装redis 我会以三种方式安装&#xff0c;在5月4号修改完成 第一、直接最简单安装&#xff0c;适用于测试环境玩玩 第二、conf配置安装 第三…

Redis的数据类型及使用场景

redis命令大全官网: Commands | Docs (redis.io) 基本介绍 redis起初主要就是为了解决性能问题的&#xff0c;那么redis为什么快? 基于内存操作的&#xff0c;所以操作不需要跟磁盘进行交互&#xff0c;单次的执行会很快 命令执行是单线程 因为基于内存操作 单次执行时间反…