llvm-project
643 строки · 22.5 Кб
1//===- bolt/Profile/YAMLProfileReader.cpp - YAML profile de-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/YAMLProfileReader.h"10#include "bolt/Core/BinaryBasicBlock.h"11#include "bolt/Core/BinaryFunction.h"12#include "bolt/Passes/MCF.h"13#include "bolt/Profile/ProfileYAMLMapping.h"14#include "bolt/Utils/NameResolver.h"15#include "bolt/Utils/Utils.h"16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/edit_distance.h"18#include "llvm/Demangle/Demangle.h"19#include "llvm/Support/CommandLine.h"20
21using namespace llvm;22
23namespace opts {24
25extern cl::opt<unsigned> Verbosity;26extern cl::OptionCategory BoltOptCategory;27extern cl::opt<bool> InferStaleProfile;28extern cl::opt<bool> Lite;29
30cl::opt<unsigned> NameSimilarityFunctionMatchingThreshold(31"name-similarity-function-matching-threshold",32cl::desc("Match functions using namespace and edit distance"), cl::init(0),33cl::Hidden, cl::cat(BoltOptCategory));34
35static llvm::cl::opt<bool>36IgnoreHash("profile-ignore-hash",37cl::desc("ignore hash while reading function profile"),38cl::Hidden, cl::cat(BoltOptCategory));39
40llvm::cl::opt<bool>41MatchProfileWithFunctionHash("match-profile-with-function-hash",42cl::desc("Match profile with function hash"),43cl::Hidden, cl::cat(BoltOptCategory));44
45llvm::cl::opt<bool> ProfileUseDFS("profile-use-dfs",46cl::desc("use DFS order for YAML profile"),47cl::Hidden, cl::cat(BoltOptCategory));48} // namespace opts49
50namespace llvm {51namespace bolt {52
53bool YAMLProfileReader::isYAML(const StringRef Filename) {54if (auto MB = MemoryBuffer::getFileOrSTDIN(Filename)) {55StringRef Buffer = (*MB)->getBuffer();56return Buffer.starts_with("---\n");57} else {58report_error(Filename, MB.getError());59}60return false;61}
62
63void YAMLProfileReader::buildNameMaps(BinaryContext &BC) {64auto lookupFunction = [&](StringRef Name) -> BinaryFunction * {65if (BinaryData *BD = BC.getBinaryDataByName(Name))66return BC.getFunctionForSymbol(BD->getSymbol());67return nullptr;68};69
70ProfileBFs.reserve(YamlBP.Functions.size());71
72for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) {73StringRef Name = YamlBF.Name;74const size_t Pos = Name.find("(*");75if (Pos != StringRef::npos)76Name = Name.substr(0, Pos);77ProfileFunctionNames.insert(Name);78ProfileBFs.push_back(lookupFunction(Name));79if (const std::optional<StringRef> CommonName = getLTOCommonName(Name))80LTOCommonNameMap[*CommonName].push_back(&YamlBF);81}82for (auto &[Symbol, BF] : BC.SymbolToFunctionMap) {83StringRef Name = Symbol->getName();84if (const std::optional<StringRef> CommonName = getLTOCommonName(Name))85LTOCommonNameFunctionMap[*CommonName].insert(BF);86}87}
88
89bool YAMLProfileReader::hasLocalsWithFileName() const {90return llvm::any_of(ProfileFunctionNames.keys(), [](StringRef FuncName) {91return FuncName.count('/') == 2 && FuncName[0] != '/';92});93}
94
95bool YAMLProfileReader::parseFunctionProfile(96BinaryFunction &BF, const yaml::bolt::BinaryFunctionProfile &YamlBF) {97BinaryContext &BC = BF.getBinaryContext();98
99const bool IsDFSOrder = YamlBP.Header.IsDFSOrder;100const HashFunction HashFunction = YamlBP.Header.HashFunction;101bool ProfileMatched = true;102uint64_t MismatchedBlocks = 0;103uint64_t MismatchedCalls = 0;104uint64_t MismatchedEdges = 0;105
106uint64_t FunctionExecutionCount = 0;107
108BF.setExecutionCount(YamlBF.ExecCount);109
110uint64_t FuncRawBranchCount = 0;111for (const yaml::bolt::BinaryBasicBlockProfile &YamlBB : YamlBF.Blocks)112for (const yaml::bolt::SuccessorInfo &YamlSI : YamlBB.Successors)113FuncRawBranchCount += YamlSI.Count;114BF.setRawBranchCount(FuncRawBranchCount);115
116if (BF.empty())117return true;118
119if (!opts::IgnoreHash) {120if (!BF.getHash())121BF.computeHash(IsDFSOrder, HashFunction);122if (YamlBF.Hash != BF.getHash()) {123if (opts::Verbosity >= 1)124errs() << "BOLT-WARNING: function hash mismatch\n";125ProfileMatched = false;126}127}128
129if (YamlBF.NumBasicBlocks != BF.size()) {130if (opts::Verbosity >= 1)131errs() << "BOLT-WARNING: number of basic blocks mismatch\n";132ProfileMatched = false;133}134
135BinaryFunction::BasicBlockOrderType Order;136if (IsDFSOrder)137llvm::copy(BF.dfs(), std::back_inserter(Order));138else139llvm::copy(BF.getLayout().blocks(), std::back_inserter(Order));140
141for (const yaml::bolt::BinaryBasicBlockProfile &YamlBB : YamlBF.Blocks) {142if (YamlBB.Index >= Order.size()) {143if (opts::Verbosity >= 2)144errs() << "BOLT-WARNING: index " << YamlBB.Index145<< " is out of bounds\n";146++MismatchedBlocks;147continue;148}149
150BinaryBasicBlock &BB = *Order[YamlBB.Index];151
152// Basic samples profile (without LBR) does not have branches information153// and needs a special processing.154if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE) {155if (!YamlBB.EventCount) {156BB.setExecutionCount(0);157continue;158}159uint64_t NumSamples = YamlBB.EventCount * 1000;160if (NormalizeByInsnCount && BB.getNumNonPseudos())161NumSamples /= BB.getNumNonPseudos();162else if (NormalizeByCalls)163NumSamples /= BB.getNumCalls() + 1;164
165BB.setExecutionCount(NumSamples);166if (BB.isEntryPoint())167FunctionExecutionCount += NumSamples;168continue;169}170
171BB.setExecutionCount(YamlBB.ExecCount);172
173for (const yaml::bolt::CallSiteInfo &YamlCSI : YamlBB.CallSites) {174BinaryFunction *Callee = YamlCSI.DestId < YamlProfileToFunction.size()175? YamlProfileToFunction[YamlCSI.DestId]176: nullptr;177bool IsFunction = Callee ? true : false;178MCSymbol *CalleeSymbol = nullptr;179if (IsFunction)180CalleeSymbol = Callee->getSymbolForEntryID(YamlCSI.EntryDiscriminator);181
182BF.getAllCallSites().emplace_back(CalleeSymbol, YamlCSI.Count,183YamlCSI.Mispreds, YamlCSI.Offset);184
185if (YamlCSI.Offset >= BB.getOriginalSize()) {186if (opts::Verbosity >= 2)187errs() << "BOLT-WARNING: offset " << YamlCSI.Offset188<< " out of bounds in block " << BB.getName() << '\n';189++MismatchedCalls;190continue;191}192
193MCInst *Instr =194BF.getInstructionAtOffset(BB.getInputOffset() + YamlCSI.Offset);195if (!Instr) {196if (opts::Verbosity >= 2)197errs() << "BOLT-WARNING: no instruction at offset " << YamlCSI.Offset198<< " in block " << BB.getName() << '\n';199++MismatchedCalls;200continue;201}202if (!BC.MIB->isCall(*Instr) && !BC.MIB->isIndirectBranch(*Instr)) {203if (opts::Verbosity >= 2)204errs() << "BOLT-WARNING: expected call at offset " << YamlCSI.Offset205<< " in block " << BB.getName() << '\n';206++MismatchedCalls;207continue;208}209
210auto setAnnotation = [&](StringRef Name, uint64_t Count) {211if (BC.MIB->hasAnnotation(*Instr, Name)) {212if (opts::Verbosity >= 1)213errs() << "BOLT-WARNING: ignoring duplicate " << Name214<< " info for offset 0x" << Twine::utohexstr(YamlCSI.Offset)215<< " in function " << BF << '\n';216return;217}218BC.MIB->addAnnotation(*Instr, Name, Count);219};220
221if (BC.MIB->isIndirectCall(*Instr) || BC.MIB->isIndirectBranch(*Instr)) {222auto &CSP = BC.MIB->getOrCreateAnnotationAs<IndirectCallSiteProfile>(223*Instr, "CallProfile");224CSP.emplace_back(CalleeSymbol, YamlCSI.Count, YamlCSI.Mispreds);225} else if (BC.MIB->getConditionalTailCall(*Instr)) {226setAnnotation("CTCTakenCount", YamlCSI.Count);227setAnnotation("CTCMispredCount", YamlCSI.Mispreds);228} else {229setAnnotation("Count", YamlCSI.Count);230}231}232
233for (const yaml::bolt::SuccessorInfo &YamlSI : YamlBB.Successors) {234if (YamlSI.Index >= Order.size()) {235if (opts::Verbosity >= 1)236errs() << "BOLT-WARNING: index out of bounds for profiled block\n";237++MismatchedEdges;238continue;239}240
241BinaryBasicBlock *ToBB = Order[YamlSI.Index];242if (!BB.getSuccessor(ToBB->getLabel())) {243// Allow passthrough blocks.244BinaryBasicBlock *FTSuccessor = BB.getConditionalSuccessor(false);245if (FTSuccessor && FTSuccessor->succ_size() == 1 &&246FTSuccessor->getSuccessor(ToBB->getLabel())) {247BinaryBasicBlock::BinaryBranchInfo &FTBI =248FTSuccessor->getBranchInfo(*ToBB);249FTBI.Count += YamlSI.Count;250FTBI.MispredictedCount += YamlSI.Mispreds;251ToBB = FTSuccessor;252} else {253if (opts::Verbosity >= 1)254errs() << "BOLT-WARNING: no successor for block " << BB.getName()255<< " that matches index " << YamlSI.Index << " or block "256<< ToBB->getName() << '\n';257++MismatchedEdges;258continue;259}260}261
262BinaryBasicBlock::BinaryBranchInfo &BI = BB.getBranchInfo(*ToBB);263BI.Count += YamlSI.Count;264BI.MispredictedCount += YamlSI.Mispreds;265}266}267
268// If basic block profile wasn't read it should be 0.269for (BinaryBasicBlock &BB : BF)270if (BB.getExecutionCount() == BinaryBasicBlock::COUNT_NO_PROFILE)271BB.setExecutionCount(0);272
273if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE)274BF.setExecutionCount(FunctionExecutionCount);275
276ProfileMatched &= !MismatchedBlocks && !MismatchedCalls && !MismatchedEdges;277
278if (!ProfileMatched) {279if (opts::Verbosity >= 1)280errs() << "BOLT-WARNING: " << MismatchedBlocks << " blocks, "281<< MismatchedCalls << " calls, and " << MismatchedEdges282<< " edges in profile did not match function " << BF << '\n';283
284if (YamlBF.NumBasicBlocks != BF.size())285++BC.Stats.NumStaleFuncsWithEqualBlockCount;286
287if (opts::InferStaleProfile && inferStaleProfile(BF, YamlBF))288ProfileMatched = true;289}290if (ProfileMatched)291BF.markProfiled(YamlBP.Header.Flags);292
293return ProfileMatched;294}
295
296Error YAMLProfileReader::preprocessProfile(BinaryContext &BC) {297ErrorOr<std::unique_ptr<MemoryBuffer>> MB =298MemoryBuffer::getFileOrSTDIN(Filename);299if (std::error_code EC = MB.getError()) {300errs() << "ERROR: cannot open " << Filename << ": " << EC.message() << "\n";301return errorCodeToError(EC);302}303yaml::Input YamlInput(MB.get()->getBuffer());304
305// Consume YAML file.306YamlInput >> YamlBP;307if (YamlInput.error()) {308errs() << "BOLT-ERROR: syntax error parsing profile in " << Filename309<< " : " << YamlInput.error().message() << '\n';310return errorCodeToError(YamlInput.error());311}312
313// Sanity check.314if (YamlBP.Header.Version != 1)315return make_error<StringError>(316Twine("cannot read profile : unsupported version"),317inconvertibleErrorCode());318
319if (YamlBP.Header.EventNames.find(',') != StringRef::npos)320return make_error<StringError>(321Twine("multiple events in profile are not supported"),322inconvertibleErrorCode());323
324// Match profile to function based on a function name.325buildNameMaps(BC);326
327// Preliminary assign function execution count.328for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs)) {329if (!BF)330continue;331if (!BF->hasProfile()) {332BF->setExecutionCount(YamlBF.ExecCount);333} else {334if (opts::Verbosity >= 1) {335errs() << "BOLT-WARNING: dropping duplicate profile for " << YamlBF.Name336<< '\n';337}338BF = nullptr;339}340}341
342return Error::success();343}
344
345bool YAMLProfileReader::profileMatches(346const yaml::bolt::BinaryFunctionProfile &Profile, const BinaryFunction &BF) {347if (opts::IgnoreHash)348return Profile.NumBasicBlocks == BF.size();349return Profile.Hash == static_cast<uint64_t>(BF.getHash());350}
351
352bool YAMLProfileReader::mayHaveProfileData(const BinaryFunction &BF) {353if (opts::MatchProfileWithFunctionHash)354return true;355for (StringRef Name : BF.getNames())356if (ProfileFunctionNames.contains(Name))357return true;358for (StringRef Name : BF.getNames()) {359if (const std::optional<StringRef> CommonName = getLTOCommonName(Name)) {360if (LTOCommonNameMap.contains(*CommonName))361return true;362}363}364
365return false;366}
367
368size_t YAMLProfileReader::matchWithExactName() {369size_t MatchedWithExactName = 0;370// This first pass assigns profiles that match 100% by name and by hash.371for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs)) {372if (!BF)373continue;374BinaryFunction &Function = *BF;375// Clear function call count that may have been set while pre-processing376// the profile.377Function.setExecutionCount(BinaryFunction::COUNT_NO_PROFILE);378
379if (profileMatches(YamlBF, Function)) {380matchProfileToFunction(YamlBF, Function);381++MatchedWithExactName;382}383}384return MatchedWithExactName;385}
386
387size_t YAMLProfileReader::matchWithHash(BinaryContext &BC) {388// Iterates through profiled functions to match the first binary function with389// the same exact hash. Serves to match identical, renamed functions.390// Collisions are possible where multiple functions share the same exact hash.391size_t MatchedWithHash = 0;392if (opts::MatchProfileWithFunctionHash) {393DenseMap<size_t, BinaryFunction *> StrictHashToBF;394StrictHashToBF.reserve(BC.getBinaryFunctions().size());395
396for (auto &[_, BF] : BC.getBinaryFunctions())397StrictHashToBF[BF.getHash()] = &BF;398
399for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) {400if (YamlBF.Used)401continue;402auto It = StrictHashToBF.find(YamlBF.Hash);403if (It != StrictHashToBF.end() && !ProfiledFunctions.count(It->second)) {404BinaryFunction *BF = It->second;405matchProfileToFunction(YamlBF, *BF);406++MatchedWithHash;407}408}409}410return MatchedWithHash;411}
412
413size_t YAMLProfileReader::matchWithLTOCommonName() {414// This second pass allows name ambiguity for LTO private functions.415size_t MatchedWithLTOCommonName = 0;416for (const auto &[CommonName, LTOProfiles] : LTOCommonNameMap) {417if (!LTOCommonNameFunctionMap.contains(CommonName))418continue;419std::unordered_set<BinaryFunction *> &Functions =420LTOCommonNameFunctionMap[CommonName];421// Return true if a given profile is matched to one of BinaryFunctions with422// matching LTO common name.423auto matchProfile = [&](yaml::bolt::BinaryFunctionProfile *YamlBF) {424if (YamlBF->Used)425return false;426for (BinaryFunction *BF : Functions) {427if (!ProfiledFunctions.count(BF) && profileMatches(*YamlBF, *BF)) {428matchProfileToFunction(*YamlBF, *BF);429++MatchedWithLTOCommonName;430return true;431}432}433return false;434};435bool ProfileMatched = llvm::any_of(LTOProfiles, matchProfile);436
437// If there's only one function with a given name, try to match it438// partially.439if (!ProfileMatched && LTOProfiles.size() == 1 && Functions.size() == 1 &&440!LTOProfiles.front()->Used &&441!ProfiledFunctions.count(*Functions.begin())) {442matchProfileToFunction(*LTOProfiles.front(), **Functions.begin());443++MatchedWithLTOCommonName;444}445}446return MatchedWithLTOCommonName;447}
448
449size_t YAMLProfileReader::matchWithNameSimilarity(BinaryContext &BC) {450if (opts::NameSimilarityFunctionMatchingThreshold == 0)451return 0;452
453size_t MatchedWithNameSimilarity = 0;454ItaniumPartialDemangler Demangler;455
456// Demangle and derive namespace from function name.457auto DemangleName = [&](std::string &FunctionName) {458StringRef RestoredName = NameResolver::restore(FunctionName);459return demangle(RestoredName);460};461auto DeriveNameSpace = [&](std::string &DemangledName) {462if (Demangler.partialDemangle(DemangledName.c_str()))463return std::string("");464std::vector<char> Buffer(DemangledName.begin(), DemangledName.end());465size_t BufferSize;466char *NameSpace =467Demangler.getFunctionDeclContextName(&Buffer[0], &BufferSize);468return std::string(NameSpace, BufferSize);469};470
471// Maps namespaces to associated function block counts and gets profile472// function names and namespaces to minimize the number of BFs to process and473// avoid repeated name demangling/namespace derivation.474StringMap<std::set<uint32_t>> NamespaceToProfiledBFSizes;475std::vector<std::string> ProfileBFDemangledNames;476ProfileBFDemangledNames.reserve(YamlBP.Functions.size());477std::vector<std::string> ProfiledBFNamespaces;478ProfiledBFNamespaces.reserve(YamlBP.Functions.size());479
480for (auto &YamlBF : YamlBP.Functions) {481std::string YamlBFDemangledName = DemangleName(YamlBF.Name);482ProfileBFDemangledNames.push_back(YamlBFDemangledName);483std::string YamlBFNamespace = DeriveNameSpace(YamlBFDemangledName);484ProfiledBFNamespaces.push_back(YamlBFNamespace);485NamespaceToProfiledBFSizes[YamlBFNamespace].insert(YamlBF.NumBasicBlocks);486}487
488StringMap<std::vector<BinaryFunction *>> NamespaceToBFs;489
490// Maps namespaces to BFs excluding binary functions with no equal sized491// profiled functions belonging to the same namespace.492for (BinaryFunction *BF : BC.getAllBinaryFunctions()) {493std::string DemangledName = BF->getDemangledName();494std::string Namespace = DeriveNameSpace(DemangledName);495
496auto NamespaceToProfiledBFSizesIt =497NamespaceToProfiledBFSizes.find(Namespace);498// Skip if there are no ProfileBFs with a given \p Namespace.499if (NamespaceToProfiledBFSizesIt == NamespaceToProfiledBFSizes.end())500continue;501// Skip if there are no ProfileBFs in a given \p Namespace with502// equal number of blocks.503if (NamespaceToProfiledBFSizesIt->second.count(BF->size()) == 0)504continue;505auto NamespaceToBFsIt = NamespaceToBFs.find(Namespace);506if (NamespaceToBFsIt == NamespaceToBFs.end())507NamespaceToBFs[Namespace] = {BF};508else509NamespaceToBFsIt->second.push_back(BF);510}511
512// Iterates through all profiled functions and binary functions belonging to513// the same namespace and matches based on edit distance threshold.514assert(YamlBP.Functions.size() == ProfiledBFNamespaces.size() &&515ProfiledBFNamespaces.size() == ProfileBFDemangledNames.size());516for (size_t I = 0; I < YamlBP.Functions.size(); ++I) {517yaml::bolt::BinaryFunctionProfile &YamlBF = YamlBP.Functions[I];518std::string &YamlBFNamespace = ProfiledBFNamespaces[I];519if (YamlBF.Used)520continue;521// Skip if there are no BFs in a given \p Namespace.522auto It = NamespaceToBFs.find(YamlBFNamespace);523if (It == NamespaceToBFs.end())524continue;525
526std::string &YamlBFDemangledName = ProfileBFDemangledNames[I];527std::vector<BinaryFunction *> BFs = It->second;528unsigned MinEditDistance = UINT_MAX;529BinaryFunction *ClosestNameBF = nullptr;530
531// Determines BF the closest to the profiled function, in the532// same namespace.533for (BinaryFunction *BF : BFs) {534if (ProfiledFunctions.count(BF))535continue;536if (BF->size() != YamlBF.NumBasicBlocks)537continue;538std::string BFDemangledName = BF->getDemangledName();539unsigned BFEditDistance =540StringRef(BFDemangledName).edit_distance(YamlBFDemangledName);541if (BFEditDistance < MinEditDistance) {542MinEditDistance = BFEditDistance;543ClosestNameBF = BF;544}545}546
547if (ClosestNameBF &&548MinEditDistance <= opts::NameSimilarityFunctionMatchingThreshold) {549matchProfileToFunction(YamlBF, *ClosestNameBF);550++MatchedWithNameSimilarity;551}552}553
554return MatchedWithNameSimilarity;555}
556
557Error YAMLProfileReader::readProfile(BinaryContext &BC) {558if (opts::Verbosity >= 1) {559outs() << "BOLT-INFO: YAML profile with hash: ";560switch (YamlBP.Header.HashFunction) {561case HashFunction::StdHash:562outs() << "std::hash\n";563break;564case HashFunction::XXH3:565outs() << "xxh3\n";566break;567}568}569YamlProfileToFunction.resize(YamlBP.Functions.size() + 1);570
571// Computes hash for binary functions.572if (opts::MatchProfileWithFunctionHash) {573for (auto &[_, BF] : BC.getBinaryFunctions()) {574BF.computeHash(YamlBP.Header.IsDFSOrder, YamlBP.Header.HashFunction);575}576} else if (!opts::IgnoreHash) {577for (BinaryFunction *BF : ProfileBFs) {578if (!BF)579continue;580BF->computeHash(YamlBP.Header.IsDFSOrder, YamlBP.Header.HashFunction);581}582}583
584const size_t MatchedWithExactName = matchWithExactName();585const size_t MatchedWithHash = matchWithHash(BC);586const size_t MatchedWithLTOCommonName = matchWithLTOCommonName();587const size_t MatchedWithNameSimilarity = matchWithNameSimilarity(BC);588
589for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs))590if (!YamlBF.Used && BF && !ProfiledFunctions.count(BF))591matchProfileToFunction(YamlBF, *BF);592
593
594for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions)595if (!YamlBF.Used && opts::Verbosity >= 1)596errs() << "BOLT-WARNING: profile ignored for function " << YamlBF.Name597<< '\n';598
599if (opts::Verbosity >= 1) {600outs() << "BOLT-INFO: matched " << MatchedWithExactName601<< " functions with identical names\n";602outs() << "BOLT-INFO: matched " << MatchedWithHash603<< " functions with hash\n";604outs() << "BOLT-INFO: matched " << MatchedWithLTOCommonName605<< " functions with matching LTO common names\n";606outs() << "BOLT-INFO: matched " << MatchedWithNameSimilarity607<< " functions with similar names\n";608}609
610// Set for parseFunctionProfile().611NormalizeByInsnCount = usesEvent("cycles") || usesEvent("instructions");612NormalizeByCalls = usesEvent("branches");613
614uint64_t NumUnused = 0;615for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) {616if (YamlBF.Id >= YamlProfileToFunction.size()) {617// Such profile was ignored.618++NumUnused;619continue;620}621if (BinaryFunction *BF = YamlProfileToFunction[YamlBF.Id])622parseFunctionProfile(*BF, YamlBF);623else624++NumUnused;625}626
627BC.setNumUnusedProfiledObjects(NumUnused);628
629if (opts::Lite && opts::MatchProfileWithFunctionHash) {630for (BinaryFunction *BF : BC.getAllBinaryFunctions())631if (!BF->hasProfile())632BF->setIgnored();633}634
635return Error::success();636}
637
638bool YAMLProfileReader::usesEvent(StringRef Name) const {639return YamlBP.Header.EventNames.find(std::string(Name)) != StringRef::npos;640}
641
642} // end namespace bolt643} // end namespace llvm644