@@ -22,12 +22,18 @@ namespace opts {
2222extern cl::opt<unsigned > Verbosity;
2323extern cl::OptionCategory BoltOptCategory;
2424extern cl::opt<bool > InferStaleProfile;
25+ extern cl::opt<bool > Lite;
2526
2627static llvm::cl::opt<bool >
2728 IgnoreHash (" profile-ignore-hash" ,
2829 cl::desc (" ignore hash while reading function profile" ),
2930 cl::Hidden, cl::cat(BoltOptCategory));
3031
32+ llvm::cl::opt<bool >
33+ MatchProfileWithFunctionHash (" match-profile-with-function-hash" ,
34+ cl::desc (" Match profile with function hash" ),
35+ cl::Hidden, cl::cat(BoltOptCategory));
36+
3137llvm::cl::opt<bool > ProfileUseDFS (" profile-use-dfs" ,
3238 cl::desc (" use DFS order for YAML profile" ),
3339 cl::Hidden, cl::cat(BoltOptCategory));
@@ -329,6 +335,8 @@ Error YAMLProfileReader::preprocessProfile(BinaryContext &BC) {
329335}
330336
331337bool YAMLProfileReader::mayHaveProfileData (const BinaryFunction &BF) {
338+ if (opts::MatchProfileWithFunctionHash)
339+ return true ;
332340 for (StringRef Name : BF.getNames ())
333341 if (ProfileFunctionNames.contains (Name))
334342 return true ;
@@ -363,9 +371,24 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
363371 return Profile.Hash == static_cast <uint64_t >(BF.getHash ());
364372 };
365373
366- // We have to do 2 passes since LTO introduces an ambiguity in function
367- // names. The first pass assigns profiles that match 100% by name and
368- // by hash. The second pass allows name ambiguity for LTO private functions.
374+ uint64_t MatchedWithExactName = 0 ;
375+ uint64_t MatchedWithHash = 0 ;
376+ uint64_t MatchedWithLTOCommonName = 0 ;
377+
378+ // Computes hash for binary functions.
379+ if (opts::MatchProfileWithFunctionHash) {
380+ for (auto &[_, BF] : BC.getBinaryFunctions ()) {
381+ BF.computeHash (YamlBP.Header .IsDFSOrder , YamlBP.Header .HashFunction );
382+ }
383+ } else if (!opts::IgnoreHash) {
384+ for (BinaryFunction *BF : ProfileBFs) {
385+ if (!BF)
386+ continue ;
387+ BF->computeHash (YamlBP.Header .IsDFSOrder , YamlBP.Header .HashFunction );
388+ }
389+ }
390+
391+ // This first pass assigns profiles that match 100% by name and by hash.
369392 for (auto [YamlBF, BF] : llvm::zip_equal (YamlBP.Functions , ProfileBFs)) {
370393 if (!BF)
371394 continue ;
@@ -374,15 +397,35 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
374397 // the profile.
375398 Function.setExecutionCount (BinaryFunction::COUNT_NO_PROFILE);
376399
377- // Recompute hash once per function.
378- if (!opts::IgnoreHash)
379- Function.computeHash (YamlBP.Header .IsDFSOrder ,
380- YamlBP.Header .HashFunction );
381-
382- if (profileMatches (YamlBF, Function))
400+ if (profileMatches (YamlBF, Function)) {
383401 matchProfileToFunction (YamlBF, Function);
402+ ++MatchedWithExactName;
403+ }
384404 }
385405
406+ // Iterates through profiled functions to match the first binary function with
407+ // the same exact hash. Serves to match identical, renamed functions.
408+ // Collisions are possible where multiple functions share the same exact hash.
409+ if (opts::MatchProfileWithFunctionHash) {
410+ DenseMap<size_t , BinaryFunction *> StrictHashToBF;
411+ StrictHashToBF.reserve (BC.getBinaryFunctions ().size ());
412+
413+ for (auto &[_, BF] : BC.getBinaryFunctions ())
414+ StrictHashToBF[BF.getHash ()] = &BF;
415+
416+ for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions ) {
417+ if (YamlBF.Used )
418+ continue ;
419+ auto It = StrictHashToBF.find (YamlBF.Hash );
420+ if (It != StrictHashToBF.end () && !ProfiledFunctions.count (It->second )) {
421+ BinaryFunction *BF = It->second ;
422+ matchProfileToFunction (YamlBF, *BF);
423+ ++MatchedWithHash;
424+ }
425+ }
426+ }
427+
428+ // This second pass allows name ambiguity for LTO private functions.
386429 for (const auto &[CommonName, LTOProfiles] : LTOCommonNameMap) {
387430 if (!LTOCommonNameFunctionMap.contains (CommonName))
388431 continue ;
@@ -396,6 +439,7 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
396439 for (BinaryFunction *BF : Functions) {
397440 if (!ProfiledFunctions.count (BF) && profileMatches (*YamlBF, *BF)) {
398441 matchProfileToFunction (*YamlBF, *BF);
442+ ++MatchedWithLTOCommonName;
399443 return true ;
400444 }
401445 }
@@ -407,8 +451,10 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
407451 // partially.
408452 if (!ProfileMatched && LTOProfiles.size () == 1 && Functions.size () == 1 &&
409453 !LTOProfiles.front ()->Used &&
410- !ProfiledFunctions.count (*Functions.begin ()))
454+ !ProfiledFunctions.count (*Functions.begin ())) {
411455 matchProfileToFunction (*LTOProfiles.front (), **Functions.begin ());
456+ ++MatchedWithLTOCommonName;
457+ }
412458 }
413459
414460 for (auto [YamlBF, BF] : llvm::zip_equal (YamlBP.Functions , ProfileBFs))
@@ -420,6 +466,15 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
420466 errs () << " BOLT-WARNING: profile ignored for function " << YamlBF.Name
421467 << ' \n ' ;
422468
469+ if (opts::Verbosity >= 1 ) {
470+ outs () << " BOLT-INFO: matched " << MatchedWithExactName
471+ << " functions with identical names\n " ;
472+ outs () << " BOLT-INFO: matched " << MatchedWithHash
473+ << " functions with hash\n " ;
474+ outs () << " BOLT-INFO: matched " << MatchedWithLTOCommonName
475+ << " functions with matching LTO common names\n " ;
476+ }
477+
423478 // Set for parseFunctionProfile().
424479 NormalizeByInsnCount = usesEvent (" cycles" ) || usesEvent (" instructions" );
425480 NormalizeByCalls = usesEvent (" branches" );
@@ -439,6 +494,12 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
439494
440495 BC.setNumUnusedProfiledObjects (NumUnused);
441496
497+ if (opts::Lite && opts::MatchProfileWithFunctionHash) {
498+ for (BinaryFunction *BF : BC.getAllBinaryFunctions ())
499+ if (!BF->hasProfile ())
500+ BF->setIgnored ();
501+ }
502+
442503 return Error::success ();
443504}
444505
0 commit comments