11
11
#include " bolt/Core/BinaryFunction.h"
12
12
#include " bolt/Passes/MCF.h"
13
13
#include " bolt/Profile/ProfileYAMLMapping.h"
14
+ #include " bolt/Utils/NameResolver.h"
14
15
#include " bolt/Utils/Utils.h"
15
16
#include " llvm/ADT/STLExtras.h"
17
+ #include " llvm/ADT/edit_distance.h"
18
+ #include " llvm/Demangle/Demangle.h"
16
19
#include " llvm/Support/CommandLine.h"
17
20
18
21
using namespace llvm ;
@@ -24,6 +27,11 @@ extern cl::OptionCategory BoltOptCategory;
24
27
extern cl::opt<bool > InferStaleProfile;
25
28
extern cl::opt<bool > Lite;
26
29
30
+ cl::opt<unsigned > NameSimilarityFunctionMatchingThreshold (
31
+ " name-similarity-function-matching-threshold" ,
32
+ cl::desc (" Match functions using namespace and edit distance" ), cl::init(0 ),
33
+ cl::Hidden, cl::cat(BoltOptCategory));
34
+
27
35
static llvm::cl::opt<bool >
28
36
IgnoreHash (" profile-ignore-hash" ,
29
37
cl::desc (" ignore hash while reading function profile" ),
@@ -350,6 +358,111 @@ bool YAMLProfileReader::mayHaveProfileData(const BinaryFunction &BF) {
350
358
return false ;
351
359
}
352
360
361
+ uint64_t YAMLProfileReader::matchWithNameSimilarity (BinaryContext &BC) {
362
+ uint64_t MatchedWithNameSimilarity = 0 ;
363
+ ItaniumPartialDemangler Demangler;
364
+
365
+ // Demangle and derive namespace from function name.
366
+ auto DemangleName = [&](std::string &FunctionName) {
367
+ StringRef RestoredName = NameResolver::restore (FunctionName);
368
+ return demangle (RestoredName);
369
+ };
370
+ auto DeriveNameSpace = [&](std::string &DemangledName) {
371
+ if (Demangler.partialDemangle (DemangledName.c_str ()))
372
+ return std::string (" " );
373
+ std::vector<char > Buffer (DemangledName.begin (), DemangledName.end ());
374
+ size_t BufferSize;
375
+ char *NameSpace =
376
+ Demangler.getFunctionDeclContextName (&Buffer[0 ], &BufferSize);
377
+ return std::string (NameSpace, BufferSize);
378
+ };
379
+
380
+ // Maps namespaces to associated function block counts and gets profile
381
+ // function names and namespaces to minimize the number of BFs to process and
382
+ // avoid repeated name demangling/namespace derivation.
383
+ StringMap<std::set<uint32_t >> NamespaceToProfiledBFSizes;
384
+ std::vector<std::string> ProfileBFDemangledNames;
385
+ ProfileBFDemangledNames.reserve (YamlBP.Functions .size ());
386
+ std::vector<std::string> ProfiledBFNamespaces;
387
+ ProfiledBFNamespaces.reserve (YamlBP.Functions .size ());
388
+
389
+ for (auto &YamlBF : YamlBP.Functions ) {
390
+ std::string YamlBFDemangledName = DemangleName (YamlBF.Name );
391
+ ProfileBFDemangledNames.push_back (YamlBFDemangledName);
392
+ std::string YamlBFNamespace = DeriveNameSpace (YamlBFDemangledName);
393
+ ProfiledBFNamespaces.push_back (YamlBFNamespace);
394
+ NamespaceToProfiledBFSizes[YamlBFNamespace].insert (YamlBF.NumBasicBlocks );
395
+ }
396
+
397
+ StringMap<std::vector<BinaryFunction *>> NamespaceToBFs;
398
+
399
+ // Maps namespaces to BFs excluding binary functions with no equal sized
400
+ // profiled functions belonging to the same namespace.
401
+ for (BinaryFunction *BF : BC.getAllBinaryFunctions ()) {
402
+ std::string DemangledName = BF->getDemangledName ();
403
+ std::string Namespace = DeriveNameSpace (DemangledName);
404
+
405
+ auto NamespaceToProfiledBFSizesIt =
406
+ NamespaceToProfiledBFSizes.find (Namespace);
407
+ // Skip if there are no ProfileBFs with a given \p Namespace.
408
+ if (NamespaceToProfiledBFSizesIt == NamespaceToProfiledBFSizes.end ())
409
+ continue ;
410
+ // Skip if there are no ProfileBFs in a given \p Namespace with
411
+ // equal number of blocks.
412
+ if (NamespaceToProfiledBFSizesIt->second .count (BF->size ()) == 0 )
413
+ continue ;
414
+ auto NamespaceToBFsIt = NamespaceToBFs.find (Namespace);
415
+ if (NamespaceToBFsIt == NamespaceToBFs.end ())
416
+ NamespaceToBFs[Namespace] = {BF};
417
+ else
418
+ NamespaceToBFsIt->second .push_back (BF);
419
+ }
420
+
421
+ // Iterates through all profiled functions and binary functions belonging to
422
+ // the same namespace and matches based on edit distance threshold.
423
+ assert (YamlBP.Functions .size () == ProfiledBFNamespaces.size () &&
424
+ ProfiledBFNamespaces.size () == ProfileBFDemangledNames.size ());
425
+ for (size_t I = 0 ; I < YamlBP.Functions .size (); ++I) {
426
+ yaml::bolt::BinaryFunctionProfile &YamlBF = YamlBP.Functions [I];
427
+ std::string &YamlBFNamespace = ProfiledBFNamespaces[I];
428
+ if (YamlBF.Used )
429
+ continue ;
430
+ // Skip if there are no BFs in a given \p Namespace.
431
+ auto It = NamespaceToBFs.find (YamlBFNamespace);
432
+ if (It == NamespaceToBFs.end ())
433
+ continue ;
434
+
435
+ std::string &YamlBFDemangledName = ProfileBFDemangledNames[I];
436
+ std::vector<BinaryFunction *> BFs = It->second ;
437
+ unsigned MinEditDistance = UINT_MAX;
438
+ BinaryFunction *ClosestNameBF = nullptr ;
439
+
440
+ // Determines BF the closest to the profiled function, in the
441
+ // same namespace.
442
+ for (BinaryFunction *BF : BFs) {
443
+ if (ProfiledFunctions.count (BF))
444
+ continue ;
445
+ if (BF->size () != YamlBF.NumBasicBlocks )
446
+ continue ;
447
+ std::string BFDemangledName = BF->getDemangledName ();
448
+ unsigned BFEditDistance =
449
+ StringRef (BFDemangledName).edit_distance (YamlBFDemangledName);
450
+ if (BFEditDistance < MinEditDistance) {
451
+ MinEditDistance = BFEditDistance;
452
+ ClosestNameBF = BF;
453
+ }
454
+ }
455
+
456
+ if (ClosestNameBF &&
457
+ MinEditDistance <= opts::NameSimilarityFunctionMatchingThreshold) {
458
+ matchProfileToFunction (YamlBF, *ClosestNameBF);
459
+ ++MatchedWithNameSimilarity;
460
+ }
461
+ }
462
+
463
+ return MatchedWithNameSimilarity;
464
+ }
465
+
353
466
Error YAMLProfileReader::readProfile (BinaryContext &BC) {
354
467
if (opts::Verbosity >= 1 ) {
355
468
outs () << " BOLT-INFO: YAML profile with hash: " ;
@@ -461,6 +574,12 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
461
574
if (!YamlBF.Used && BF && !ProfiledFunctions.count (BF))
462
575
matchProfileToFunction (YamlBF, *BF);
463
576
577
+ // Uses name similarity to match functions that were not matched by name.
578
+ uint64_t MatchedWithNameSimilarity =
579
+ opts::NameSimilarityFunctionMatchingThreshold > 0
580
+ ? matchWithNameSimilarity (BC)
581
+ : 0 ;
582
+
464
583
for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions )
465
584
if (!YamlBF.Used && opts::Verbosity >= 1 )
466
585
errs () << " BOLT-WARNING: profile ignored for function " << YamlBF.Name
@@ -473,6 +592,8 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
473
592
<< " functions with hash\n " ;
474
593
outs () << " BOLT-INFO: matched " << MatchedWithLTOCommonName
475
594
<< " functions with matching LTO common names\n " ;
595
+ outs () << " BOLT-INFO: matched " << MatchedWithNameSimilarity
596
+ << " functions with similar names\n " ;
476
597
}
477
598
478
599
// Set for parseFunctionProfile().
0 commit comments