SplitFunctions (BOLT) - 优化阅读笔记

2024-03-12 11:12

本文主要是介绍SplitFunctions (BOLT) - 优化阅读笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

将函数拆分成更小的代码片段,从而执行更激进的代码段重排的优化

在文件 bolt/lib/Passes/SplitFunctions.cpp

相关选项释义默认
-split-all-cold尽可能多的分离冷的基本块false
-split-align-threshold对齐参数2
-split-functions主要功能选项, 分离函数到代码片段false
-split-threshold控制分离的片段的大小0
-split-strategy分离策略:
profile2: 依据采样文件
random2:随机?
randomN:随机分离成N个片段
all: 将函数分离成单独的BB块
profile2

–split-functions --split-strategy=all

1. 分割的逻辑

下面是一个并行执行的一个函数

void SplitFunctions::splitFunction(BinaryFunction &BF, SplitStrategy &S) {if (BF.empty())return;// 在 RunOnFunctios, 已根据 opts::SplitStrategy 对 Strategy 初始化了// 主要判断是否有采样文件等if (!S.canSplit(BF))return;// 先拷贝一份 BB 块FunctionLayout &Layout = BF.getLayout();BinaryFunction::BasicBlockOrderType PreSplitLayout(Layout.block_begin(),Layout.block_end());// ...BinaryFunction::BasicBlockOrderType NewLayout(Layout.block_begin(),Layout.block_end());// 接下来,遍历以检查哪些BB块不能被移动// Never outline the first basic block.NewLayout.front()->setCanOutline(false);for (BinaryBasicBlock *const BB : NewLayout) {if (!BB->canOutline())continue;// 在 aarch64 中不要拆分额外的入口点。它们可以通过使用 ADRs 进行引用,当发生这种情况时,由于 ADR 指令的有限范围,这些块不能被放置得太远if (BC.isAArch64() && BB->isEntryPoint()) {BB->setCanOutline(false);continue;}if (BF.hasEHRanges() && !opts::SplitEH) {// 我们不能移动异常处理块(或者说异常处理块的入口点)if (BB->isLandingPad()) {BB->setCanOutline(false);continue;}// 由于异常处理运行时无法处理拆分的函数,我们不能移动可能引发异常的块。// 但是,如果我们可以保证该块永远不会引发异常,那么将该块移动以减小函数大小是安全的for (MCInst &Instr : *BB) {if (BC.MIB->isInvoke(Instr)) {BB->setCanOutline(false);break;}}}}// 参考 1.1 更新 Layout 的索引BF.getLayout().updateLayoutIndices();// 根据不同的 split 算法设置BB所属的代码片段// profile2: FragmentNum::cold() --> 1// random2: 随机设置某个范围的 BB 为 cold// randomN: 随机分配BB到某个片段// all: 所有BB属于单独的片段S.fragment(NewLayout.begin(), NewLayout.end());// Make sure all non-outlineable blocks are in the main-fragment.for (BinaryBasicBlock *const BB : NewLayout) {if (!BB->canOutline())BB->setFragmentNum(FragmentNum::main());}// 按顺序排一下基本块if (opts::AggressiveSplitting) {// 我们可以移动的所有计数为 0 的区块都将进入函数的末尾。// 即使它们是自然形成的集群,并且出现在热门基本区块之间llvm::stable_sort(NewLayout, [&](const BinaryBasicBlock *const A,const BinaryBasicBlock *const B) {return A->getFragmentNum() < B->getFragmentNum();});} else if (BF.hasEHRanges() && !opts::SplitEH) {// 通常情况下,带有异常处理功能的函数在末尾都有异常处理块。// 我们无法移动起始位置,但可以将包含起始位置的 0 计数值块移动到末尾,从而方便拆分auto FirstLP = NewLayout.begin();while ((*FirstLP)->isLandingPad())++FirstLP;std::stable_sort(FirstLP, NewLayout.end(),[&](BinaryBasicBlock *A, BinaryBasicBlock *B) {return A->getFragmentNum() < B->getFragmentNum();});}// 让 BB 所属的代码片段编号递增FragmentNum CurrentFragment = NewLayout.back()->getFragmentNum();for (BinaryBasicBlock *const BB : reverse(NewLayout)) {if (BB->getFragmentNum() > CurrentFragment)BB->setFragmentNum(CurrentFragment);CurrentFragment = BB->getFragmentNum();}// 让代码片段编号保持连续if (!S.keepEmpty()) {FragmentNum CurrentFragment = FragmentNum::main();FragmentNum NewFragment = FragmentNum::main();for (BinaryBasicBlock *const BB : NewLayout) {if (BB->getFragmentNum() > CurrentFragment) {CurrentFragment = BB->getFragmentNum();NewFragment = FragmentNum(NewFragment.get() + 1);}BB->setFragmentNum(NewFragment);}}// 参考 1.2 BF.getLayout().update(NewLayout);// 对于共享对象,调用指令和相应的异常处理块必须放置在同一片段中。// 当我们拆分它们时,创建跳板异常处理块,它将重定向执行到真正的异常处理块......SplitBytesHot += HotSize;SplitBytesCold += ColdSize;

1.1 更新 Layout 的索引

通常用法,如在 bolt/lib/Passes/SplitFunctions.cpp 中:

BF.getLayout().updateLayoutIndices();
S.fragment(NewLayout.begin(), NewLayout.end());
// 这看起来是按顺序给BB的 LayoutIndex 按顺序赋值一个 index
// 并且初始化所有的BB所属的代码片段为0
void FunctionLayout::updateLayoutIndices() {unsigned BlockIndex = 0;for (FunctionFragment &FF : fragments()) {for (BinaryBasicBlock *const BB : FF) {BB->setLayoutIndex(BlockIndex++);BB->setFragmentNum(FF.getFragmentNum());}}
}

1.2 更新内存布局

通常用法,如在 bolt/lib/Passes/SplitFunctions.cpp 中:

BF.getLayout().update(NewLayout);
bool FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {// 检查要更新的 Layout 的 BB 块是否一样 以及 他们所属的代码片段是否一样const bool EqualBlockOrder = llvm::equal(Blocks, NewLayout);if (EqualBlockOrder) {const bool EqualPartitioning =llvm::all_of(fragments(), [](const FunctionFragment &FF) {return llvm::all_of(FF, [&](const BinaryBasicBlock *const BB) {return FF.Num == BB->getFragmentNum();});});if (EqualPartitioning)return false;}// 删除除main()代码片段外的其他片段clear();// 根据 NewLayout 里 BB 设置的代码片段编号新增对应的代码片段for (BinaryBasicBlock *const BB : NewLayout) {FragmentNum Num = BB->getFragmentNum();assert(Num >= Fragments.back()->getFragmentNum() &&"Blocks must be arranged such that fragments are monotonically ""increasing.");// Add empty fragments if necessarywhile (Fragments.back()->getFragmentNum() < Num)addFragment();// Set the next fragment to point one past the current BBaddBasicBlock(BB);}return true;
}

这篇关于SplitFunctions (BOLT) - 优化阅读笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/801074

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear