llvm中如何利用分支概率和基本块频率估计
1. 背景
llvm自2.9版以后,已经集成了对分支概率和基本块频率的静态分析。
分支概率(branch probability)是指在程序的控制流图中,从控制流从一个基本块A到其任意后继基本块Si的概率。控制流从基本块A到其所有后继基本块的概率之和为1. 基本块频率(block frequency)是指在程序的控制流图中,任意基本块的执行次数。这两种信息都可以通过静态分析得到。其原理如下【1】【2】:
An alternative is static profiling, in which a compiler estimates execution frequencies (not absolute counts) with static program analysis. A static profile eliminates the drawbacks of dynamic profiling— if it accurately captures a program’s dynamic behavior. Recent work suggests that static analysis can predict dynamic program behavior. Fisher and Freudenberger [Fisher-92] observed that many programs’ dynamic branching behavior is independent of their input data. Ball and Larus developed a simple algorithm that statically predicts the outcome of a conditional branch with good accuracy [Ball-93]. Wagner et al. usedl simple estimates of branch probabilities to compute static profiles [Wagner-94]. (见文献【2】)
2. llvm3.3中的相关文件
Support/BranchProbability.cpp(.h): 实现一个用来表示分支概率的数据结构
Analysis/BranchProbabilityInfo.cpp(.h): 实现一个在basic block级别进行分支概率估计的FunctionPass
CodeGen/MachineBranchProbabilityInfo.cpp(.h): 实现一个在machine basic block级别进行分支概率估计的ImmutablePass
Support/BlockFrequency.cpp(.h): 实现一个用来表示基本块频率的数据结构
Analysis/BlockFrequencyInfo.cpp(.h): 实现一个在basic block级别进行基本块频率估计的FunctionPass
CodeGen/MachineBlockFrequency.cpp(.h): 实现一个在machine basic block级别进行基本块频率估计的MachineFunctionPass
Analysis/BlockFrequencyImpl.h: 在basic block级别和machine basic block级别共用的基本块频率估计的实现
3. llvm3.3中的相关实现
3.1 分支概率分析
3.1.1 在basic block级别,分支概率分析的实现主要参考文献【2】的方法,利用几个基本启发式来给分支加权。
for (po_iterator<BasicBlock *> I = po_begin(&F.getEntryBlock()), E = po_end(&F.getEntryBlock()); I != E; ++I) { DEBUG(dbgs() << "Computing probabilities for " << I->getName() << "\n"); if (calcUnreachableHeuristics(*I)) continue; if (calcMetadataWeights(*I)) continue; if (calcColdCallHeuristics(*I)) continue; if (calcLoopBranchHeuristics(*I)) continue; if (calcPointerHeuristics(*I)) continue; if (calcZeroHeuristics(*I)) continue; if (calcFloatingPointHeuristics(*I)) continue; calcInvokeHeuristics(*I); } return false; }
3.1.2 在machine basic block级别,分支概率的实现实际上依赖于basic block级别的分支概率分析结果,所以MachineBranchProbabilityInfo并不是一个独立的MachineFunctionPass.
3.2 基本块频率分析
3.2.1 在basic block级别和machine basic block级别共用基本块频率估计的实现
bool BlockFrequencyInfo::runOnFunction(Function &F) { BranchProbabilityInfo &BPI = getAnalysis<BranchProbabilityInfo>(); BFI->doFunction(&F, &BPI); return false; }
bool MachineBlockFrequencyInfo::runOnMachineFunction(MachineFunction &F) { MachineBranchProbabilityInfo &MBPI = getAnalysis<MachineBranchProbabilityInfo>(); MBFI->doFunction(&F, &MBPI); return false; }
3.2.2 上面的代码还可以看出,基本块频率分析依赖于分支概率分析。因此,如果要利用这两种分析结果,只需要在自己的FunctionPass或者MachineFunctionPass里面进行类似如下的修改(建议参考CodeGen/MachineBlockPlacement.cpp):
1)修改getAnalysisUsage函数如下:
void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<MachineBranchProbabilityInfo>(); AU.addRequired<MachineBlockFrequencyInfo>(); MachineFunctionPass::getAnalysisUsage(AU); }
2)修改runOnMachineFunction函数如下
bool MachineBlockPlacement::runOnMachineFunction(MachineFunction &F) { MBPI = &getAnalysis<MachineBranchProbabilityInfo>(); MBFI = &getAnalysis<MachineBlockFrequencyInfo>(); ... //打印分支概率信息 std::string szInfo; raw_fd_ostream S("machinBranchProbs.txt", szInfo, raw_fd_ostream::F_Append); for (MachineFunction::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) { MachineBasicBlock *MBB = BI; for (MachineBasicBlock::const_succ_iterator SI =MBB->succ_begin(), EI = MBB->succ_end(); SI != EI; ++SI) { MachineBasicBlock *mBlock = *SI; MBPI->printEdgeProbability(S << " ", MBB, mBlock); } } S.close(); //打印基本块频率信息 raw_fd_ostream S1("machinBlockFreq.txt", szInfo, raw_fd_ostream::F_Append); if (MBFI) MBFI->print(S1);; S1.close(); ... return false; }
4. 参考文献: