diff --git a/bolt/include/bolt/Profile/YAMLProfileReader.h b/bolt/include/bolt/Profile/YAMLProfileReader.h --- a/bolt/include/bolt/Profile/YAMLProfileReader.h +++ b/bolt/include/bolt/Profile/YAMLProfileReader.h @@ -61,10 +61,13 @@ StringMap> LTOCommonNameMap; /// Map a common LTO prefix to a set of binary functions. - StringMap LTOCommonNameFunctionMap; + StringMap> LTOCommonNameFunctionMap; - /// Strict matching of a name in a profile to its contents. - StringMap ProfileNameToProfile; + /// Function names in profile. + StringSet<> ProfileFunctionNames; + + /// BinaryFunction pointers indexed by YamlBP functions. + std::vector ProfileBFs; /// Populate \p Function profile with the one supplied in YAML format. bool parseFunctionProfile(BinaryFunction &Function, @@ -75,7 +78,7 @@ const yaml::bolt::BinaryFunctionProfile &YamlBF); /// Initialize maps for profile matching. - void buildNameMaps(std::map &Functions); + void buildNameMaps(BinaryContext &BC); /// Update matched YAML -> BinaryFunction pair. void matchProfileToFunction(yaml::bolt::BinaryFunctionProfile &YamlBF, diff --git a/bolt/lib/Profile/YAMLProfileReader.cpp b/bolt/lib/Profile/YAMLProfileReader.cpp --- a/bolt/lib/Profile/YAMLProfileReader.cpp +++ b/bolt/lib/Profile/YAMLProfileReader.cpp @@ -12,6 +12,7 @@ #include "bolt/Passes/MCF.h" #include "bolt/Profile/ProfileYAMLMapping.h" #include "bolt/Utils/Utils.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/CommandLine.h" using namespace llvm; @@ -45,27 +46,34 @@ return false; } -void YAMLProfileReader::buildNameMaps( - std::map &Functions) { +void YAMLProfileReader::buildNameMaps(BinaryContext &BC) { + auto lookupFunction = [&](StringRef Name) -> BinaryFunction * { + if (BinaryData *BD = BC.getBinaryDataByName(Name)) + return BC.getFunctionForSymbol(BD->getSymbol()); + return nullptr; + }; + + ProfileBFs.reserve(YamlBP.Functions.size()); + for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) { StringRef Name = YamlBF.Name; const size_t Pos = Name.find("(*"); if (Pos != StringRef::npos) Name = Name.substr(0, Pos); - ProfileNameToProfile[Name] = &YamlBF; + ProfileFunctionNames.insert(Name); + ProfileBFs.push_back(lookupFunction(Name)); if (const std::optional CommonName = getLTOCommonName(Name)) LTOCommonNameMap[*CommonName].push_back(&YamlBF); } - for (auto &BFI : Functions) { - const BinaryFunction &Function = BFI.second; - for (StringRef Name : Function.getNames()) - if (const std::optional CommonName = getLTOCommonName(Name)) - LTOCommonNameFunctionMap[*CommonName].insert(&Function); + for (auto &[Symbol, BF] : BC.SymbolToFunctionMap) { + StringRef Name = Symbol->getName(); + if (const std::optional CommonName = getLTOCommonName(Name)) + LTOCommonNameFunctionMap[*CommonName].insert(BF); } } bool YAMLProfileReader::hasLocalsWithFileName() const { - return llvm::any_of(ProfileNameToProfile.keys(), [](StringRef FuncName) { + return llvm::any_of(ProfileFunctionNames.keys(), [](StringRef FuncName) { return FuncName.count('/') == 2 && FuncName[0] != '/'; }); } @@ -283,28 +291,21 @@ inconvertibleErrorCode()); // Match profile to function based on a function name. - buildNameMaps(BC.getBinaryFunctions()); + buildNameMaps(BC); // Preliminary assign function execution count. - for (auto &KV : BC.getBinaryFunctions()) { - BinaryFunction &BF = KV.second; - for (StringRef Name : BF.getNames()) { - auto PI = ProfileNameToProfile.find(Name); - if (PI != ProfileNameToProfile.end()) { - yaml::bolt::BinaryFunctionProfile &YamlBF = *PI->getValue(); - BF.setExecutionCount(YamlBF.ExecCount); - break; - } - } - } + for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs)) + if (BF) + BF->setExecutionCount(YamlBF.ExecCount); return Error::success(); } bool YAMLProfileReader::mayHaveProfileData(const BinaryFunction &BF) { - for (StringRef Name : BF.getNames()) { - if (ProfileNameToProfile.contains(Name)) + for (StringRef Name : BF.getNames()) + if (ProfileFunctionNames.contains(Name)) return true; + for (StringRef Name : BF.getNames()) { if (const std::optional CommonName = getLTOCommonName(Name)) { if (LTOCommonNameMap.contains(*CommonName)) return true; @@ -327,9 +328,10 @@ // We have to do 2 passes since LTO introduces an ambiguity in function // names. The first pass assigns profiles that match 100% by name and // by hash. The second pass allows name ambiguity for LTO private functions. - for (auto &BFI : BC.getBinaryFunctions()) { - BinaryFunction &Function = BFI.second; - + for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs)) { + if (!BF) + continue; + BinaryFunction &Function = *BF; // Clear function call count that may have been set while pre-processing // the profile. Function.setExecutionCount(BinaryFunction::COUNT_NO_PROFILE); @@ -338,69 +340,42 @@ if (!opts::IgnoreHash) Function.computeHash(YamlBP.Header.IsDFSOrder); - for (StringRef FunctionName : Function.getNames()) { - auto PI = ProfileNameToProfile.find(FunctionName); - if (PI == ProfileNameToProfile.end()) - continue; - - yaml::bolt::BinaryFunctionProfile &YamlBF = *PI->getValue(); - if (profileMatches(YamlBF, Function)) { - matchProfileToFunction(YamlBF, Function); - break; - } - } + if (profileMatches(YamlBF, Function)) + matchProfileToFunction(YamlBF, Function); } - for (auto &BFI : BC.getBinaryFunctions()) { - BinaryFunction &Function = BFI.second; - - if (ProfiledFunctions.count(&Function)) + for (auto &[CommonName, LTOProfiles]: LTOCommonNameMap) { + if (!LTOCommonNameFunctionMap.contains(CommonName)) continue; - - for (StringRef FunctionName : Function.getNames()) { - const std::optional CommonName = - getLTOCommonName(FunctionName); - if (CommonName) { - auto I = LTOCommonNameMap.find(*CommonName); - if (I == LTOCommonNameMap.end()) - continue; - - bool ProfileMatched = false; - std::vector <OProfiles = - I->getValue(); - for (yaml::bolt::BinaryFunctionProfile *YamlBF : LTOProfiles) { - if (YamlBF->Used) - continue; - if ((ProfileMatched = profileMatches(*YamlBF, Function))) { - matchProfileToFunction(*YamlBF, Function); - break; - } - } - if (ProfileMatched) - break; - - // If there's only one function with a given name, try to - // match it partially. - if (LTOProfiles.size() == 1 && - LTOCommonNameFunctionMap[*CommonName].size() == 1 && - !LTOProfiles.front()->Used) { - matchProfileToFunction(*LTOProfiles.front(), Function); - break; - } - } else { - auto PI = ProfileNameToProfile.find(FunctionName); - if (PI == ProfileNameToProfile.end()) - continue; - - yaml::bolt::BinaryFunctionProfile &YamlBF = *PI->getValue(); - if (!YamlBF.Used) { - matchProfileToFunction(YamlBF, Function); - break; + std::unordered_set &Functions = + LTOCommonNameFunctionMap[CommonName]; + // Return true if a given profile is matched to one of BinaryFunctions with + // matching LTO common name. + auto matchProfile = [&](yaml::bolt::BinaryFunctionProfile *YamlBF) { + if (YamlBF->Used) + return false; + for (BinaryFunction *BF : Functions) { + if (!ProfiledFunctions.count(BF) && profileMatches(*YamlBF, *BF)) { + matchProfileToFunction(*YamlBF, *BF); + return true; } } - } + return false; + }; + bool ProfileMatched = llvm::any_of(LTOProfiles, matchProfile); + + // If there's only one function with a given name, try to match it + // partially. + if (!ProfileMatched && LTOProfiles.size() == 1 && Functions.size() == 1 && + !LTOProfiles.front()->Used && + !ProfiledFunctions.count(*Functions.begin())) + matchProfileToFunction(*LTOProfiles.front(), **Functions.begin()); } + for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs)) + if (!YamlBF.Used && BF && !ProfiledFunctions.count(BF)) + matchProfileToFunction(YamlBF, *BF); + for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) if (!YamlBF.Used && opts::Verbosity >= 1) errs() << "BOLT-WARNING: profile ignored for function " << YamlBF.Name