Home | History | Annotate | Line # | Download | only in IR
      1 //===- PseudoProbe.cpp - Pseudo Probe Helpers -----------------------------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file implements the helpers to manipulate pseudo probe IR intrinsic
     10 // calls.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "llvm/IR/PseudoProbe.h"
     15 #include "llvm/IR/DebugInfoMetadata.h"
     16 #include "llvm/IR/IRBuilder.h"
     17 #include "llvm/IR/Instruction.h"
     18 #include <unordered_set>
     19 
     20 using namespace llvm;
     21 
     22 namespace llvm {
     23 
     24 Optional<PseudoProbe> extractProbeFromDiscriminator(const Instruction &Inst) {
     25   assert(isa<CallBase>(&Inst) && !isa<IntrinsicInst>(&Inst) &&
     26          "Only call instructions should have pseudo probe encodes as their "
     27          "Dwarf discriminators");
     28   if (const DebugLoc &DLoc = Inst.getDebugLoc()) {
     29     const DILocation *DIL = DLoc;
     30     auto Discriminator = DIL->getDiscriminator();
     31     if (DILocation::isPseudoProbeDiscriminator(Discriminator)) {
     32       PseudoProbe Probe;
     33       Probe.Id =
     34           PseudoProbeDwarfDiscriminator::extractProbeIndex(Discriminator);
     35       Probe.Type =
     36           PseudoProbeDwarfDiscriminator::extractProbeType(Discriminator);
     37       Probe.Attr =
     38           PseudoProbeDwarfDiscriminator::extractProbeAttributes(Discriminator);
     39       Probe.Factor =
     40           PseudoProbeDwarfDiscriminator::extractProbeFactor(Discriminator) /
     41           (float)PseudoProbeDwarfDiscriminator::FullDistributionFactor;
     42       return Probe;
     43     }
     44   }
     45   return None;
     46 }
     47 
     48 Optional<PseudoProbe> extractProbe(const Instruction &Inst) {
     49   if (const auto *II = dyn_cast<PseudoProbeInst>(&Inst)) {
     50     PseudoProbe Probe;
     51     Probe.Id = II->getIndex()->getZExtValue();
     52     Probe.Type = (uint32_t)PseudoProbeType::Block;
     53     Probe.Attr = II->getAttributes()->getZExtValue();
     54     Probe.Factor = II->getFactor()->getZExtValue() /
     55                    (float)PseudoProbeFullDistributionFactor;
     56     return Probe;
     57   }
     58 
     59   if (isa<CallBase>(&Inst) && !isa<IntrinsicInst>(&Inst))
     60     return extractProbeFromDiscriminator(Inst);
     61 
     62   return None;
     63 }
     64 
     65 void setProbeDistributionFactor(Instruction &Inst, float Factor) {
     66   assert(Factor >= 0 && Factor <= 1 &&
     67          "Distribution factor must be in [0, 1.0]");
     68   if (auto *II = dyn_cast<PseudoProbeInst>(&Inst)) {
     69     IRBuilder<> Builder(&Inst);
     70     uint64_t IntFactor = PseudoProbeFullDistributionFactor;
     71     if (Factor < 1)
     72       IntFactor *= Factor;
     73     auto OrigFactor = II->getFactor()->getZExtValue();
     74     if (IntFactor != OrigFactor)
     75       II->replaceUsesOfWith(II->getFactor(), Builder.getInt64(IntFactor));
     76   } else if (isa<CallBase>(&Inst) && !isa<IntrinsicInst>(&Inst)) {
     77     if (const DebugLoc &DLoc = Inst.getDebugLoc()) {
     78       const DILocation *DIL = DLoc;
     79       auto Discriminator = DIL->getDiscriminator();
     80       if (DILocation::isPseudoProbeDiscriminator(Discriminator)) {
     81         auto Index =
     82             PseudoProbeDwarfDiscriminator::extractProbeIndex(Discriminator);
     83         auto Type =
     84             PseudoProbeDwarfDiscriminator::extractProbeType(Discriminator);
     85         auto Attr = PseudoProbeDwarfDiscriminator::extractProbeAttributes(
     86             Discriminator);
     87         // Round small factors to 0 to avoid over-counting.
     88         uint32_t IntFactor =
     89             PseudoProbeDwarfDiscriminator::FullDistributionFactor;
     90         if (Factor < 1)
     91           IntFactor *= Factor;
     92         uint32_t V = PseudoProbeDwarfDiscriminator::packProbeData(
     93             Index, Type, Attr, IntFactor);
     94         DIL = DIL->cloneWithDiscriminator(V);
     95         Inst.setDebugLoc(DIL);
     96       }
     97     }
     98   }
     99 }
    100 
    101 void addPseudoProbeAttribute(PseudoProbeInst &Inst,
    102                              PseudoProbeAttributes Attr) {
    103   IRBuilder<> Builder(&Inst);
    104   uint32_t OldAttr = Inst.getAttributes()->getZExtValue();
    105   uint32_t NewAttr = OldAttr | (uint32_t)Attr;
    106   if (OldAttr != NewAttr)
    107     Inst.replaceUsesOfWith(Inst.getAttributes(), Builder.getInt32(NewAttr));
    108 }
    109 
    110 /// A block emptied (i.e., with all instructions moved out of it) won't be
    111 /// sampled at run time. In such cases, AutoFDO will be informed of zero samples
    112 /// collected for the block. This is not accurate and could lead to misleading
    113 /// weights assigned for the block. A way to mitigate that is to treat such
    114 /// block as having unknown counts in the AutoFDO profile loader and allow the
    115 /// counts inference tool a chance to calculate a relatively reasonable weight
    116 /// for it. This can be done by moving all pseudo probes in the emptied block
    117 /// i.e, /c From, to before /c To and tag them dangling. Note that this is
    118 /// not needed for dead blocks which really have a zero weight. It's per
    119 /// transforms to decide whether to call this function or not.
    120 bool moveAndDanglePseudoProbes(BasicBlock *From, Instruction *To) {
    121   SmallVector<PseudoProbeInst *, 4> ToBeMoved;
    122   for (auto &I : *From) {
    123     if (auto *II = dyn_cast<PseudoProbeInst>(&I)) {
    124       addPseudoProbeAttribute(*II, PseudoProbeAttributes::Dangling);
    125       ToBeMoved.push_back(II);
    126     }
    127   }
    128 
    129   for (auto *I : ToBeMoved)
    130     I->moveBefore(To);
    131 
    132   return !ToBeMoved.empty();
    133 }
    134 
    135 /// Same dangling probes in one blocks are redundant since they all have the
    136 /// same semantic that is to rely on the counts inference too to get reasonable
    137 /// count for the same original block. Therefore, there's no need to keep
    138 /// multiple copies of them.
    139 bool removeRedundantPseudoProbes(BasicBlock *Block) {
    140 
    141   auto Hash = [](const PseudoProbeInst *I) {
    142     return std::hash<uint64_t>()(I->getFuncGuid()->getZExtValue()) ^
    143            std::hash<uint64_t>()(I->getIndex()->getZExtValue());
    144   };
    145 
    146   auto IsEqual = [](const PseudoProbeInst *Left, const PseudoProbeInst *Right) {
    147     return Left->getFuncGuid() == Right->getFuncGuid() &&
    148            Left->getIndex() == Right->getIndex() &&
    149            Left->getAttributes() == Right->getAttributes() &&
    150            Left->getDebugLoc() == Right->getDebugLoc();
    151   };
    152 
    153   SmallVector<PseudoProbeInst *, 4> ToBeRemoved;
    154   std::unordered_set<PseudoProbeInst *, decltype(Hash), decltype(IsEqual)>
    155       DanglingProbes(0, Hash, IsEqual);
    156 
    157   for (auto &I : *Block) {
    158     if (auto *II = dyn_cast<PseudoProbeInst>(&I)) {
    159       if (II->getAttributes()->getZExtValue() &
    160           (uint32_t)PseudoProbeAttributes::Dangling)
    161         if (!DanglingProbes.insert(II).second)
    162           ToBeRemoved.push_back(II);
    163     }
    164   }
    165 
    166   for (auto *I : ToBeRemoved)
    167     I->eraseFromParent();
    168   return !ToBeRemoved.empty();
    169 }
    170 } // namespace llvm
    171