LLVM 的DSA与APA优化
LLVM在链接时所做的最激进的优化,莫过于DSA和APA。在DSA分析中,借助于LLVM比较充足的type information,在指针分析的基础上,可以构造出整个内存对象的连接关系图。然后对这个图进行分析,得到内存对象的连接模式,将连接比较紧密的结构对象,例如树、链表等结构体分配在自定义的一格连续分配的内存池中。这样可以少维护很多内存块,并且大大提高空间locality,相应的提高cache命中率。
APA(Automatic Pool Allocation)能够将堆上分配的链接形式的结构体,分配在连续的内存池中,这种做法是通过将内存分配函数替换为自定义池
分配函数实现的,示意图如下所示:
另外一些在链接阶段进行的分析,包括调用图构建,Mod/Ref分析,以及一些过程间的分析,例如函数inline,死全局变量删除(dead global elimination),死实参删除(dead argument),常量传播,列表边界检查消除(array bounds check elimination),简单结构体域重排(structure field reordering),以及Automatic Pool Allocation。
在编译时会汇总每个函数摘要信息(prodedure summary),附在LLVM IR中,在链接时就无需重新从源码中获取信息,直接使用函数摘要进行过程间分析即可。这种技术大大缩短了增量编译的时间。函数摘要一直是过程间分析的重点,因为这种技术在不过分影响精确性的前提下,大大提高了静态分析的效率。
这里简单提示一下,结构体域重排(structure field reordering)会涉及到以下问题:
1)为什么需要结构体域重排。
2)结构体域重排应该怎么做。
3)结构体域重排会不会带来其它影响。
另外结构体域重排,也可以与hot概念相结合,如下代码所示:
// s has hot member and cold member
struct s{
char c;
int i;
double d;
};
// we can split s to two struct
struct hots{
char c;
double d;
};
struct colds{
int i;
};
将结构体根据hot的程度分拆成两个结构体,可以针对两个结构体进行不同的优化,例如,将hot结构体的member提升到register中等。
与结构体域重排优化概念相关的另外概念是padding,alignment,point compression。前两个概念与结构体域重排直接相关,示意代码如下所示:
struct s1 {
char a; // here padding 3 bytes
int b;
char c;
char d;
xhar e; // here padding 1 bytes
}
这个结构体的sizeof是12bytes,但是,如果将这个s1结构体子域重排的话,8bytes就够了,如下图所示:
struct s1 {
char a;
char c;
char d;
char e;
int b;
}
首先就是,要做reordering的前提就是,必须能够确保当前结构体只在当前TU中,如果当前结构体在另外的TU中也存在的话,那么就会存在结构体内存布局不相容的情况。所以这样的优化只能在链接时进行。
另外,就是要相应修改所有对struct进行引用的操作,在C/C++这些类型不安全的语言中,类型转换非常普遍,有可能另外一种类型的使用其实就是在当前类型那个内存上进行的,如下代码所示。如何识别跟踪这些类型转换是一格非常困难的问题,LLVM IR提供了type information来帮助执行这些优化。
struct s {
char a;
int b;
char c;
};
struct s_head {
char a;
};
struct s_ext {
char a;
int b;
char c;
int d;
char e;
};
struct S s;
struct S_head *head = (struct S_head*)&s;
fn1(head);
struct S_ext ext;
struct S *sp = (struct S*)&ext;
fn2(sp);
另一个与reordering the fields相关的概念就是point compression,这两者的目的都是用于提高内存使用率,使内存显得更为紧凑。与reordering hte fields类似的两个优化概念是Structure peeling,structure splitting,这些都属于Data Layout Optimizations。
LLVM代码生成器
在寄存器分配之前,LLVM会一直保存SSA形式。LLVM代码生成结构如下图所示:
图中描述了在代码生成时用到的一些技术。
装载时优化
运行时优化
在大部分人看来,运行时优化仅仅与JIT、虚拟机和CPU乱序发射以及cache相关,因为运行时优化只在运行时执行,JIT可以结合虚拟机在程序解释执行时识别出hot区域,以便能够将这些代码编译成native code,CPU乱序可以依据当前指令的相关性来执行指令重排等操作,而cache也可以将频繁出现的内容缓存到cache中以便加快执行速度。可是,LLVM与这些貌似都无关,确实LLVM运行时优化与他们不相同。LLVM运行时优化与闲时优化相互结合来实现相关优化,LLVM会在代码生成的时候插入一些低代价的指令来收集运行时的信息(profiling information),这些信息用于指导闲时优化重新生成一份更加高效的native code。这个过程也可以重复多次来达到较优的效果。一个重要的用处就是识别hot loop region和hot path,然后再对这些热区域进行特殊处理。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2022-05-26 Mobileye技术与市场走势
2021-05-26 CUDA上深度学习模型量化的自动化优化
2021-05-26 将TVM集成到PyTorch
2021-05-26 使用Apache TVM将机器学习编译为WASM和WebGPU
2020-05-26 SLAM的通用框架:GSLAM
2020-05-26 Docker_Swarm集群系统
2020-05-26 多传感器融合(三)