@@ -22,12 +22,18 @@ namespace opts {
22
22
extern cl::opt<unsigned > Verbosity;
23
23
extern cl::OptionCategory BoltOptCategory;
24
24
extern cl::opt<bool > InferStaleProfile;
25
+ extern cl::opt<bool > Lite;
25
26
26
27
static llvm::cl::opt<bool >
27
28
IgnoreHash (" profile-ignore-hash" ,
28
29
cl::desc (" ignore hash while reading function profile" ),
29
30
cl::Hidden, cl::cat(BoltOptCategory));
30
31
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
+
31
37
llvm::cl::opt<bool > ProfileUseDFS (" profile-use-dfs" ,
32
38
cl::desc (" use DFS order for YAML profile" ),
33
39
cl::Hidden, cl::cat(BoltOptCategory));
@@ -329,6 +335,8 @@ Error YAMLProfileReader::preprocessProfile(BinaryContext &BC) {
329
335
}
330
336
331
337
bool YAMLProfileReader::mayHaveProfileData (const BinaryFunction &BF) {
338
+ if (opts::MatchProfileWithFunctionHash)
339
+ return true ;
332
340
for (StringRef Name : BF.getNames ())
333
341
if (ProfileFunctionNames.contains (Name))
334
342
return true ;
@@ -363,9 +371,24 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
363
371
return Profile.Hash == static_cast <uint64_t >(BF.getHash ());
364
372
};
365
373
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.
369
392
for (auto [YamlBF, BF] : llvm::zip_equal (YamlBP.Functions , ProfileBFs)) {
370
393
if (!BF)
371
394
continue ;
@@ -374,15 +397,35 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
374
397
// the profile.
375
398
Function.setExecutionCount (BinaryFunction::COUNT_NO_PROFILE);
376
399
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)) {
383
401
matchProfileToFunction (YamlBF, Function);
402
+ ++MatchedWithExactName;
403
+ }
384
404
}
385
405
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.
386
429
for (const auto &[CommonName, LTOProfiles] : LTOCommonNameMap) {
387
430
if (!LTOCommonNameFunctionMap.contains (CommonName))
388
431
continue ;
@@ -396,6 +439,7 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
396
439
for (BinaryFunction *BF : Functions) {
397
440
if (!ProfiledFunctions.count (BF) && profileMatches (*YamlBF, *BF)) {
398
441
matchProfileToFunction (*YamlBF, *BF);
442
+ ++MatchedWithLTOCommonName;
399
443
return true ;
400
444
}
401
445
}
@@ -407,8 +451,10 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
407
451
// partially.
408
452
if (!ProfileMatched && LTOProfiles.size () == 1 && Functions.size () == 1 &&
409
453
!LTOProfiles.front ()->Used &&
410
- !ProfiledFunctions.count (*Functions.begin ()))
454
+ !ProfiledFunctions.count (*Functions.begin ())) {
411
455
matchProfileToFunction (*LTOProfiles.front (), **Functions.begin ());
456
+ ++MatchedWithLTOCommonName;
457
+ }
412
458
}
413
459
414
460
for (auto [YamlBF, BF] : llvm::zip_equal (YamlBP.Functions , ProfileBFs))
@@ -420,6 +466,15 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
420
466
errs () << " BOLT-WARNING: profile ignored for function " << YamlBF.Name
421
467
<< ' \n ' ;
422
468
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
+
423
478
// Set for parseFunctionProfile().
424
479
NormalizeByInsnCount = usesEvent (" cycles" ) || usesEvent (" instructions" );
425
480
NormalizeByCalls = usesEvent (" branches" );
@@ -439,6 +494,12 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
439
494
440
495
BC.setNumUnusedProfiledObjects (NumUnused);
441
496
497
+ if (opts::Lite && opts::MatchProfileWithFunctionHash) {
498
+ for (BinaryFunction *BF : BC.getAllBinaryFunctions ())
499
+ if (!BF->hasProfile ())
500
+ BF->setIgnored ();
501
+ }
502
+
442
503
return Error::success ();
443
504
}
444
505
0 commit comments