1 //===- bolt/Profile/YAMLProfileWriter.cpp - YAML profile serializer -------===// 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 #include "bolt/Profile/YAMLProfileWriter.h" 10 #include "bolt/Core/BinaryBasicBlock.h" 11 #include "bolt/Core/BinaryFunction.h" 12 #include "bolt/Profile/ProfileReaderBase.h" 13 #include "bolt/Profile/ProfileYAMLMapping.h" 14 #include "bolt/Rewrite/RewriteInstance.h" 15 #include "llvm/Support/FileSystem.h" 16 #include "llvm/Support/raw_ostream.h" 17 18 #undef DEBUG_TYPE 19 #define DEBUG_TYPE "bolt-prof" 20 21 namespace llvm { 22 namespace bolt { 23 24 namespace { 25 void convert(const BinaryFunction &BF, 26 yaml::bolt::BinaryFunctionProfile &YamlBF) { 27 const BinaryContext &BC = BF.getBinaryContext(); 28 29 const uint16_t LBRProfile = BF.getProfileFlags() & BinaryFunction::PF_LBR; 30 31 YamlBF.Name = BF.getPrintName(); 32 YamlBF.Id = BF.getFunctionNumber(); 33 YamlBF.Hash = BF.computeHash(/*UseDFS=*/true); 34 YamlBF.NumBasicBlocks = BF.size(); 35 YamlBF.ExecCount = BF.getKnownExecutionCount(); 36 37 for (const BinaryBasicBlock *BB : BF.dfs()) { 38 yaml::bolt::BinaryBasicBlockProfile YamlBB; 39 YamlBB.Index = BB->getLayoutIndex(); 40 YamlBB.NumInstructions = BB->getNumNonPseudos(); 41 42 if (!LBRProfile) { 43 YamlBB.EventCount = BB->getKnownExecutionCount(); 44 if (YamlBB.EventCount) 45 YamlBF.Blocks.emplace_back(YamlBB); 46 continue; 47 } 48 49 YamlBB.ExecCount = BB->getKnownExecutionCount(); 50 51 for (const MCInst &Instr : *BB) { 52 if (!BC.MIB->isCall(Instr) && !BC.MIB->isIndirectBranch(Instr)) 53 continue; 54 55 yaml::bolt::CallSiteInfo CSI; 56 auto Offset = BC.MIB->tryGetAnnotationAs<uint32_t>(Instr, "Offset"); 57 if (!Offset || Offset.get() < BB->getInputOffset()) 58 continue; 59 CSI.Offset = Offset.get() - BB->getInputOffset(); 60 61 if (BC.MIB->isIndirectCall(Instr) || BC.MIB->isIndirectBranch(Instr)) { 62 auto ICSP = BC.MIB->tryGetAnnotationAs<IndirectCallSiteProfile>( 63 Instr, "CallProfile"); 64 if (!ICSP) 65 continue; 66 for (const IndirectCallProfile &CSP : ICSP.get()) { 67 CSI.DestId = 0; // designated for unknown functions 68 CSI.EntryDiscriminator = 0; 69 if (CSP.Symbol) { 70 const BinaryFunction *Callee = BC.getFunctionForSymbol(CSP.Symbol); 71 if (Callee) { 72 CSI.DestId = Callee->getFunctionNumber(); 73 } 74 } 75 CSI.Count = CSP.Count; 76 CSI.Mispreds = CSP.Mispreds; 77 YamlBB.CallSites.push_back(CSI); 78 } 79 } else { // direct call or a tail call 80 uint64_t EntryID = 0; 81 const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(Instr); 82 const BinaryFunction *const Callee = 83 BC.getFunctionForSymbol(CalleeSymbol, &EntryID); 84 if (Callee) { 85 CSI.DestId = Callee->getFunctionNumber(); 86 CSI.EntryDiscriminator = EntryID; 87 } 88 89 if (BC.MIB->getConditionalTailCall(Instr)) { 90 auto CTCCount = 91 BC.MIB->tryGetAnnotationAs<uint64_t>(Instr, "CTCTakenCount"); 92 if (CTCCount) { 93 CSI.Count = *CTCCount; 94 auto CTCMispreds = 95 BC.MIB->tryGetAnnotationAs<uint64_t>(Instr, "CTCMispredCount"); 96 if (CTCMispreds) 97 CSI.Mispreds = *CTCMispreds; 98 } 99 } else { 100 auto Count = BC.MIB->tryGetAnnotationAs<uint64_t>(Instr, "Count"); 101 if (Count) 102 CSI.Count = *Count; 103 } 104 105 if (CSI.Count) 106 YamlBB.CallSites.emplace_back(CSI); 107 } 108 } 109 110 std::sort(YamlBB.CallSites.begin(), YamlBB.CallSites.end()); 111 112 // Skip printing if there's no profile data for non-entry basic block. 113 // Include landing pads with non-zero execution count. 114 if (YamlBB.CallSites.empty() && !BB->isEntryPoint() && 115 !(BB->isLandingPad() && BB->getKnownExecutionCount() != 0)) { 116 uint64_t SuccessorExecCount = 0; 117 for (const BinaryBasicBlock::BinaryBranchInfo &BranchInfo : 118 BB->branch_info()) { 119 SuccessorExecCount += BranchInfo.Count; 120 } 121 if (!SuccessorExecCount) 122 continue; 123 } 124 125 auto BranchInfo = BB->branch_info_begin(); 126 for (const BinaryBasicBlock *Successor : BB->successors()) { 127 yaml::bolt::SuccessorInfo YamlSI; 128 YamlSI.Index = Successor->getLayoutIndex(); 129 YamlSI.Count = BranchInfo->Count; 130 YamlSI.Mispreds = BranchInfo->MispredictedCount; 131 132 YamlBB.Successors.emplace_back(YamlSI); 133 134 ++BranchInfo; 135 } 136 137 YamlBF.Blocks.emplace_back(YamlBB); 138 } 139 } 140 } // end anonymous namespace 141 142 std::error_code YAMLProfileWriter::writeProfile(const RewriteInstance &RI) { 143 const BinaryContext &BC = RI.getBinaryContext(); 144 const auto &Functions = BC.getBinaryFunctions(); 145 146 std::error_code EC; 147 OS = std::make_unique<raw_fd_ostream>(Filename, EC, sys::fs::OF_None); 148 if (EC) { 149 errs() << "BOLT-WARNING: " << EC.message() << " : unable to open " 150 << Filename << " for output.\n"; 151 return EC; 152 } 153 154 yaml::bolt::BinaryProfile BP; 155 156 // Fill out the header info. 157 BP.Header.Version = 1; 158 BP.Header.FileName = std::string(BC.getFilename()); 159 Optional<StringRef> BuildID = BC.getFileBuildID(); 160 BP.Header.Id = BuildID ? std::string(*BuildID) : "<unknown>"; 161 BP.Header.Origin = std::string(RI.getProfileReader()->getReaderName()); 162 163 StringSet<> EventNames = RI.getProfileReader()->getEventNames(); 164 if (!EventNames.empty()) { 165 std::string Sep = ""; 166 for (const StringMapEntry<NoneType> &EventEntry : EventNames) { 167 BP.Header.EventNames += Sep + EventEntry.first().str(); 168 Sep = ","; 169 } 170 } 171 172 // Make sure the profile is consistent across all functions. 173 uint16_t ProfileFlags = BinaryFunction::PF_NONE; 174 for (const auto &BFI : Functions) { 175 const BinaryFunction &BF = BFI.second; 176 if (BF.hasProfile() && !BF.empty()) { 177 assert(BF.getProfileFlags() != BinaryFunction::PF_NONE); 178 if (ProfileFlags == BinaryFunction::PF_NONE) { 179 ProfileFlags = BF.getProfileFlags(); 180 } 181 assert(BF.getProfileFlags() == ProfileFlags && 182 "expected consistent profile flags across all functions"); 183 } 184 } 185 BP.Header.Flags = ProfileFlags; 186 187 // Add all function objects. 188 for (const auto &BFI : Functions) { 189 const BinaryFunction &BF = BFI.second; 190 if (BF.hasProfile()) { 191 if (!BF.hasValidProfile() && !RI.getProfileReader()->isTrustedSource()) 192 continue; 193 194 yaml::bolt::BinaryFunctionProfile YamlBF; 195 convert(BF, YamlBF); 196 BP.Functions.emplace_back(YamlBF); 197 } 198 } 199 200 // Write the profile. 201 yaml::Output Out(*OS, nullptr, 0); 202 Out << BP; 203 204 return std::error_code(); 205 } 206 207 } // namespace bolt 208 } // namespace llvm 209