12f09f445SMaksim Panchenko //===- bolt/Profile/YAMLProfileWriter.cpp - YAML profile serializer -------===// 2a34c753fSRafael Auler // 3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a34c753fSRafael Auler // 7a34c753fSRafael Auler //===----------------------------------------------------------------------===// 8a34c753fSRafael Auler 9a34c753fSRafael Auler #include "bolt/Profile/YAMLProfileWriter.h" 10a34c753fSRafael Auler #include "bolt/Core/BinaryBasicBlock.h" 11a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h" 122d3c827cSAmir Ayupov #include "bolt/Profile/BoltAddressTranslation.h" 1397025bd9SAmir Ayupov #include "bolt/Profile/DataAggregator.h" 14a34c753fSRafael Auler #include "bolt/Profile/ProfileReaderBase.h" 15a34c753fSRafael Auler #include "bolt/Rewrite/RewriteInstance.h" 16c820bd3eSAmir Ayupov #include "bolt/Utils/CommandLineOpts.h" 17c00c62c1SAmir Ayupov #include "llvm/MC/MCPseudoProbe.h" 1869b7e257SAmir Ayupov #include "llvm/Support/CommandLine.h" 19a34c753fSRafael Auler #include "llvm/Support/FileSystem.h" 20a34c753fSRafael Auler #include "llvm/Support/raw_ostream.h" 21a34c753fSRafael Auler 22a34c753fSRafael Auler #undef DEBUG_TYPE 23a34c753fSRafael Auler #define DEBUG_TYPE "bolt-prof" 24a34c753fSRafael Auler 2569b7e257SAmir Ayupov namespace opts { 26c820bd3eSAmir Ayupov using namespace llvm; 27c820bd3eSAmir Ayupov extern cl::opt<bool> ProfileUseDFS; 28c820bd3eSAmir Ayupov cl::opt<bool> ProfileWritePseudoProbes( 29c820bd3eSAmir Ayupov "profile-write-pseudo-probes", 30c820bd3eSAmir Ayupov cl::desc("Use pseudo probes in profile generation"), cl::Hidden, 31c820bd3eSAmir Ayupov cl::cat(BoltOptCategory)); 3269b7e257SAmir Ayupov } // namespace opts 3369b7e257SAmir Ayupov 34a34c753fSRafael Auler namespace llvm { 35a34c753fSRafael Auler namespace bolt { 36a34c753fSRafael Auler 372d3c827cSAmir Ayupov const BinaryFunction *YAMLProfileWriter::setCSIDestination( 382d3c827cSAmir Ayupov const BinaryContext &BC, yaml::bolt::CallSiteInfo &CSI, 392d3c827cSAmir Ayupov const MCSymbol *Symbol, const BoltAddressTranslation *BAT, 402d3c827cSAmir Ayupov uint32_t Offset) { 41385e3e26SAmir Ayupov CSI.DestId = 0; // designated for unknown functions 42385e3e26SAmir Ayupov CSI.EntryDiscriminator = 0; 432d3c827cSAmir Ayupov 44385e3e26SAmir Ayupov if (Symbol) { 45385e3e26SAmir Ayupov uint64_t EntryID = 0; 462d3c827cSAmir Ayupov if (const BinaryFunction *Callee = 47385e3e26SAmir Ayupov BC.getFunctionForSymbol(Symbol, &EntryID)) { 482d3c827cSAmir Ayupov if (BAT && BAT->isBATFunction(Callee->getAddress())) 492d3c827cSAmir Ayupov std::tie(Callee, EntryID) = BAT->translateSymbol(BC, *Symbol, Offset); 50935b946bSAmir Ayupov else if (const BinaryBasicBlock *BB = 51935b946bSAmir Ayupov Callee->getBasicBlockContainingOffset(Offset)) 52935b946bSAmir Ayupov BC.getFunctionForSymbol(Callee->getSecondaryEntryPointSymbol(*BB), 53935b946bSAmir Ayupov &EntryID); 54385e3e26SAmir Ayupov CSI.DestId = Callee->getFunctionNumber(); 55385e3e26SAmir Ayupov CSI.EntryDiscriminator = EntryID; 56385e3e26SAmir Ayupov return Callee; 57385e3e26SAmir Ayupov } 58385e3e26SAmir Ayupov } 59385e3e26SAmir Ayupov return nullptr; 60385e3e26SAmir Ayupov } 61385e3e26SAmir Ayupov 62c00c62c1SAmir Ayupov std::vector<YAMLProfileWriter::InlineTreeNode> 63c00c62c1SAmir Ayupov YAMLProfileWriter::collectInlineTree( 64c00c62c1SAmir Ayupov const MCPseudoProbeDecoder &Decoder, 65c00c62c1SAmir Ayupov const MCDecodedPseudoProbeInlineTree &Root) { 66c00c62c1SAmir Ayupov auto getHash = [&](const MCDecodedPseudoProbeInlineTree &Node) { 67c00c62c1SAmir Ayupov return Decoder.getFuncDescForGUID(Node.Guid)->FuncHash; 68c00c62c1SAmir Ayupov }; 69c00c62c1SAmir Ayupov std::vector<InlineTreeNode> InlineTree( 70c00c62c1SAmir Ayupov {InlineTreeNode{&Root, Root.Guid, getHash(Root), 0, 0}}); 71c00c62c1SAmir Ayupov uint32_t ParentId = 0; 72c00c62c1SAmir Ayupov while (ParentId != InlineTree.size()) { 73c00c62c1SAmir Ayupov const MCDecodedPseudoProbeInlineTree *Cur = InlineTree[ParentId].InlineTree; 74c00c62c1SAmir Ayupov for (const MCDecodedPseudoProbeInlineTree &Child : Cur->getChildren()) 75c00c62c1SAmir Ayupov InlineTree.emplace_back( 76c00c62c1SAmir Ayupov InlineTreeNode{&Child, Child.Guid, getHash(Child), ParentId, 77c00c62c1SAmir Ayupov std::get<1>(Child.getInlineSite())}); 78c00c62c1SAmir Ayupov ++ParentId; 79c00c62c1SAmir Ayupov } 80c00c62c1SAmir Ayupov 81c00c62c1SAmir Ayupov return InlineTree; 82c00c62c1SAmir Ayupov } 83c00c62c1SAmir Ayupov 84cd774c87SAmir Ayupov std::tuple<yaml::bolt::ProfilePseudoProbeDesc, 85cd774c87SAmir Ayupov YAMLProfileWriter::InlineTreeDesc> 86c00c62c1SAmir Ayupov YAMLProfileWriter::convertPseudoProbeDesc(const MCPseudoProbeDecoder &Decoder) { 87cd774c87SAmir Ayupov yaml::bolt::ProfilePseudoProbeDesc Desc; 88c00c62c1SAmir Ayupov InlineTreeDesc InlineTree; 89c00c62c1SAmir Ayupov 90c00c62c1SAmir Ayupov for (const MCDecodedPseudoProbeInlineTree &TopLev : 91c00c62c1SAmir Ayupov Decoder.getDummyInlineRoot().getChildren()) 92c00c62c1SAmir Ayupov InlineTree.TopLevelGUIDToInlineTree[TopLev.Guid] = &TopLev; 93c00c62c1SAmir Ayupov 94c00c62c1SAmir Ayupov for (const auto &FuncDesc : Decoder.getGUID2FuncDescMap()) 95c00c62c1SAmir Ayupov ++InlineTree.HashIdxMap[FuncDesc.FuncHash]; 96c00c62c1SAmir Ayupov 97c00c62c1SAmir Ayupov InlineTree.GUIDIdxMap.reserve(Decoder.getGUID2FuncDescMap().size()); 98c00c62c1SAmir Ayupov for (const auto &Node : Decoder.getInlineTreeVec()) 99c00c62c1SAmir Ayupov ++InlineTree.GUIDIdxMap[Node.Guid]; 100c00c62c1SAmir Ayupov 101c00c62c1SAmir Ayupov std::vector<std::pair<uint32_t, uint64_t>> GUIDFreqVec; 102c00c62c1SAmir Ayupov GUIDFreqVec.reserve(InlineTree.GUIDIdxMap.size()); 103c00c62c1SAmir Ayupov for (const auto [GUID, Cnt] : InlineTree.GUIDIdxMap) 104c00c62c1SAmir Ayupov GUIDFreqVec.emplace_back(Cnt, GUID); 105c00c62c1SAmir Ayupov llvm::sort(GUIDFreqVec); 106c00c62c1SAmir Ayupov 107c00c62c1SAmir Ayupov std::vector<std::pair<uint32_t, uint64_t>> HashFreqVec; 108c00c62c1SAmir Ayupov HashFreqVec.reserve(InlineTree.HashIdxMap.size()); 109c00c62c1SAmir Ayupov for (const auto [Hash, Cnt] : InlineTree.HashIdxMap) 110c00c62c1SAmir Ayupov HashFreqVec.emplace_back(Cnt, Hash); 111c00c62c1SAmir Ayupov llvm::sort(HashFreqVec); 112c00c62c1SAmir Ayupov 113c00c62c1SAmir Ayupov uint32_t Index = 0; 114c00c62c1SAmir Ayupov Desc.Hash.reserve(HashFreqVec.size()); 115c00c62c1SAmir Ayupov for (uint64_t Hash : llvm::make_second_range(llvm::reverse(HashFreqVec))) { 116c00c62c1SAmir Ayupov Desc.Hash.emplace_back(Hash); 117c00c62c1SAmir Ayupov InlineTree.HashIdxMap[Hash] = Index++; 118c00c62c1SAmir Ayupov } 119c00c62c1SAmir Ayupov 120c00c62c1SAmir Ayupov Index = 0; 121c00c62c1SAmir Ayupov Desc.GUID.reserve(GUIDFreqVec.size()); 122c00c62c1SAmir Ayupov for (uint64_t GUID : llvm::make_second_range(llvm::reverse(GUIDFreqVec))) { 123c00c62c1SAmir Ayupov Desc.GUID.emplace_back(GUID); 124c00c62c1SAmir Ayupov InlineTree.GUIDIdxMap[GUID] = Index++; 125c00c62c1SAmir Ayupov uint64_t Hash = Decoder.getFuncDescForGUID(GUID)->FuncHash; 126c00c62c1SAmir Ayupov Desc.GUIDHashIdx.emplace_back(InlineTree.HashIdxMap[Hash]); 127c00c62c1SAmir Ayupov } 128c00c62c1SAmir Ayupov 129c00c62c1SAmir Ayupov return {Desc, InlineTree}; 130c00c62c1SAmir Ayupov } 131c00c62c1SAmir Ayupov 132c00c62c1SAmir Ayupov std::vector<yaml::bolt::PseudoProbeInfo> 133c00c62c1SAmir Ayupov YAMLProfileWriter::convertNodeProbes(NodeIdToProbes &NodeProbes) { 134c00c62c1SAmir Ayupov struct BlockProbeInfoHasher { 135c00c62c1SAmir Ayupov size_t operator()(const yaml::bolt::PseudoProbeInfo &BPI) const { 136c00c62c1SAmir Ayupov auto HashCombine = [](auto &Range) { 137c00c62c1SAmir Ayupov return llvm::hash_combine_range(Range.begin(), Range.end()); 138c00c62c1SAmir Ayupov }; 139c00c62c1SAmir Ayupov return llvm::hash_combine(HashCombine(BPI.BlockProbes), 140c00c62c1SAmir Ayupov HashCombine(BPI.CallProbes), 141c00c62c1SAmir Ayupov HashCombine(BPI.IndCallProbes)); 142c00c62c1SAmir Ayupov } 143c00c62c1SAmir Ayupov }; 144c00c62c1SAmir Ayupov 145c00c62c1SAmir Ayupov // Check identical BlockProbeInfo structs and merge them 146c00c62c1SAmir Ayupov std::unordered_map<yaml::bolt::PseudoProbeInfo, std::vector<uint32_t>, 147c00c62c1SAmir Ayupov BlockProbeInfoHasher> 148c00c62c1SAmir Ayupov BPIToNodes; 149c00c62c1SAmir Ayupov for (auto &[NodeId, Probes] : NodeProbes) { 150c00c62c1SAmir Ayupov yaml::bolt::PseudoProbeInfo BPI; 151c00c62c1SAmir Ayupov BPI.BlockProbes = std::vector(Probes[0].begin(), Probes[0].end()); 152c00c62c1SAmir Ayupov BPI.IndCallProbes = std::vector(Probes[1].begin(), Probes[1].end()); 153c00c62c1SAmir Ayupov BPI.CallProbes = std::vector(Probes[2].begin(), Probes[2].end()); 154c00c62c1SAmir Ayupov BPIToNodes[BPI].push_back(NodeId); 155c00c62c1SAmir Ayupov } 156c00c62c1SAmir Ayupov 157c00c62c1SAmir Ayupov auto handleMask = [](const auto &Ids, auto &Vec, auto &Mask) { 158c00c62c1SAmir Ayupov for (auto Id : Ids) 159c00c62c1SAmir Ayupov if (Id > 64) 160c00c62c1SAmir Ayupov Vec.emplace_back(Id); 161c00c62c1SAmir Ayupov else 162c00c62c1SAmir Ayupov Mask |= 1ull << (Id - 1); 163c00c62c1SAmir Ayupov }; 164c00c62c1SAmir Ayupov 165c00c62c1SAmir Ayupov // Add to YAML with merged nodes/block mask optimizations 166c00c62c1SAmir Ayupov std::vector<yaml::bolt::PseudoProbeInfo> YamlProbes; 167c00c62c1SAmir Ayupov YamlProbes.reserve(BPIToNodes.size()); 168c00c62c1SAmir Ayupov for (const auto &[BPI, Nodes] : BPIToNodes) { 169c00c62c1SAmir Ayupov auto &YamlBPI = YamlProbes.emplace_back(yaml::bolt::PseudoProbeInfo()); 170c00c62c1SAmir Ayupov YamlBPI.CallProbes = BPI.CallProbes; 171c00c62c1SAmir Ayupov YamlBPI.IndCallProbes = BPI.IndCallProbes; 172c00c62c1SAmir Ayupov if (Nodes.size() == 1) 173c00c62c1SAmir Ayupov YamlBPI.InlineTreeIndex = Nodes.front(); 174c00c62c1SAmir Ayupov else 175c00c62c1SAmir Ayupov YamlBPI.InlineTreeNodes = Nodes; 176c00c62c1SAmir Ayupov handleMask(BPI.BlockProbes, YamlBPI.BlockProbes, YamlBPI.BlockMask); 177c00c62c1SAmir Ayupov } 178c00c62c1SAmir Ayupov return YamlProbes; 179c00c62c1SAmir Ayupov } 180c00c62c1SAmir Ayupov 181c00c62c1SAmir Ayupov std::tuple<std::vector<yaml::bolt::InlineTreeNode>, 182c00c62c1SAmir Ayupov YAMLProfileWriter::InlineTreeMapTy> 183c00c62c1SAmir Ayupov YAMLProfileWriter::convertBFInlineTree(const MCPseudoProbeDecoder &Decoder, 184c00c62c1SAmir Ayupov const InlineTreeDesc &InlineTree, 185c00c62c1SAmir Ayupov uint64_t GUID) { 186c00c62c1SAmir Ayupov DenseMap<const MCDecodedPseudoProbeInlineTree *, uint32_t> InlineTreeNodeId; 187c00c62c1SAmir Ayupov std::vector<yaml::bolt::InlineTreeNode> YamlInlineTree; 188c00c62c1SAmir Ayupov auto It = InlineTree.TopLevelGUIDToInlineTree.find(GUID); 189c00c62c1SAmir Ayupov if (It == InlineTree.TopLevelGUIDToInlineTree.end()) 190c00c62c1SAmir Ayupov return {YamlInlineTree, InlineTreeNodeId}; 191c00c62c1SAmir Ayupov const MCDecodedPseudoProbeInlineTree *Root = It->second; 192c00c62c1SAmir Ayupov assert(Root && "Malformed TopLevelGUIDToInlineTree"); 193c00c62c1SAmir Ayupov uint32_t Index = 0; 194c00c62c1SAmir Ayupov uint32_t PrevParent = 0; 195c00c62c1SAmir Ayupov uint32_t PrevGUIDIdx = 0; 196c00c62c1SAmir Ayupov for (const auto &Node : collectInlineTree(Decoder, *Root)) { 197c00c62c1SAmir Ayupov InlineTreeNodeId[Node.InlineTree] = Index++; 198c00c62c1SAmir Ayupov auto GUIDIdxIt = InlineTree.GUIDIdxMap.find(Node.GUID); 199c00c62c1SAmir Ayupov assert(GUIDIdxIt != InlineTree.GUIDIdxMap.end() && "Malformed GUIDIdxMap"); 200c00c62c1SAmir Ayupov uint32_t GUIDIdx = GUIDIdxIt->second; 201c00c62c1SAmir Ayupov if (GUIDIdx == PrevGUIDIdx) 202c00c62c1SAmir Ayupov GUIDIdx = UINT32_MAX; 203c00c62c1SAmir Ayupov else 204c00c62c1SAmir Ayupov PrevGUIDIdx = GUIDIdx; 205c00c62c1SAmir Ayupov YamlInlineTree.emplace_back(yaml::bolt::InlineTreeNode{ 206*06e08696SKazu Hirata Node.ParentId - PrevParent, Node.InlineSite, GUIDIdx, 0, 0}); 207c00c62c1SAmir Ayupov PrevParent = Node.ParentId; 208c00c62c1SAmir Ayupov } 209c00c62c1SAmir Ayupov return {YamlInlineTree, InlineTreeNodeId}; 210c00c62c1SAmir Ayupov } 211c00c62c1SAmir Ayupov 212061b4089SAmir Ayupov yaml::bolt::BinaryFunctionProfile 2132d3c827cSAmir Ayupov YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS, 214c00c62c1SAmir Ayupov const InlineTreeDesc &InlineTree, 2152d3c827cSAmir Ayupov const BoltAddressTranslation *BAT) { 216061b4089SAmir Ayupov yaml::bolt::BinaryFunctionProfile YamlBF; 217a34c753fSRafael Auler const BinaryContext &BC = BF.getBinaryContext(); 2184d19676dSAmir Ayupov const MCPseudoProbeDecoder *PseudoProbeDecoder = 219c820bd3eSAmir Ayupov opts::ProfileWritePseudoProbes ? BC.getPseudoProbeDecoder() : nullptr; 220a34c753fSRafael Auler 221a34c753fSRafael Auler const uint16_t LBRProfile = BF.getProfileFlags() & BinaryFunction::PF_LBR; 222a34c753fSRafael Auler 2233e3a926bSspupyrev // Prepare function and block hashes 224061b4089SAmir Ayupov BF.computeHash(UseDFS); 2253e3a926bSspupyrev BF.computeBlockHashes(); 2263e3a926bSspupyrev 22797025bd9SAmir Ayupov YamlBF.Name = DataAggregator::getLocationName(BF, BAT); 228a34c753fSRafael Auler YamlBF.Id = BF.getFunctionNumber(); 2293e3a926bSspupyrev YamlBF.Hash = BF.getHash(); 230a34c753fSRafael Auler YamlBF.NumBasicBlocks = BF.size(); 231a34c753fSRafael Auler YamlBF.ExecCount = BF.getKnownExecutionCount(); 232c00c62c1SAmir Ayupov DenseMap<const MCDecodedPseudoProbeInlineTree *, uint32_t> InlineTreeNodeId; 233c00c62c1SAmir Ayupov if (PseudoProbeDecoder && BF.getGUID()) { 234c00c62c1SAmir Ayupov std::tie(YamlBF.InlineTree, InlineTreeNodeId) = 235c00c62c1SAmir Ayupov convertBFInlineTree(*PseudoProbeDecoder, InlineTree, BF.getGUID()); 2369b007a19SAmir Ayupov } 237a34c753fSRafael Auler 23869b7e257SAmir Ayupov BinaryFunction::BasicBlockOrderType Order; 239061b4089SAmir Ayupov llvm::copy(UseDFS ? BF.dfs() : BF.getLayout().blocks(), 24069b7e257SAmir Ayupov std::back_inserter(Order)); 24169b7e257SAmir Ayupov 2424be3083bSshaw young const FunctionLayout Layout = BF.getLayout(); 2434be3083bSshaw young Layout.updateLayoutIndices(Order); 2444be3083bSshaw young 24569b7e257SAmir Ayupov for (const BinaryBasicBlock *BB : Order) { 246a34c753fSRafael Auler yaml::bolt::BinaryBasicBlockProfile YamlBB; 247a34c753fSRafael Auler YamlBB.Index = BB->getLayoutIndex(); 248a34c753fSRafael Auler YamlBB.NumInstructions = BB->getNumNonPseudos(); 2493e3a926bSspupyrev YamlBB.Hash = BB->getHash(); 250a34c753fSRafael Auler 251a34c753fSRafael Auler if (!LBRProfile) { 252a34c753fSRafael Auler YamlBB.EventCount = BB->getKnownExecutionCount(); 253a34c753fSRafael Auler if (YamlBB.EventCount) 254a34c753fSRafael Auler YamlBF.Blocks.emplace_back(YamlBB); 255a34c753fSRafael Auler continue; 256a34c753fSRafael Auler } 257a34c753fSRafael Auler 258a34c753fSRafael Auler YamlBB.ExecCount = BB->getKnownExecutionCount(); 259a34c753fSRafael Auler 260a34c753fSRafael Auler for (const MCInst &Instr : *BB) { 261a34c753fSRafael Auler if (!BC.MIB->isCall(Instr) && !BC.MIB->isIndirectBranch(Instr)) 262a34c753fSRafael Auler continue; 263a34c753fSRafael Auler 2646c873155SAmir Ayupov SmallVector<std::pair<StringRef, yaml::bolt::CallSiteInfo>> CSTargets; 265a34c753fSRafael Auler yaml::bolt::CallSiteInfo CSI; 2662563fd63SAmir Ayupov std::optional<uint32_t> Offset = BC.MIB->getOffset(Instr); 267a9cd49d5SAmir Ayupov if (!Offset || *Offset < BB->getInputOffset()) 268a34c753fSRafael Auler continue; 269a9cd49d5SAmir Ayupov CSI.Offset = *Offset - BB->getInputOffset(); 270a34c753fSRafael Auler 271a34c753fSRafael Auler if (BC.MIB->isIndirectCall(Instr) || BC.MIB->isIndirectBranch(Instr)) { 272f18fcdabSAmir Ayupov const auto ICSP = BC.MIB->tryGetAnnotationAs<IndirectCallSiteProfile>( 27340c2e0faSMaksim Panchenko Instr, "CallProfile"); 274a34c753fSRafael Auler if (!ICSP) 275a34c753fSRafael Auler continue; 276a34c753fSRafael Auler for (const IndirectCallProfile &CSP : ICSP.get()) { 2776c873155SAmir Ayupov StringRef TargetName = ""; 2782d3c827cSAmir Ayupov const BinaryFunction *Callee = 2792d3c827cSAmir Ayupov setCSIDestination(BC, CSI, CSP.Symbol, BAT); 280385e3e26SAmir Ayupov if (Callee) 2816c873155SAmir Ayupov TargetName = Callee->getOneName(); 282a34c753fSRafael Auler CSI.Count = CSP.Count; 283a34c753fSRafael Auler CSI.Mispreds = CSP.Mispreds; 2846c873155SAmir Ayupov CSTargets.emplace_back(TargetName, CSI); 285a34c753fSRafael Auler } 286a34c753fSRafael Auler } else { // direct call or a tail call 2876c873155SAmir Ayupov StringRef TargetName = ""; 288a34c753fSRafael Auler const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(Instr); 289a34c753fSRafael Auler const BinaryFunction *const Callee = 2902d3c827cSAmir Ayupov setCSIDestination(BC, CSI, CalleeSymbol, BAT); 291385e3e26SAmir Ayupov if (Callee) 2926c873155SAmir Ayupov TargetName = Callee->getOneName(); 293a34c753fSRafael Auler 294de0abc09SAmir Ayupov auto getAnnotationWithDefault = [&](const MCInst &Inst, StringRef Ann) { 295de0abc09SAmir Ayupov return BC.MIB->getAnnotationWithDefault(Instr, Ann, 0ull); 296de0abc09SAmir Ayupov }; 297a34c753fSRafael Auler if (BC.MIB->getConditionalTailCall(Instr)) { 298de0abc09SAmir Ayupov CSI.Count = getAnnotationWithDefault(Instr, "CTCTakenCount"); 299de0abc09SAmir Ayupov CSI.Mispreds = getAnnotationWithDefault(Instr, "CTCMispredCount"); 300a34c753fSRafael Auler } else { 301de0abc09SAmir Ayupov CSI.Count = getAnnotationWithDefault(Instr, "Count"); 302a34c753fSRafael Auler } 303a34c753fSRafael Auler 304a34c753fSRafael Auler if (CSI.Count) 3056c873155SAmir Ayupov CSTargets.emplace_back(TargetName, CSI); 306a34c753fSRafael Auler } 3076c873155SAmir Ayupov // Sort targets in a similar way to getBranchData, see Location::operator< 3086c873155SAmir Ayupov llvm::sort(CSTargets, [](const auto &RHS, const auto &LHS) { 3096c873155SAmir Ayupov if (RHS.first != LHS.first) 3106c873155SAmir Ayupov return RHS.first < LHS.first; 3116c873155SAmir Ayupov return RHS.second.Offset < LHS.second.Offset; 3126c873155SAmir Ayupov }); 3136c873155SAmir Ayupov for (auto &KV : CSTargets) 3146c873155SAmir Ayupov YamlBB.CallSites.push_back(KV.second); 315a34c753fSRafael Auler } 316a34c753fSRafael Auler 317a34c753fSRafael Auler // Skip printing if there's no profile data for non-entry basic block. 318a34c753fSRafael Auler // Include landing pads with non-zero execution count. 31940c2e0faSMaksim Panchenko if (YamlBB.CallSites.empty() && !BB->isEntryPoint() && 320a34c753fSRafael Auler !(BB->isLandingPad() && BB->getKnownExecutionCount() != 0)) { 3213e3a926bSspupyrev // Include blocks having successors or predecessors with positive counts. 322a34c753fSRafael Auler uint64_t SuccessorExecCount = 0; 323a34c753fSRafael Auler for (const BinaryBasicBlock::BinaryBranchInfo &BranchInfo : 324def464aaSAmir Ayupov BB->branch_info()) 325a34c753fSRafael Auler SuccessorExecCount += BranchInfo.Count; 3263e3a926bSspupyrev uint64_t PredecessorExecCount = 0; 3273e3a926bSspupyrev for (auto Pred : BB->predecessors()) 3283e3a926bSspupyrev PredecessorExecCount += Pred->getBranchInfo(*BB).Count; 3293e3a926bSspupyrev if (!SuccessorExecCount && !PredecessorExecCount) 330a34c753fSRafael Auler continue; 331a34c753fSRafael Auler } 332a34c753fSRafael Auler 333a34c753fSRafael Auler auto BranchInfo = BB->branch_info_begin(); 334a34c753fSRafael Auler for (const BinaryBasicBlock *Successor : BB->successors()) { 335a34c753fSRafael Auler yaml::bolt::SuccessorInfo YamlSI; 336a34c753fSRafael Auler YamlSI.Index = Successor->getLayoutIndex(); 337a34c753fSRafael Auler YamlSI.Count = BranchInfo->Count; 338a34c753fSRafael Auler YamlSI.Mispreds = BranchInfo->MispredictedCount; 339a34c753fSRafael Auler 340a34c753fSRafael Auler YamlBB.Successors.emplace_back(YamlSI); 341a34c753fSRafael Auler 342a34c753fSRafael Auler ++BranchInfo; 343a34c753fSRafael Auler } 344a34c753fSRafael Auler 345c905db67SAmir Ayupov if (PseudoProbeDecoder) { 346c905db67SAmir Ayupov const AddressProbesMap &ProbeMap = 347c905db67SAmir Ayupov PseudoProbeDecoder->getAddress2ProbesMap(); 348c905db67SAmir Ayupov const uint64_t FuncAddr = BF.getAddress(); 349c905db67SAmir Ayupov const std::pair<uint64_t, uint64_t> &BlockRange = 350c905db67SAmir Ayupov BB->getInputAddressRange(); 351c00c62c1SAmir Ayupov const std::pair<uint64_t, uint64_t> BlockAddrRange = { 352c00c62c1SAmir Ayupov FuncAddr + BlockRange.first, FuncAddr + BlockRange.second}; 353c00c62c1SAmir Ayupov auto Probes = ProbeMap.find(BlockAddrRange.first, BlockAddrRange.second); 354c00c62c1SAmir Ayupov YamlBB.PseudoProbes = writeBlockProbes(Probes, InlineTreeNodeId); 355c905db67SAmir Ayupov } 356c905db67SAmir Ayupov 357a34c753fSRafael Auler YamlBF.Blocks.emplace_back(YamlBB); 358a34c753fSRafael Auler } 359061b4089SAmir Ayupov return YamlBF; 360a34c753fSRafael Auler } 361a34c753fSRafael Auler 36240c2e0faSMaksim Panchenko std::error_code YAMLProfileWriter::writeProfile(const RewriteInstance &RI) { 363a34c753fSRafael Auler const BinaryContext &BC = RI.getBinaryContext(); 364a34c753fSRafael Auler const auto &Functions = BC.getBinaryFunctions(); 365a34c753fSRafael Auler 366a34c753fSRafael Auler std::error_code EC; 367a34c753fSRafael Auler OS = std::make_unique<raw_fd_ostream>(Filename, EC, sys::fs::OF_None); 368a34c753fSRafael Auler if (EC) { 369a34c753fSRafael Auler errs() << "BOLT-WARNING: " << EC.message() << " : unable to open " 370a34c753fSRafael Auler << Filename << " for output.\n"; 371a34c753fSRafael Auler return EC; 372a34c753fSRafael Auler } 373a34c753fSRafael Auler 374a34c753fSRafael Auler yaml::bolt::BinaryProfile BP; 375a34c753fSRafael Auler 376a34c753fSRafael Auler // Fill out the header info. 377a34c753fSRafael Auler BP.Header.Version = 1; 378a34c753fSRafael Auler BP.Header.FileName = std::string(BC.getFilename()); 379e8f5743eSAmir Ayupov std::optional<StringRef> BuildID = BC.getFileBuildID(); 380a34c753fSRafael Auler BP.Header.Id = BuildID ? std::string(*BuildID) : "<unknown>"; 381a34c753fSRafael Auler BP.Header.Origin = std::string(RI.getProfileReader()->getReaderName()); 3821e0d08e8SAmir Ayupov BP.Header.IsDFSOrder = opts::ProfileUseDFS; 383b039ccc6SAmir Ayupov BP.Header.HashFunction = HashFunction::Default; 384a34c753fSRafael Auler 385a34c753fSRafael Auler StringSet<> EventNames = RI.getProfileReader()->getEventNames(); 386a34c753fSRafael Auler if (!EventNames.empty()) { 387ce3b687bSKazu Hirata std::string Sep; 38834bcadc3SKazu Hirata for (const StringMapEntry<std::nullopt_t> &EventEntry : EventNames) { 389a34c753fSRafael Auler BP.Header.EventNames += Sep + EventEntry.first().str(); 390a34c753fSRafael Auler Sep = ","; 391a34c753fSRafael Auler } 392a34c753fSRafael Auler } 393a34c753fSRafael Auler 394a34c753fSRafael Auler // Make sure the profile is consistent across all functions. 395a34c753fSRafael Auler uint16_t ProfileFlags = BinaryFunction::PF_NONE; 396a34c753fSRafael Auler for (const auto &BFI : Functions) { 397a34c753fSRafael Auler const BinaryFunction &BF = BFI.second; 398a34c753fSRafael Auler if (BF.hasProfile() && !BF.empty()) { 399a34c753fSRafael Auler assert(BF.getProfileFlags() != BinaryFunction::PF_NONE); 400def464aaSAmir Ayupov if (ProfileFlags == BinaryFunction::PF_NONE) 401a34c753fSRafael Auler ProfileFlags = BF.getProfileFlags(); 402def464aaSAmir Ayupov 403a34c753fSRafael Auler assert(BF.getProfileFlags() == ProfileFlags && 404a34c753fSRafael Auler "expected consistent profile flags across all functions"); 405a34c753fSRafael Auler } 406a34c753fSRafael Auler } 407a34c753fSRafael Auler BP.Header.Flags = ProfileFlags; 408a34c753fSRafael Auler 409c00c62c1SAmir Ayupov // Add probe inline tree nodes. 410c00c62c1SAmir Ayupov InlineTreeDesc InlineTree; 411c00c62c1SAmir Ayupov if (const MCPseudoProbeDecoder *Decoder = 412c00c62c1SAmir Ayupov opts::ProfileWritePseudoProbes ? BC.getPseudoProbeDecoder() : nullptr) 413c00c62c1SAmir Ayupov std::tie(BP.PseudoProbeDesc, InlineTree) = convertPseudoProbeDesc(*Decoder); 414c00c62c1SAmir Ayupov 415a34c753fSRafael Auler // Add all function objects. 416a34c753fSRafael Auler for (const auto &BFI : Functions) { 417a34c753fSRafael Auler const BinaryFunction &BF = BFI.second; 418a34c753fSRafael Auler if (BF.hasProfile()) { 419a34c753fSRafael Auler if (!BF.hasValidProfile() && !RI.getProfileReader()->isTrustedSource()) 420a34c753fSRafael Auler continue; 421a34c753fSRafael Auler 422c00c62c1SAmir Ayupov BP.Functions.emplace_back(convert(BF, opts::ProfileUseDFS, InlineTree)); 423a34c753fSRafael Auler } 424a34c753fSRafael Auler } 425a34c753fSRafael Auler 426a34c753fSRafael Auler // Write the profile. 427a34c753fSRafael Auler yaml::Output Out(*OS, nullptr, 0); 428a34c753fSRafael Auler Out << BP; 429a34c753fSRafael Auler 430a34c753fSRafael Auler return std::error_code(); 431a34c753fSRafael Auler } 432a34c753fSRafael Auler 433a34c753fSRafael Auler } // namespace bolt 434a34c753fSRafael Auler } // namespace llvm 435