[DRAFT] LLVM ThinLTO原理分析

news2024/11/16 11:34:40

我们在《论文阅读:ThinLTO: Scalable and Incremental LTO》中介绍了ThinLTO论文的主要思想,这里我们介绍下LLVM ThinLTO是如何实现的。本文主要分为如下几个部分:

  • LLVM ThinLTO Object 含有哪些内容?
  • LLVM ThinLTO 是如何做优化的?
  • LLVM ThinLTO 能够enable哪些优化?

LLVM ThinLTO Objects都包含了哪些?

继续使用 Example of link time optimization 中的例子进行分析,在《LLVM full LTO 学习笔记》中我们通过 magic number 作为切入点,简单分析了 full lto 的过程。下面按照这个路子继续该分析

$ clang -flto=thin -c a.c -o a_lto.o
$ clang -flto=thin -c main.c -o main_lto.o
$ hexdump a_lto.o | head
0000000 4342 dec0 1435 0000 0005 0000 0c62 2430
0000010 594d 66be fb8d 4fb4 c81b 4424 3201 0005
0000020 0c21 0000 0266 0000 020b 0021 0002 0000
0000030 0016 0000 8107 9123 c841 4904 1006 3932
0000040 0192 0c84 0525 1908 041e 628b 1080 0245
0000050 9242 420b 1084 1432 0838 4b18 320a 8842
0000060 7048 21c4 4423 8712 108c 9241 6402 08c8
0000070 14b1 4320 8846 c920 3201 8442 2a18 2a28
0000080 3190 b07c 915c c420 00c8 0000 2089 0000
0000090 000e 0000 2232 0908 6220 0046 2b21 9824

我们可以看到 magic number 为 4342 dec0,说明对于 thin LTO 的 objects,其文件格式还是 bitcode file 。通过阅读 ThinLTO 的文档,发现其实文档中早已经说的很详细了。

In ThinLTO mode, as with regular LTO, clang emits LLVM bitcode after the compile phase. The ThinLTO bitcode is augmented with a compact summary of the module. During the link step, only the summaries are read and merged into a combined summary index, which includes an index of function locations for later cross-module function importing. Fast and efficient whole-program analysis is then performed on the combined summary index.

使用 llvm-dis a_lto.o 得到其可读的 IR。我们将其与 full lto 得到的 IR 进行对比后发现,两者差异极小,主要在于最后面的 summary 部分。以 a_lto.o 进行 thinLTO 和 full LTO 的对比如下。

// ---------------- Thin LTO ----------------//
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{i32 1, !"EnableSplitLTOUnit", i32 0}
!4 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 58e7bf78a3ef724b70304912fb3bb66af8c4a10c)"}

^0 = module: (path: "a_lto.o", hash: (3489747275, 1762444854, 1461358598, 2667786215, 1835806708))
^1 = gv: (name: "foo2", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 2, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), refs: (writeonly ^2)))) ; guid = 2494702099028631698
^2 = gv: (name: "i", summaries: (variable: (module: ^0, flags: (linkage: internal, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1, constant: 0)))) ; guid = 2708120569957007488
^3 = gv: (name: "foo1", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 13, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), calls: ((callee: ^5)), refs: (readonly ^2)))) ; guid = 7682762345278052905
^4 = gv: (name: "foo4") ; guid = 11564431941544006930
^5 = gv: (name: "foo3", summaries: (function: (module: ^0, flags: (linkage: internal, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 2, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), calls: ((callee: ^4))))) ; guid = 17367728344439303071
^6 = blockcount: 5

// ---------------- Full LTO ----------------//
!llvm.module.flags = !{!0, !1, !2, !3, !4}
!llvm.ident = !{!5}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{i32 1, !"ThinLTO", i32 0}
!4 = !{i32 1, !"EnableSplitLTOUnit", i32 1}
!5 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 58e7bf78a3ef724b70304912fb3bb66af8c4a10c)"}

