zoukankan      html  css  js  c++  java
  • 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() << "
    ");
      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. 参考文献:

    【1】. Hashemi, A., Kaeli, D., Calder, B.: Procedure mapping using static call graph estimation. In: Workshop on Interaction between Compiler and Computer Architecture, San Antonio, TX (1997) 
    【2】. Youfeng Wu, James R. Larus: Static branch frequency and program profile analysis. MICRO 1994: 1-11


  • 相关阅读:
    Nginx配置中运行与启动的详细介绍
    php实现文件上传进度条
    C# 提取逗号分割的字符串
    【sas proc sql】out join
    【SAS NOTE】substr函数
    【sas proc sql】子查询
    【SAS NOTE】数字字符互换
    【SAS NOTE】数组
    【sas Notel】merge
    【sas sql proc】inner join or outer join
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3249333.html
Copyright © 2011-2022 走看看