@@ -41,6 +41,10 @@ llvm::cl::opt<bool>
41
41
MatchProfileWithFunctionHash (" match-profile-with-function-hash" ,
42
42
cl::desc (" Match profile with function hash" ),
43
43
cl::Hidden, cl::cat(BoltOptCategory));
44
+ llvm::cl::opt<bool >
45
+ MatchWithCallGraph (" match-with-call-graph" ,
46
+ cl::desc (" Match functions with call graph" ), cl::Hidden,
47
+ cl::cat(BoltOptCategory));
44
48
45
49
llvm::cl::opt<bool > ProfileUseDFS (" profile-use-dfs" ,
46
50
cl::desc (" use DFS order for YAML profile" ),
@@ -50,6 +54,69 @@ llvm::cl::opt<bool> ProfileUseDFS("profile-use-dfs",
50
54
namespace llvm {
51
55
namespace bolt {
52
56
57
+ YAMLProfileReader::CallGraphMatcher::CallGraphMatcher (
58
+ BinaryContext &BC, yaml::bolt::BinaryProfile &YamlBP,
59
+ ProfileLookupMap &IdToYAMLBF) {
60
+ constructBFCG (BC, YamlBP);
61
+ constructYAMLFCG (YamlBP, IdToYAMLBF);
62
+ computeBFNeighborHashes (BC);
63
+ }
64
+
65
+ void YAMLProfileReader::CallGraphMatcher::constructBFCG (
66
+ BinaryContext &BC, yaml::bolt::BinaryProfile &YamlBP) {
67
+ for (BinaryFunction *BF : BC.getAllBinaryFunctions ()) {
68
+ for (const BinaryBasicBlock &BB : BF->blocks ()) {
69
+ for (const MCInst &Instr : BB) {
70
+ if (!BC.MIB ->isCall (Instr))
71
+ continue ;
72
+ const MCSymbol *CallSymbol = BC.MIB ->getTargetSymbol (Instr);
73
+ if (!CallSymbol)
74
+ continue ;
75
+ BinaryData *BD = BC.getBinaryDataByName (CallSymbol->getName ());
76
+ if (!BD)
77
+ continue ;
78
+ BinaryFunction *CalleeBF = BC.getFunctionForSymbol (BD->getSymbol ());
79
+ if (!CalleeBF)
80
+ continue ;
81
+
82
+ BFAdjacencyMap[CalleeBF].insert (BF);
83
+ BFAdjacencyMap[BF].insert (CalleeBF);
84
+ }
85
+ }
86
+ }
87
+ }
88
+
89
+ void YAMLProfileReader::CallGraphMatcher::computeBFNeighborHashes (
90
+ BinaryContext &BC) {
91
+ for (BinaryFunction *BF : BC.getAllBinaryFunctions ()) {
92
+ auto It = BFAdjacencyMap.find (BF);
93
+ if (It == BFAdjacencyMap.end ())
94
+ continue ;
95
+ auto &AdjacentBFs = It->second ;
96
+ std::string HashStr;
97
+ for (BinaryFunction *BF : AdjacentBFs)
98
+ HashStr += BF->getOneName ();
99
+ uint64_t Hash = std::hash<std::string>{}(HashStr);
100
+ NeighborHashToBFs[Hash].push_back (BF);
101
+ }
102
+ }
103
+
104
+ void YAMLProfileReader::CallGraphMatcher::constructYAMLFCG (
105
+ yaml::bolt::BinaryProfile &YamlBP, ProfileLookupMap &IdToYAMLBF) {
106
+
107
+ for (auto &CallerYamlBF : YamlBP.Functions ) {
108
+ for (auto &YamlBB : CallerYamlBF.Blocks ) {
109
+ for (auto &CallSite : YamlBB.CallSites ) {
110
+ auto IdToYAMLBFIt = IdToYAMLBF.find (CallSite.DestId );
111
+ if (IdToYAMLBFIt == IdToYAMLBF.end ())
112
+ continue ;
113
+ YamlBFAdjacencyMap[&CallerYamlBF].insert (IdToYAMLBFIt->second );
114
+ YamlBFAdjacencyMap[IdToYAMLBFIt->second ].insert (&CallerYamlBF);
115
+ }
116
+ }
117
+ }
118
+ }
119
+
53
120
bool YAMLProfileReader::isYAML (const StringRef Filename) {
54
121
if (auto MB = MemoryBuffer::getFileOrSTDIN (Filename)) {
55
122
StringRef Buffer = (*MB)->getBuffer ();
@@ -350,7 +417,7 @@ bool YAMLProfileReader::profileMatches(
350
417
}
351
418
352
419
bool YAMLProfileReader::mayHaveProfileData (const BinaryFunction &BF) {
353
- if (opts::MatchProfileWithFunctionHash)
420
+ if (opts::MatchProfileWithFunctionHash || opts::MatchWithCallGraph )
354
421
return true ;
355
422
for (StringRef Name : BF.getNames ())
356
423
if (ProfileFunctionNames.contains (Name))
@@ -446,6 +513,79 @@ size_t YAMLProfileReader::matchWithLTOCommonName() {
446
513
return MatchedWithLTOCommonName;
447
514
}
448
515
516
+ size_t YAMLProfileReader::matchWithCallGraph (BinaryContext &BC) {
517
+ if (!opts::MatchWithCallGraph)
518
+ return 0 ;
519
+
520
+ size_t MatchedWithCallGraph = 0 ;
521
+ CallGraphMatcher CGMatcher (BC, YamlBP, IdToYamLBF);
522
+
523
+ ItaniumPartialDemangler Demangler;
524
+ auto GetBaseName = [&](std::string &FunctionName) {
525
+ if (Demangler.partialDemangle (FunctionName.c_str ()))
526
+ return std::string (" " );
527
+ size_t BufferSize = 1 ;
528
+ char *Buffer = static_cast <char *>(std::malloc (BufferSize));
529
+ char *BaseName = Demangler.getFunctionBaseName (Buffer, &BufferSize);
530
+ if (!BaseName) {
531
+ std::free (Buffer);
532
+ return std::string (" " );
533
+ }
534
+ if (Buffer != BaseName)
535
+ Buffer = BaseName;
536
+ std::string BaseNameStr (Buffer, BufferSize);
537
+ std::free (Buffer);
538
+ return BaseNameStr;
539
+ };
540
+
541
+ // Matches YAMLBF to BFs with neighbor hashes.
542
+ for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions ) {
543
+ if (YamlBF.Used )
544
+ continue ;
545
+ auto AdjacentYamlBFsOpt = CGMatcher.getAdjacentYamlBFs (YamlBF);
546
+ if (!AdjacentYamlBFsOpt)
547
+ continue ;
548
+ std::set<yaml::bolt::BinaryFunctionProfile *> AdjacentYamlBFs =
549
+ AdjacentYamlBFsOpt.value ();
550
+ std::string AdjacentYamlBFsHashStr;
551
+ for (auto *AdjacentYamlBF : AdjacentYamlBFs)
552
+ AdjacentYamlBFsHashStr += AdjacentYamlBF->Name ;
553
+ uint64_t Hash = std::hash<std::string>{}(AdjacentYamlBFsHashStr);
554
+ auto BFsWithSameHashOpt = CGMatcher.getBFsWithNeighborHash (Hash);
555
+ if (!BFsWithSameHashOpt)
556
+ continue ;
557
+ std::vector<BinaryFunction *> BFsWithSameHash = BFsWithSameHashOpt.value ();
558
+ // Finds the binary function with the longest common prefix to the profiled
559
+ // function and matches.
560
+ BinaryFunction *ClosestBF = nullptr ;
561
+ size_t LCP = 0 ;
562
+ std::string YamlBFBaseName = GetBaseName (YamlBF.Name );
563
+ for (BinaryFunction *BF : BFsWithSameHash) {
564
+ if (ProfiledFunctions.count (BF))
565
+ continue ;
566
+ std::string BFName = std::string (BF->getOneName ());
567
+ std::string BFBaseName = GetBaseName (BFName);
568
+ size_t PrefixLength = 0 ;
569
+ size_t N = std::min (YamlBFBaseName.size (), BFBaseName.size ());
570
+ for (size_t I = 0 ; I < N; ++I) {
571
+ if (YamlBFBaseName[I] != BFBaseName[I])
572
+ break ;
573
+ ++PrefixLength;
574
+ }
575
+ if (PrefixLength >= LCP) {
576
+ LCP = PrefixLength;
577
+ ClosestBF = BF;
578
+ }
579
+ }
580
+ if (ClosestBF) {
581
+ matchProfileToFunction (YamlBF, *ClosestBF);
582
+ ++MatchedWithCallGraph;
583
+ }
584
+ }
585
+
586
+ return MatchedWithCallGraph;
587
+ }
588
+
449
589
size_t YAMLProfileReader::matchWithNameSimilarity (BinaryContext &BC) {
450
590
if (opts::NameSimilarityFunctionMatchingThreshold == 0 )
451
591
return 0 ;
@@ -581,9 +721,14 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
581
721
}
582
722
}
583
723
724
+ // Map profiled function ids to names.
725
+ for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions )
726
+ IdToYamLBF[YamlBF.Id ] = &YamlBF;
727
+
584
728
const size_t MatchedWithExactName = matchWithExactName ();
585
729
const size_t MatchedWithHash = matchWithHash (BC);
586
730
const size_t MatchedWithLTOCommonName = matchWithLTOCommonName ();
731
+ const size_t MatchedWithCallGraph = matchWithCallGraph (BC);
587
732
const size_t MatchedWithNameSimilarity = matchWithNameSimilarity (BC);
588
733
589
734
for (auto [YamlBF, BF] : llvm::zip_equal (YamlBP.Functions , ProfileBFs))
@@ -603,18 +748,15 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
603
748
<< " functions with hash\n " ;
604
749
outs () << " BOLT-INFO: matched " << MatchedWithLTOCommonName
605
750
<< " functions with matching LTO common names\n " ;
751
+ outs () << " BOLT-INFO: matched " << MatchedWithCallGraph
752
+ << " functions with call graph\n " ;
606
753
outs () << " BOLT-INFO: matched " << MatchedWithNameSimilarity
607
754
<< " functions with similar names\n " ;
608
755
}
609
756
610
757
// Set for parseFunctionProfile().
611
758
NormalizeByInsnCount = usesEvent (" cycles" ) || usesEvent (" instructions" );
612
759
NormalizeByCalls = usesEvent (" branches" );
613
-
614
- // Map profiled function ids to names.
615
- for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions )
616
- IdToYamLBF[YamlBF.Id ] = &YamlBF;
617
-
618
760
uint64_t NumUnused = 0 ;
619
761
for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions ) {
620
762
if (YamlBF.Id >= YamlProfileToFunction.size ()) {
@@ -630,7 +772,8 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
630
772
631
773
BC.setNumUnusedProfiledObjects (NumUnused);
632
774
633
- if (opts::Lite && opts::MatchProfileWithFunctionHash) {
775
+ if (opts::Lite &&
776
+ (opts::MatchProfileWithFunctionHash || opts::MatchWithCallGraph)) {
634
777
for (BinaryFunction *BF : BC.getAllBinaryFunctions ())
635
778
if (!BF->hasProfile ())
636
779
BF->setIgnored ();
0 commit comments