1*a34c753fSRafael Auler //===-- YAMLProfileReader.cpp - BOLT YAML profile de-serializer -*- C++ -*-===// 2*a34c753fSRafael Auler // 3*a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5*a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*a34c753fSRafael Auler // 7*a34c753fSRafael Auler //===----------------------------------------------------------------------===// 8*a34c753fSRafael Auler // 9*a34c753fSRafael Auler //===----------------------------------------------------------------------===// 10*a34c753fSRafael Auler 11*a34c753fSRafael Auler #include "bolt/Profile/YAMLProfileReader.h" 12*a34c753fSRafael Auler #include "bolt/Core/BinaryBasicBlock.h" 13*a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h" 14*a34c753fSRafael Auler #include "bolt/Passes/MCF.h" 15*a34c753fSRafael Auler #include "bolt/Profile/ProfileYAMLMapping.h" 16*a34c753fSRafael Auler #include "bolt/Utils/Utils.h" 17*a34c753fSRafael Auler #include "llvm/Support/CommandLine.h" 18*a34c753fSRafael Auler 19*a34c753fSRafael Auler using namespace llvm; 20*a34c753fSRafael Auler 21*a34c753fSRafael Auler namespace opts { 22*a34c753fSRafael Auler 23*a34c753fSRafael Auler extern cl::opt<unsigned> Verbosity; 24*a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory; 25*a34c753fSRafael Auler 26*a34c753fSRafael Auler static llvm::cl::opt<bool> 27*a34c753fSRafael Auler IgnoreHash("profile-ignore-hash", 28*a34c753fSRafael Auler cl::desc("ignore hash while reading function profile"), 29*a34c753fSRafael Auler cl::init(false), 30*a34c753fSRafael Auler cl::ZeroOrMore, 31*a34c753fSRafael Auler cl::Hidden, 32*a34c753fSRafael Auler cl::cat(BoltOptCategory)); 33*a34c753fSRafael Auler 34*a34c753fSRafael Auler } 35*a34c753fSRafael Auler 36*a34c753fSRafael Auler namespace llvm { 37*a34c753fSRafael Auler namespace bolt { 38*a34c753fSRafael Auler 39*a34c753fSRafael Auler bool YAMLProfileReader::isYAML(const StringRef Filename) { 40*a34c753fSRafael Auler ErrorOr<std::unique_ptr<MemoryBuffer>> MB = 41*a34c753fSRafael Auler MemoryBuffer::getFileOrSTDIN(Filename); 42*a34c753fSRafael Auler if (std::error_code EC = MB.getError()) 43*a34c753fSRafael Auler report_error(Filename, EC); 44*a34c753fSRafael Auler StringRef Buffer = MB.get()->getBuffer(); 45*a34c753fSRafael Auler if (Buffer.startswith("---\n")) 46*a34c753fSRafael Auler return true; 47*a34c753fSRafael Auler return false; 48*a34c753fSRafael Auler } 49*a34c753fSRafael Auler 50*a34c753fSRafael Auler void YAMLProfileReader::buildNameMaps( 51*a34c753fSRafael Auler std::map<uint64_t, BinaryFunction> &Functions) { 52*a34c753fSRafael Auler for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) { 53*a34c753fSRafael Auler StringRef Name = YamlBF.Name; 54*a34c753fSRafael Auler const size_t Pos = Name.find("(*"); 55*a34c753fSRafael Auler if (Pos != StringRef::npos) 56*a34c753fSRafael Auler Name = Name.substr(0, Pos); 57*a34c753fSRafael Auler ProfileNameToProfile[Name] = &YamlBF; 58*a34c753fSRafael Auler if (const Optional<StringRef> CommonName = getLTOCommonName(Name)) { 59*a34c753fSRafael Auler LTOCommonNameMap[*CommonName].push_back(&YamlBF); 60*a34c753fSRafael Auler } 61*a34c753fSRafael Auler } 62*a34c753fSRafael Auler for (auto &BFI : Functions) { 63*a34c753fSRafael Auler const BinaryFunction &Function = BFI.second; 64*a34c753fSRafael Auler for (StringRef Name : Function.getNames()) { 65*a34c753fSRafael Auler if (const Optional<StringRef> CommonName = getLTOCommonName(Name)) { 66*a34c753fSRafael Auler LTOCommonNameFunctionMap[*CommonName].insert(&Function); 67*a34c753fSRafael Auler } 68*a34c753fSRafael Auler } 69*a34c753fSRafael Auler } 70*a34c753fSRafael Auler } 71*a34c753fSRafael Auler 72*a34c753fSRafael Auler bool YAMLProfileReader::hasLocalsWithFileName() const { 73*a34c753fSRafael Auler for (const StringMapEntry<yaml::bolt::BinaryFunctionProfile *> &KV : 74*a34c753fSRafael Auler ProfileNameToProfile) { 75*a34c753fSRafael Auler const StringRef &FuncName = KV.getKey(); 76*a34c753fSRafael Auler if (FuncName.count('/') == 2 && FuncName[0] != '/') 77*a34c753fSRafael Auler return true; 78*a34c753fSRafael Auler } 79*a34c753fSRafael Auler return false; 80*a34c753fSRafael Auler } 81*a34c753fSRafael Auler 82*a34c753fSRafael Auler bool YAMLProfileReader::parseFunctionProfile( 83*a34c753fSRafael Auler BinaryFunction &BF, 84*a34c753fSRafael Auler const yaml::bolt::BinaryFunctionProfile &YamlBF) { 85*a34c753fSRafael Auler BinaryContext &BC = BF.getBinaryContext(); 86*a34c753fSRafael Auler 87*a34c753fSRafael Auler bool ProfileMatched = true; 88*a34c753fSRafael Auler uint64_t MismatchedBlocks = 0; 89*a34c753fSRafael Auler uint64_t MismatchedCalls = 0; 90*a34c753fSRafael Auler uint64_t MismatchedEdges = 0; 91*a34c753fSRafael Auler 92*a34c753fSRafael Auler uint64_t FunctionExecutionCount = 0; 93*a34c753fSRafael Auler 94*a34c753fSRafael Auler BF.setExecutionCount(YamlBF.ExecCount); 95*a34c753fSRafael Auler 96*a34c753fSRafael Auler if (!opts::IgnoreHash && YamlBF.Hash != BF.computeHash(/*UseDFS=*/true)) { 97*a34c753fSRafael Auler if (opts::Verbosity >= 1) 98*a34c753fSRafael Auler errs() << "BOLT-WARNING: function hash mismatch\n"; 99*a34c753fSRafael Auler ProfileMatched = false; 100*a34c753fSRafael Auler } 101*a34c753fSRafael Auler 102*a34c753fSRafael Auler if (YamlBF.NumBasicBlocks != BF.size()) { 103*a34c753fSRafael Auler if (opts::Verbosity >= 1) 104*a34c753fSRafael Auler errs() << "BOLT-WARNING: number of basic blocks mismatch\n"; 105*a34c753fSRafael Auler ProfileMatched = false; 106*a34c753fSRafael Auler } 107*a34c753fSRafael Auler 108*a34c753fSRafael Auler std::vector<BinaryBasicBlock *> DFSOrder = BF.dfs(); 109*a34c753fSRafael Auler 110*a34c753fSRafael Auler for (const yaml::bolt::BinaryBasicBlockProfile &YamlBB : YamlBF.Blocks) { 111*a34c753fSRafael Auler if (YamlBB.Index >= DFSOrder.size()) { 112*a34c753fSRafael Auler if (opts::Verbosity >= 2) 113*a34c753fSRafael Auler errs() << "BOLT-WARNING: index " << YamlBB.Index 114*a34c753fSRafael Auler << " is out of bounds\n"; 115*a34c753fSRafael Auler ++MismatchedBlocks; 116*a34c753fSRafael Auler continue; 117*a34c753fSRafael Auler } 118*a34c753fSRafael Auler 119*a34c753fSRafael Auler BinaryBasicBlock &BB = *DFSOrder[YamlBB.Index]; 120*a34c753fSRafael Auler 121*a34c753fSRafael Auler // Basic samples profile (without LBR) does not have branches information 122*a34c753fSRafael Auler // and needs a special processing. 123*a34c753fSRafael Auler if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE) { 124*a34c753fSRafael Auler if (!YamlBB.EventCount) { 125*a34c753fSRafael Auler BB.setExecutionCount(0); 126*a34c753fSRafael Auler continue; 127*a34c753fSRafael Auler } 128*a34c753fSRafael Auler uint64_t NumSamples = YamlBB.EventCount * 1000; 129*a34c753fSRafael Auler if (NormalizeByInsnCount && BB.getNumNonPseudos()) { 130*a34c753fSRafael Auler NumSamples /= BB.getNumNonPseudos(); 131*a34c753fSRafael Auler } else if (NormalizeByCalls) { 132*a34c753fSRafael Auler NumSamples /= BB.getNumCalls() + 1; 133*a34c753fSRafael Auler } 134*a34c753fSRafael Auler BB.setExecutionCount(NumSamples); 135*a34c753fSRafael Auler if (BB.isEntryPoint()) 136*a34c753fSRafael Auler FunctionExecutionCount += NumSamples; 137*a34c753fSRafael Auler continue; 138*a34c753fSRafael Auler } 139*a34c753fSRafael Auler 140*a34c753fSRafael Auler BB.setExecutionCount(YamlBB.ExecCount); 141*a34c753fSRafael Auler 142*a34c753fSRafael Auler for (const yaml::bolt::CallSiteInfo &YamlCSI : YamlBB.CallSites) { 143*a34c753fSRafael Auler BinaryFunction *Callee = YamlCSI.DestId < YamlProfileToFunction.size() 144*a34c753fSRafael Auler ? YamlProfileToFunction[YamlCSI.DestId] 145*a34c753fSRafael Auler : nullptr; 146*a34c753fSRafael Auler bool IsFunction = Callee ? true : false; 147*a34c753fSRafael Auler MCSymbol *CalleeSymbol = nullptr; 148*a34c753fSRafael Auler if (IsFunction) { 149*a34c753fSRafael Auler CalleeSymbol = Callee->getSymbolForEntryID(YamlCSI.EntryDiscriminator); 150*a34c753fSRafael Auler } 151*a34c753fSRafael Auler BF.getAllCallSites().emplace_back( 152*a34c753fSRafael Auler CalleeSymbol, YamlCSI.Count, YamlCSI.Mispreds, YamlCSI.Offset); 153*a34c753fSRafael Auler 154*a34c753fSRafael Auler if (YamlCSI.Offset >= BB.getOriginalSize()) { 155*a34c753fSRafael Auler if (opts::Verbosity >= 2) 156*a34c753fSRafael Auler errs() << "BOLT-WARNING: offset " << YamlCSI.Offset 157*a34c753fSRafael Auler << " out of bounds in block " << BB.getName() << '\n'; 158*a34c753fSRafael Auler ++MismatchedCalls; 159*a34c753fSRafael Auler continue; 160*a34c753fSRafael Auler } 161*a34c753fSRafael Auler 162*a34c753fSRafael Auler MCInst *Instr = 163*a34c753fSRafael Auler BF.getInstructionAtOffset(BB.getInputOffset() + YamlCSI.Offset); 164*a34c753fSRafael Auler if (!Instr) { 165*a34c753fSRafael Auler if (opts::Verbosity >= 2) 166*a34c753fSRafael Auler errs() << "BOLT-WARNING: no instruction at offset " << YamlCSI.Offset 167*a34c753fSRafael Auler << " in block " << BB.getName() << '\n'; 168*a34c753fSRafael Auler ++MismatchedCalls; 169*a34c753fSRafael Auler continue; 170*a34c753fSRafael Auler } 171*a34c753fSRafael Auler if (!BC.MIB->isCall(*Instr) && !BC.MIB->isIndirectBranch(*Instr)) { 172*a34c753fSRafael Auler if (opts::Verbosity >= 2) 173*a34c753fSRafael Auler errs() << "BOLT-WARNING: expected call at offset " << YamlCSI.Offset 174*a34c753fSRafael Auler << " in block " << BB.getName() << '\n'; 175*a34c753fSRafael Auler ++MismatchedCalls; 176*a34c753fSRafael Auler continue; 177*a34c753fSRafael Auler } 178*a34c753fSRafael Auler 179*a34c753fSRafael Auler auto setAnnotation = [&](StringRef Name, uint64_t Count) { 180*a34c753fSRafael Auler if (BC.MIB->hasAnnotation(*Instr, Name)) { 181*a34c753fSRafael Auler if (opts::Verbosity >= 1) 182*a34c753fSRafael Auler errs() << "BOLT-WARNING: ignoring duplicate " << Name 183*a34c753fSRafael Auler << " info for offset 0x" << Twine::utohexstr(YamlCSI.Offset) 184*a34c753fSRafael Auler << " in function " << BF << '\n'; 185*a34c753fSRafael Auler return; 186*a34c753fSRafael Auler } 187*a34c753fSRafael Auler BC.MIB->addAnnotation(*Instr, Name, Count); 188*a34c753fSRafael Auler }; 189*a34c753fSRafael Auler 190*a34c753fSRafael Auler if (BC.MIB->isIndirectCall(*Instr) || BC.MIB->isIndirectBranch(*Instr)) { 191*a34c753fSRafael Auler auto &CSP = BC.MIB->getOrCreateAnnotationAs<IndirectCallSiteProfile>( 192*a34c753fSRafael Auler *Instr, "CallProfile"); 193*a34c753fSRafael Auler CSP.emplace_back(CalleeSymbol, YamlCSI.Count, YamlCSI.Mispreds); 194*a34c753fSRafael Auler } else if (BC.MIB->getConditionalTailCall(*Instr)) { 195*a34c753fSRafael Auler setAnnotation("CTCTakenCount", YamlCSI.Count); 196*a34c753fSRafael Auler setAnnotation("CTCMispredCount", YamlCSI.Mispreds); 197*a34c753fSRafael Auler } else { 198*a34c753fSRafael Auler setAnnotation("Count", YamlCSI.Count); 199*a34c753fSRafael Auler } 200*a34c753fSRafael Auler } 201*a34c753fSRafael Auler 202*a34c753fSRafael Auler for (const yaml::bolt::SuccessorInfo &YamlSI : YamlBB.Successors) { 203*a34c753fSRafael Auler if (YamlSI.Index >= DFSOrder.size()) { 204*a34c753fSRafael Auler if (opts::Verbosity >= 1) 205*a34c753fSRafael Auler errs() << "BOLT-WARNING: index out of bounds for profiled block\n"; 206*a34c753fSRafael Auler ++MismatchedEdges; 207*a34c753fSRafael Auler continue; 208*a34c753fSRafael Auler } 209*a34c753fSRafael Auler 210*a34c753fSRafael Auler BinaryBasicBlock &SuccessorBB = *DFSOrder[YamlSI.Index]; 211*a34c753fSRafael Auler if (!BB.getSuccessor(SuccessorBB.getLabel())) { 212*a34c753fSRafael Auler if (opts::Verbosity >= 1) 213*a34c753fSRafael Auler errs() << "BOLT-WARNING: no successor for block " << BB.getName() 214*a34c753fSRafael Auler << " that matches index " << YamlSI.Index << " or block " 215*a34c753fSRafael Auler << SuccessorBB.getName() << '\n'; 216*a34c753fSRafael Auler ++MismatchedEdges; 217*a34c753fSRafael Auler continue; 218*a34c753fSRafael Auler } 219*a34c753fSRafael Auler 220*a34c753fSRafael Auler BinaryBasicBlock::BinaryBranchInfo &BI = BB.getBranchInfo(SuccessorBB); 221*a34c753fSRafael Auler BI.Count += YamlSI.Count; 222*a34c753fSRafael Auler BI.MispredictedCount += YamlSI.Mispreds; 223*a34c753fSRafael Auler } 224*a34c753fSRafael Auler } 225*a34c753fSRafael Auler 226*a34c753fSRafael Auler // If basic block profile wasn't read it should be 0. 227*a34c753fSRafael Auler for (BinaryBasicBlock &BB : BF) { 228*a34c753fSRafael Auler if (BB.getExecutionCount() == BinaryBasicBlock::COUNT_NO_PROFILE) 229*a34c753fSRafael Auler BB.setExecutionCount(0); 230*a34c753fSRafael Auler } 231*a34c753fSRafael Auler 232*a34c753fSRafael Auler if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE) { 233*a34c753fSRafael Auler BF.setExecutionCount(FunctionExecutionCount); 234*a34c753fSRafael Auler estimateEdgeCounts(BF); 235*a34c753fSRafael Auler } 236*a34c753fSRafael Auler 237*a34c753fSRafael Auler ProfileMatched &= !MismatchedBlocks && !MismatchedCalls && !MismatchedEdges; 238*a34c753fSRafael Auler 239*a34c753fSRafael Auler if (ProfileMatched) 240*a34c753fSRafael Auler BF.markProfiled(YamlBP.Header.Flags); 241*a34c753fSRafael Auler 242*a34c753fSRafael Auler if (!ProfileMatched && opts::Verbosity >= 1) { 243*a34c753fSRafael Auler errs() << "BOLT-WARNING: " << MismatchedBlocks << " blocks, " 244*a34c753fSRafael Auler << MismatchedCalls << " calls, and " << MismatchedEdges 245*a34c753fSRafael Auler << " edges in profile did not match function " << BF << '\n'; 246*a34c753fSRafael Auler } 247*a34c753fSRafael Auler 248*a34c753fSRafael Auler return ProfileMatched; 249*a34c753fSRafael Auler } 250*a34c753fSRafael Auler 251*a34c753fSRafael Auler Error YAMLProfileReader::preprocessProfile(BinaryContext &BC) { 252*a34c753fSRafael Auler ErrorOr<std::unique_ptr<MemoryBuffer>> MB = 253*a34c753fSRafael Auler MemoryBuffer::getFileOrSTDIN(Filename); 254*a34c753fSRafael Auler if (std::error_code EC = MB.getError()) { 255*a34c753fSRafael Auler errs() << "ERROR: cannot open " << Filename << ": " << EC.message() << "\n"; 256*a34c753fSRafael Auler return errorCodeToError(EC); 257*a34c753fSRafael Auler } 258*a34c753fSRafael Auler yaml::Input YamlInput(MB.get()->getBuffer()); 259*a34c753fSRafael Auler 260*a34c753fSRafael Auler // Consume YAML file. 261*a34c753fSRafael Auler YamlInput >> YamlBP; 262*a34c753fSRafael Auler if (YamlInput.error()) { 263*a34c753fSRafael Auler errs() << "BOLT-ERROR: syntax error parsing profile in " << Filename 264*a34c753fSRafael Auler << " : " << YamlInput.error().message() << '\n'; 265*a34c753fSRafael Auler return errorCodeToError(YamlInput.error()); 266*a34c753fSRafael Auler } 267*a34c753fSRafael Auler 268*a34c753fSRafael Auler // Sanity check. 269*a34c753fSRafael Auler if (YamlBP.Header.Version != 1) { 270*a34c753fSRafael Auler return make_error<StringError>( 271*a34c753fSRafael Auler Twine("cannot read profile : unsupported version"), 272*a34c753fSRafael Auler inconvertibleErrorCode()); 273*a34c753fSRafael Auler } 274*a34c753fSRafael Auler if (YamlBP.Header.EventNames.find(',') != StringRef::npos) { 275*a34c753fSRafael Auler return make_error<StringError>( 276*a34c753fSRafael Auler Twine("multiple events in profile are not supported"), 277*a34c753fSRafael Auler inconvertibleErrorCode()); 278*a34c753fSRafael Auler } 279*a34c753fSRafael Auler 280*a34c753fSRafael Auler // Match profile to function based on a function name. 281*a34c753fSRafael Auler buildNameMaps(BC.getBinaryFunctions()); 282*a34c753fSRafael Auler 283*a34c753fSRafael Auler // Preliminary assign function execution count. 284*a34c753fSRafael Auler for (auto &KV : BC.getBinaryFunctions()) { 285*a34c753fSRafael Auler BinaryFunction &BF = KV.second; 286*a34c753fSRafael Auler for (StringRef Name : BF.getNames()) { 287*a34c753fSRafael Auler auto PI = ProfileNameToProfile.find(Name); 288*a34c753fSRafael Auler if (PI != ProfileNameToProfile.end()) { 289*a34c753fSRafael Auler yaml::bolt::BinaryFunctionProfile &YamlBF = *PI->getValue(); 290*a34c753fSRafael Auler BF.setExecutionCount(YamlBF.ExecCount); 291*a34c753fSRafael Auler break; 292*a34c753fSRafael Auler } 293*a34c753fSRafael Auler } 294*a34c753fSRafael Auler } 295*a34c753fSRafael Auler 296*a34c753fSRafael Auler return Error::success(); 297*a34c753fSRafael Auler } 298*a34c753fSRafael Auler 299*a34c753fSRafael Auler bool YAMLProfileReader::mayHaveProfileData(const BinaryFunction &BF) { 300*a34c753fSRafael Auler for (StringRef Name : BF.getNames()) { 301*a34c753fSRafael Auler if (ProfileNameToProfile.find(Name) != ProfileNameToProfile.end()) 302*a34c753fSRafael Auler return true; 303*a34c753fSRafael Auler if (const Optional<StringRef> CommonName = getLTOCommonName(Name)) { 304*a34c753fSRafael Auler if (LTOCommonNameMap.find(*CommonName) != LTOCommonNameMap.end()) { 305*a34c753fSRafael Auler return true; 306*a34c753fSRafael Auler } 307*a34c753fSRafael Auler } 308*a34c753fSRafael Auler } 309*a34c753fSRafael Auler 310*a34c753fSRafael Auler return false; 311*a34c753fSRafael Auler } 312*a34c753fSRafael Auler 313*a34c753fSRafael Auler Error YAMLProfileReader::readProfile(BinaryContext &BC) { 314*a34c753fSRafael Auler YamlProfileToFunction.resize(YamlBP.Functions.size() + 1); 315*a34c753fSRafael Auler 316*a34c753fSRafael Auler auto profileMatches = [](const yaml::bolt::BinaryFunctionProfile &Profile, 317*a34c753fSRafael Auler BinaryFunction &BF) { 318*a34c753fSRafael Auler if (opts::IgnoreHash && Profile.NumBasicBlocks == BF.size()) 319*a34c753fSRafael Auler return true; 320*a34c753fSRafael Auler if (!opts::IgnoreHash && 321*a34c753fSRafael Auler Profile.Hash == static_cast<uint64_t>(BF.getHash())) 322*a34c753fSRafael Auler return true; 323*a34c753fSRafael Auler return false; 324*a34c753fSRafael Auler }; 325*a34c753fSRafael Auler 326*a34c753fSRafael Auler // We have to do 2 passes since LTO introduces an ambiguity in function 327*a34c753fSRafael Auler // names. The first pass assigns profiles that match 100% by name and 328*a34c753fSRafael Auler // by hash. The second pass allows name ambiguity for LTO private functions. 329*a34c753fSRafael Auler for (auto &BFI : BC.getBinaryFunctions()) { 330*a34c753fSRafael Auler BinaryFunction &Function = BFI.second; 331*a34c753fSRafael Auler 332*a34c753fSRafael Auler // Clear function call count that may have been set while pre-processing 333*a34c753fSRafael Auler // the profile. 334*a34c753fSRafael Auler Function.setExecutionCount(BinaryFunction::COUNT_NO_PROFILE); 335*a34c753fSRafael Auler 336*a34c753fSRafael Auler // Recompute hash once per function. 337*a34c753fSRafael Auler if (!opts::IgnoreHash) 338*a34c753fSRafael Auler Function.computeHash(/*UseDFS=*/true); 339*a34c753fSRafael Auler 340*a34c753fSRafael Auler for (StringRef FunctionName : Function.getNames()) { 341*a34c753fSRafael Auler auto PI = ProfileNameToProfile.find(FunctionName); 342*a34c753fSRafael Auler if (PI == ProfileNameToProfile.end()) { 343*a34c753fSRafael Auler continue; 344*a34c753fSRafael Auler } 345*a34c753fSRafael Auler yaml::bolt::BinaryFunctionProfile &YamlBF = *PI->getValue(); 346*a34c753fSRafael Auler if (profileMatches(YamlBF, Function)) 347*a34c753fSRafael Auler matchProfileToFunction(YamlBF, Function); 348*a34c753fSRafael Auler } 349*a34c753fSRafael Auler } 350*a34c753fSRafael Auler 351*a34c753fSRafael Auler for (auto &BFI : BC.getBinaryFunctions()) { 352*a34c753fSRafael Auler BinaryFunction &Function = BFI.second; 353*a34c753fSRafael Auler 354*a34c753fSRafael Auler if (ProfiledFunctions.count(&Function)) 355*a34c753fSRafael Auler continue; 356*a34c753fSRafael Auler 357*a34c753fSRafael Auler for (StringRef FunctionName : Function.getNames()) { 358*a34c753fSRafael Auler const Optional<StringRef> CommonName = getLTOCommonName(FunctionName); 359*a34c753fSRafael Auler if (CommonName) { 360*a34c753fSRafael Auler auto I = LTOCommonNameMap.find(*CommonName); 361*a34c753fSRafael Auler if (I == LTOCommonNameMap.end()) 362*a34c753fSRafael Auler continue; 363*a34c753fSRafael Auler 364*a34c753fSRafael Auler bool ProfileMatched = false; 365*a34c753fSRafael Auler std::vector<yaml::bolt::BinaryFunctionProfile *> <OProfiles = 366*a34c753fSRafael Auler I->getValue(); 367*a34c753fSRafael Auler for (yaml::bolt::BinaryFunctionProfile *YamlBF : LTOProfiles) { 368*a34c753fSRafael Auler if (YamlBF->Used) 369*a34c753fSRafael Auler continue; 370*a34c753fSRafael Auler if ((ProfileMatched = profileMatches(*YamlBF, Function))) { 371*a34c753fSRafael Auler matchProfileToFunction(*YamlBF, Function); 372*a34c753fSRafael Auler break; 373*a34c753fSRafael Auler } 374*a34c753fSRafael Auler } 375*a34c753fSRafael Auler if (ProfileMatched) 376*a34c753fSRafael Auler break; 377*a34c753fSRafael Auler 378*a34c753fSRafael Auler // If there's only one function with a given name, try to 379*a34c753fSRafael Auler // match it partially. 380*a34c753fSRafael Auler if (LTOProfiles.size() == 1 && 381*a34c753fSRafael Auler LTOCommonNameFunctionMap[*CommonName].size() == 1 && 382*a34c753fSRafael Auler !LTOProfiles.front()->Used) { 383*a34c753fSRafael Auler matchProfileToFunction(*LTOProfiles.front(), Function); 384*a34c753fSRafael Auler break; 385*a34c753fSRafael Auler } 386*a34c753fSRafael Auler } else { 387*a34c753fSRafael Auler auto PI = ProfileNameToProfile.find(FunctionName); 388*a34c753fSRafael Auler if (PI == ProfileNameToProfile.end()) 389*a34c753fSRafael Auler continue; 390*a34c753fSRafael Auler 391*a34c753fSRafael Auler yaml::bolt::BinaryFunctionProfile &YamlBF = *PI->getValue(); 392*a34c753fSRafael Auler if (!YamlBF.Used) { 393*a34c753fSRafael Auler matchProfileToFunction(YamlBF, Function); 394*a34c753fSRafael Auler break; 395*a34c753fSRafael Auler } 396*a34c753fSRafael Auler } 397*a34c753fSRafael Auler } 398*a34c753fSRafael Auler } 399*a34c753fSRafael Auler 400*a34c753fSRafael Auler for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) { 401*a34c753fSRafael Auler if (!YamlBF.Used && opts::Verbosity >= 1) { 402*a34c753fSRafael Auler errs() << "BOLT-WARNING: profile ignored for function " << YamlBF.Name 403*a34c753fSRafael Auler << '\n'; 404*a34c753fSRafael Auler } 405*a34c753fSRafael Auler } 406*a34c753fSRafael Auler 407*a34c753fSRafael Auler // Set for parseFunctionProfile(). 408*a34c753fSRafael Auler NormalizeByInsnCount = usesEvent("cycles") || usesEvent("instructions"); 409*a34c753fSRafael Auler NormalizeByCalls = usesEvent("branches"); 410*a34c753fSRafael Auler 411*a34c753fSRafael Auler uint64_t NumUnused = 0; 412*a34c753fSRafael Auler for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) { 413*a34c753fSRafael Auler if (YamlBF.Id >= YamlProfileToFunction.size()) { 414*a34c753fSRafael Auler // Such profile was ignored. 415*a34c753fSRafael Auler ++NumUnused; 416*a34c753fSRafael Auler continue; 417*a34c753fSRafael Auler } 418*a34c753fSRafael Auler if (BinaryFunction *BF = YamlProfileToFunction[YamlBF.Id]) { 419*a34c753fSRafael Auler parseFunctionProfile(*BF, YamlBF); 420*a34c753fSRafael Auler } else { 421*a34c753fSRafael Auler ++NumUnused; 422*a34c753fSRafael Auler } 423*a34c753fSRafael Auler } 424*a34c753fSRafael Auler 425*a34c753fSRafael Auler BC.setNumUnusedProfiledObjects(NumUnused); 426*a34c753fSRafael Auler 427*a34c753fSRafael Auler return Error::success(); 428*a34c753fSRafael Auler } 429*a34c753fSRafael Auler 430*a34c753fSRafael Auler bool YAMLProfileReader::usesEvent(StringRef Name) const { 431*a34c753fSRafael Auler return YamlBP.Header.EventNames.find(std::string(Name)) != StringRef::npos; 432*a34c753fSRafael Auler } 433*a34c753fSRafael Auler 434*a34c753fSRafael Auler } // end namespace bolt 435*a34c753fSRafael Auler } // end namespace llvm 436