^0 = module: (path: "a_lto.o", hash: (0, 0, 0, 0, 0))
^1 = gv: (name: "foo2", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 2, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), refs: (^2)))) ; guid = 2494702099028631698
^2 = gv: (name: "i", summaries: (variable: (module: ^0, flags: (linkage: internal, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1, constant: 0)))) ; guid = 2708120569957007488
^3 = gv: (name: "foo1", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 13, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), calls: ((callee: ^5)), refs: (^2)))) ; guid = 7682762345278052905
^4 = gv: (name: "foo4") ; guid = 11564431941544006930
^5 = gv: (name: "foo3", summaries: (function: (module: ^0, flags: (linkage: internal, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 2, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), calls: ((callee: ^4))))) ; guid = 17367728344439303071
^6 = flags: 8
^7 = blockcount: 5

我们将重点的差别进行 highlight,

DifferenceThin LTOFull LTO
Module Flags!3 = !{i32 1, !"ThinLTO", i32 0}
Global Value Summary module ^0^0 = module: (path: "a_lto.o", hash: (3489747275, 1762444854, 1461358598, 2667786215, 1835806708))^0 = module: (path: "a_lto.o", hash: (0, 0, 0, 0, 0))
Global Value Summary foo2 ^1- notEligibleToImport: 0
- refs: (writeonly ^2)
- notEligibleToImport: 1
- refs: (^2)
Global Value Summary i ^2- notEligibleToImport: 0notEligibleToImport: 1
Global Value Summary foo1 ^3- notEligibleToImport: 0
- refs: (readonly ^2)
- notEligibleToImport: 1
- refs: (^2)
Global Value Summary foo3 ^5notEligibleToImport: 0notEligibleToImport: 1

通过 Metadata 知道,! 后面表示的是 metadata,^表示的是 global value summary。

All metadata are identified in syntax by an exclamation point (‘!’).
Compiling with ThinLTO causes the building of a compact summary of the module that is emitted into the bitcode. The summary is emitted into the LLVM assembly and identified in syntax by a caret (‘^’).

通过 Module Flags Metadata 来对 !3 = !{i32 1, !"ThinLTO", i32 0} 进行解释。module flags metadata 是一组三元组 triplets

  • The first element is a behavior flag, which specifies the behavior when two (or more) modules are merged together.
  • The second element is a metadata string that is a unique ID for the metadata.
  • The third element is the value of the flag.
!3 = !{i32 1, !"ThinLTO", i32 0}

thin lto
ThinLTO 的值为 0, 表示非 ThinLTO,另外一个表明是否为 ThinLTO 或者 FullLTO,GLOBALVAL_SUMMARY_BLOCK 默认是 thin lto。

$ llvm-bcanalyzer -dump a_full_lto.o
  Block ID #24 (FULL_LTO_GLOBALVAL_SUMMARY_BLOCK):
      Num Instances: 1
         Total Size: 789b/98.62B/24W
    Percent of file: 3.4924%
      Num SubBlocks: 0
        Num Abbrevs: 6
        Num Records: 7
    Percent Abbrevs: 57.1429%

	Record Histogram:
		  Count    # Bits     b/Rec   % Abv  Record Kind
		      3       218      72.7  100.00  PERMODULE
		      1        22                    BLOCK_COUNT
		      1        22                    FLAGS
		      1        22                    VERSION
		      1        38            100.00  PERMODULE_GLOBALVAR_INIT_REFS
$ llvm-bcanalyzer -dump a_thin_lto.o
  Block ID #20 (GLOBALVAL_SUMMARY_BLOCK):
      Num Instances: 1
         Total Size: 789b/98.62B/24W
    Percent of file: 3.4727%
      Num SubBlocks: 0
        Num Abbrevs: 6
        Num Records: 7
    Percent Abbrevs: 57.1429%

	Record Histogram:
		  Count    # Bits     b/Rec   % Abv  Record Kind
		      3       218      72.7  100.00  PERMODULE
		      1        22                    BLOCK_COUNT
		      1        22                    FLAGS
		      1        22                    VERSION
		      1        38            100.00  PERMODULE_GLOBALVAR_INIT_REFS

在有 global value summary 的情况下,默认是 thin lto,除非 ThinLTO module metadata flag 为 0 。

/// Emit the per-module summary section alongside the rest of
/// the module's bitcode.
void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() {
  // By default we compile with ThinLTO if the module has a summary, but the
  // client can request full LTO with a module flag.
  bool IsThinLTO = true;
  if (auto *MD =
          mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("ThinLTO")))
    IsThinLTO = MD->getZExtValue();
  Stream.EnterSubblock(IsThinLTO ? bitc::GLOBALVAL_SUMMARY_BLOCK_ID
                                 : bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID,
                       4);
  // ...
}

