CPU性能优化--函数分组

发布于:2024-12-22 ⋅ 阅读:(12) ⋅ 点赞:(0)

热点函数可以被分组一起进一步提升CPU前端缓存利用率当热点函数分组在一起时候他们可能共用相同缓存行这会减少CPU需要读取缓存行数量

44给出了被分组函数foo,barzoo图形化展示默认布局需要读取四个缓存行优化布局函数foobarzoo代码只需要三个缓存行此外当我们foo调用zoozoo开始部分已经指令缓存中因为我们读取过缓存行

前面优化类似函数分组提升了指令缓存DSB缓存利用率当有很多小热点函数优化表现最好

连接器负责程序最终二进制输出所有函数排列布局虽然开发者可以尝试自己重排程序函数但是不能保证产生期望物理布局几十年人们一直使用连接器脚本完成这项工作如果使用GNU连接器那么你还需要使用这种方法Gold连接器 更简单方法可以做这件事要使用Gold连接器生成期望函数顺序可以先用-ffunction-sections 选项编译代码从而每个函数放到单独分区然后使用--section-ordering-file=order.txt 选项编译选项可以输入一个包含反应最终期望布局函数排序列表文件LLD连接器LLVM编译器基础设施一部分也有相同功能可以通过--symbol-ordering-file选项使用

调用函数一起函数放一起

另一种解决热点函数分组问题方法HFSort工具实现工具可以基于剖析数据自动生成分区排序文件通过工具工程师类似Facebook百度维基百科这样分布式应用实现2% 性能提升最近HFSort集成到了FaceBook HHVM不再作为单独工具LLD连接器采用HFSort算法实现根据剖析数据分区进行排序

7.7 基于剖析文件编译优化

编译程序乘胜最优汇编代码都是启发式行为在特定场景为了达到最优性能代码转码算法很多多边场景因为编译器需要做很多决策所以需要基于某些典型场景猜测最好选择例如决定某个函数是否需要內联编译器需要考虑函数调用次数但是问题编译器并不能提前知道这些信息

如果剖析信息方便获得的话基于指定剖析信息编译器可以做出更好优化决策大多数编译器中都有一组转换功能可以根据反馈给他们剖析数据调整算法这组转换功能被称为基于剖析文件编译优化Profile Guided Optimization, PGO 在文献中有时可以发现反馈定向优化FDO这个术语本质PGO同一个概念通常有剖析数据时编译器依赖剖析数据没有剖析数据时编译器会依赖剖析数据没有剖析数据使用启发标准算法

使用PGO真实负载性能优化15%很常见PGO不仅可以提升內联功能代码布局还会优化寄存器分配

剖析数据可以通过两种方法生成代码插桩和基于采样剖析两者用法都相对简单并且5.8我们也讨论它们相应优缺点

第一种方法需要先利用LLVM编译器使用-fprofile-instr-generate 选项编译器程序这样告诉编译器生成插桩代码这些插桩会在运行采集剖析信息然后LLVM编译器使用-fprofile-instr-use选项利用剖析数据重新编译器程序生成PGO调优二进制文件使用Clang PGO指导参考LLVM文档GCC编译器使用了不同编译器选项-fprofile-generate -fprofile-use具体请参考GCC文档

第二种方法基于此阿阳生成编译器所需要的剖析数据然后利用AutoFDO工具Linux perf生成采样数据转为类似GCCLLVM编译器可以理解的格式

编译器盲目使用你提供剖析数据编译器会假设所有负载表现都一样只会针对单一负载优化应用程序PGO用户需要非常小心选取需要剖析负载因为优化应场景另一个场景可能会劣化幸运的事由于不同负载剖析数据可以合并在一起代表应用程序一组使用场景所以不一定只是一个负载场景

7.8 ITLB优化

内存地址中虚拟地址无力地址翻译调优前端性能另一个重要领域这些翻译主要TLB完成TLB在某些条目缓存最近使用过内存页面翻译地址TLB不能完成翻译请求时需要进行耗时内核页表遍历一计算每个引用虚拟地址正确物理地址TMA显示ITLB开销,下面提供建议可能有所帮助

通过吧应用程序性能关键代码部分映射到大页可以减少ITLB压力需要这需要重新链接二进制文件子啊合适边界对齐代码准备大页映射除了使用大页用于优化指令缓存性能标准技术也可以用于提升ITLB性能重拍函数让热点函数更集中通过LTO/IPO减小热点区域大小使用PGO避免过度內联

转换

如何转换

为何有益

什么场景

执行者

基本块布局

维护热点代码直

避免分支耗时缓存利用率高

分之多代码

编译器

基本块对齐

使用NOP指令对热点代码进行移位

缓存利用率高

热点循环

编译器

函数拆分

冷代码放到独立函数中

缓存利用率更高

编译器

函数分组

热点函数分组到一起

缓存利用率更高

有很多热点函数

链接器