RFC

https://lists.llvm.org/pipermail/llvm-dev/2015-May/085526.html
https://sites.google.com/site/llvmthinlto/

Patches

https://reviews.llvm.org/D13107?id=35761

Function Importer

https://reviews.llvm.org/D14914
https://reviews.llvm.org/D18343

llvm-opt2/llvm-opt相关

关于 SyntheticCount的讨论

  • https://lists.llvm.org/pipermail/llvm-dev/2017-December/119701.html
  • https://reviews.llvm.org/D43521?id=135117#inline-388028
/// Compute synthetic function entry counts.
void computeSyntheticCounts(ModuleSummaryIndex &Index);

相关术语

  • BFI, block frequency inforamtion
  • BPI,probability information
  • CGSCC,call graph scc analysis,https://lists.llvm.org/pipermail/llvm-dev/2016-June/100792.html

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

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

相关文章

Splashtop 与 Canopy 携手共同增强对物联网设备的远程管理

2023年10月17日 加利福尼亚州库比蒂诺 Splashtop 在安全远程访问解决方案领域处于领先地位&#xff0c;Canopy 则是用于复杂硬件部署的领先 RMM 平台&#xff0c;双方今天宣布达成战略合作伙伴关系&#xff0c;以进一步增强和简化对物联网设备的远程管理。通过此次合作&#x…

react实现一维表格、键值对数据表格key value表格

UI画的需求很抽象&#xff0c;直接把数据铺开&#xff0c;不能直接用antd组件了 上一行是name&#xff0c;下一行是value&#xff0c;总数不定&#xff0c;最后前端还要显示求和 class OneDimensionTable extends React.Component { render() {const { data } this.props;le…

C++基础系列(一) 对象指针

一. 函数指针和指针函数 1.1 函数指针 这两个是C语言里两个比较绕的概念&#xff0c;我们先说一下函数指针 函数指针本质是一个指针&#xff0c;该指针的地址指向了一个函数。 在程序中定义了一个函数&#xff0c;那么在编译时系统就会为这个函数代码分配一段存储空间&#xf…

金融机器学习方法:K-均值算法

目录 1.算法介绍 2.算法原理 3.python实现示例 1.算法介绍 K均值聚类算法是机器学习和数据分析中常用的无监督学习方法之一&#xff0c;主要用于数据的分类。它的目标是将数据划分为几个独特的、互不重叠的子集或“集群”&#xff0c;以使得同一集群内的数据点彼此相似&…

window.location对象实例详解

一、前言 Window.location 只读属性返回一个 Location 对象&#xff0c;其中包含当前标签页文档的网页地址信息。 Window.location 是一个只读 Location 对象&#xff0c;但是我们仍然可以去重新赋值更改对象值。 下面就让我们详细介绍一下location的常用属性和方法&#xf…

基于springboot实现滴答拍摄影项目【项目源码+论文说明】

摘要 拍摄能让人放开自我、因看到不同的美景都想留下美好的记忆&#xff0c;有些人喜欢拍摄静物来表现宁静的氛围&#xff0c;通过小品类的照片&#xff0c;传达内心的情绪。而我更喜欢另一种方式&#xff0c;就是用长时间曝光把波动的海水或湖水雾化&#xff0c;拍摄出来的作…

为什么产品经理都要考NPDP?

最近很多宝子问我&#xff0c;产品经理适合考什么证书&#xff1f;那必然是NPDP啊&#xff01;作为国际产品专业认证&#xff0c;NPDP证书是现如今最炙手可热且含金量相对较高的证书了&#xff0c;下面胖圆讲给大家详细介绍一下NPDP证书的具体信息。 1&#xff09;NPDP是什么&…

Win10下基于VS2015编译SQLite3源码

一、下载SQLite SQLite SQLite Download Page 下载红框部分的3个文件 提示&#xff1a;这里有个 sglite-autoconf-3420000.tar.gz 是免编译版&#xff0c;想省事就下载这个&#xff0c;但我自己用这个老是编译不过 所以我这里不推荐这个了 二、配置SQLite 打开vs 2015或者其他…

vscode中快速生成vue3模板

步骤&#xff1a;设置 -> 用户代码片段 -> vue.json&#xff08;没有vue.json,选vue也可&#xff09;-> 定义自己所需的代码段 代码段 如下&#xff0c; {"Print to console": {"prefix": "vue3", //键入该值&#xff0c;按tab…

自定义类型(结构体 , 枚举 , 联合)详解

文章目录 结构体结构体变量初始化结构体内存对齐结构体的对齐规则:为什么存在内存对齐 修改默认对齐数结构体实现位段(位段的填充&可移植性)什么是位段(位是二进制位)位段的内存分配位段的跨平台问题 实现offsetof&#xff08;计算结构体成员相较于起始位置的偏移量&#x…

Netty入门指南之基础介绍

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Netty应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献介绍为什么…

报错:AttributeError: module ‘tensorflow‘ has no attribute ‘flags‘

改成如下&#xff1a; 报错原因&#xff1a;tensorflow1.x与2.x版本问题不兼容

重装操作系统后 gitee:Failed to create Gitee Repository

错误描述 重装系统后&#xff0c;提交项目代码到gitee程序报错&#xff1a; 11:21 Failed to create Gitee Repositorydetected dubious ownership in repository at E:/Workspaces/SpringBoot/saTokenE:/Workspaces/SpringBoot/saToken is owned by:S-1-5-21-1301660696-421…

【已解决】ubuntu耳机单侧有声音

背景 台式机&#xff0c;双系统&#xff1a;win10 ubuntu 20.04&#xff1b;ubuntu 系统当中&#xff0c;左侧耳机有声音&#xff0c;右侧没有&#xff1b; 解决方法 终端输入&#xff1a;alsamixer&#xff0c;显示下面的图片&#xff1a; 调整方法&#xff1a;键盘上下左…

微信native-v3版支付对接流程及demo

1.将p12证书转为pem证书&#xff0c;得到商户私钥 openssl pkcs12 -in apiclient_cert.p12 -out apiclient_cert.pem -nodes 密码是&#xff1a;商户id 2.将获取到的apiclient_cert.pem证书&#xff0c;复制出这一块内容&#xff0c;其他的不要 3.下载这个工具包 https://gi…

Sqoop技术文档笔记

Sqoop是一个用于在Hadoop和关系型数据库之间传输数据的开源工具。它可以将结构化数据从关系型数据库&#xff08;如MySQL、Oracle、SQL Server等&#xff09;导入到Hadoop的分布式文件系统&#xff08;HDFS&#xff09;或hive中&#xff0c;并且可以将数据从HDFS、hive导出到关…

数据分析在游戏行业的应用

数据分析在游戏行业中扮演着至关重要的角色&#xff0c;它可以用于以下方面&#xff1a; 1、玩家行为分析 了解玩家在游戏中的行为&#xff0c;包括游戏时长、最喜欢的游戏模式、关卡通过率等&#xff0c;从而为游戏设计和运营提供参考。 2、留存率 监控玩家在游戏中的持续参…

ChatGPT/GPT4科研技术应用与AI绘图及论文高效写作

2023年我们进入了AI2.0时代。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车&#xff0c;就有可能被淘汰在这个数字化时代&#xff0c;如何能高效地处理文本、文献查阅、PPT…

交换奇偶位

写一个宏&#xff0c;可以将一个整数的二进制位的奇数位和偶数位交换。 要交换二进制位的奇数位和偶数位&#xff0c;那么肯定要先拿到奇数位和偶数位&#xff0c;然后让奇数位左移一位&#xff0c;偶数位右移一位&#xff0c;再将移动后的这两组数相加就可以了&#xff08;一个…

【网络安全】被恶意攻击的IP地址有多可怕?

被恶意攻击的IP地址可以导致一系列问题&#xff0c;其严重性和可怕程度取决于攻击的性质、目标、攻击者的动机以及受影响的系统或组织。以下是一些可能出现的问题和可怕性的因素&#xff1a; 数据泄露和盗窃&#xff1a;攻击者可能试图入侵系统&#xff0c;窃取敏感数据&#x…