llvm-project

Форк
0
/
YAMLProfileReader.cpp 
643 строки · 22.5 Кб
1
//===- bolt/Profile/YAMLProfileReader.cpp - YAML profile de-serializer ----===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8

9
#include "bolt/Profile/YAMLProfileReader.h"
10
#include "bolt/Core/BinaryBasicBlock.h"
11
#include "bolt/Core/BinaryFunction.h"
12
#include "bolt/Passes/MCF.h"
13
#include "bolt/Profile/ProfileYAMLMapping.h"
14
#include "bolt/Utils/NameResolver.h"
15
#include "bolt/Utils/Utils.h"
16
#include "llvm/ADT/STLExtras.h"
17
#include "llvm/ADT/edit_distance.h"
18
#include "llvm/Demangle/Demangle.h"
19
#include "llvm/Support/CommandLine.h"
20

21
using namespace llvm;
22

23
namespace opts {
24

25
extern cl::opt<unsigned> Verbosity;
26
extern cl::OptionCategory BoltOptCategory;
27
extern cl::opt<bool> InferStaleProfile;
28
extern cl::opt<bool> Lite;
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

35
static llvm::cl::opt<bool>
36
    IgnoreHash("profile-ignore-hash",
37
               cl::desc("ignore hash while reading function profile"),
38
               cl::Hidden, cl::cat(BoltOptCategory));
39

40
llvm::cl::opt<bool>
41
    MatchProfileWithFunctionHash("match-profile-with-function-hash",
42
                                 cl::desc("Match profile with function hash"),
43
                                 cl::Hidden, cl::cat(BoltOptCategory));
44

45
llvm::cl::opt<bool> ProfileUseDFS("profile-use-dfs",
46
                                  cl::desc("use DFS order for YAML profile"),
47
                                  cl::Hidden, cl::cat(BoltOptCategory));
48
} // namespace opts
49

50
namespace llvm {
51
namespace bolt {
52

53
bool YAMLProfileReader::isYAML(const StringRef Filename) {
54
  if (auto MB = MemoryBuffer::getFileOrSTDIN(Filename)) {
55
    StringRef Buffer = (*MB)->getBuffer();
56
    return Buffer.starts_with("---\n");
57
  } else {
58
    report_error(Filename, MB.getError());
59
  }
60
  return false;
61
}
62

63
void YAMLProfileReader::buildNameMaps(BinaryContext &BC) {
64
  auto lookupFunction = [&](StringRef Name) -> BinaryFunction * {
65
    if (BinaryData *BD = BC.getBinaryDataByName(Name))
66
      return BC.getFunctionForSymbol(BD->getSymbol());
67
    return nullptr;
68
  };
69

70
  ProfileBFs.reserve(YamlBP.Functions.size());
71

72
  for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) {
73
    StringRef Name = YamlBF.Name;
74
    const size_t Pos = Name.find("(*");
75
    if (Pos != StringRef::npos)
76
      Name = Name.substr(0, Pos);
77
    ProfileFunctionNames.insert(Name);
78
    ProfileBFs.push_back(lookupFunction(Name));
79
    if (const std::optional<StringRef> CommonName = getLTOCommonName(Name))
80
      LTOCommonNameMap[*CommonName].push_back(&YamlBF);
81
  }
82
  for (auto &[Symbol, BF] : BC.SymbolToFunctionMap) {
83
    StringRef Name = Symbol->getName();
84
    if (const std::optional<StringRef> CommonName = getLTOCommonName(Name))
85
      LTOCommonNameFunctionMap[*CommonName].insert(BF);
86
  }
87
}
88

89
bool YAMLProfileReader::hasLocalsWithFileName() const {
90
  return llvm::any_of(ProfileFunctionNames.keys(), [](StringRef FuncName) {
91
    return FuncName.count('/') == 2 && FuncName[0] != '/';
92
  });
93
}
94

95
bool YAMLProfileReader::parseFunctionProfile(
96
    BinaryFunction &BF, const yaml::bolt::BinaryFunctionProfile &YamlBF) {
97
  BinaryContext &BC = BF.getBinaryContext();
98

99
  const bool IsDFSOrder = YamlBP.Header.IsDFSOrder;
100
  const HashFunction HashFunction = YamlBP.Header.HashFunction;
101
  bool ProfileMatched = true;
102
  uint64_t MismatchedBlocks = 0;
103
  uint64_t MismatchedCalls = 0;
104
  uint64_t MismatchedEdges = 0;
105

106
  uint64_t FunctionExecutionCount = 0;
107

108
  BF.setExecutionCount(YamlBF.ExecCount);
109

110
  uint64_t FuncRawBranchCount = 0;
111
  for (const yaml::bolt::BinaryBasicBlockProfile &YamlBB : YamlBF.Blocks)
112
    for (const yaml::bolt::SuccessorInfo &YamlSI : YamlBB.Successors)
113
      FuncRawBranchCount += YamlSI.Count;
114
  BF.setRawBranchCount(FuncRawBranchCount);
115

116
  if (BF.empty())
117
    return true;
118

119
  if (!opts::IgnoreHash) {
120
    if (!BF.getHash())
121
      BF.computeHash(IsDFSOrder, HashFunction);
122
    if (YamlBF.Hash != BF.getHash()) {
123
      if (opts::Verbosity >= 1)
124
        errs() << "BOLT-WARNING: function hash mismatch\n";
125
      ProfileMatched = false;
126
    }
127
  }
128

129
  if (YamlBF.NumBasicBlocks != BF.size()) {
130
    if (opts::Verbosity >= 1)
131
      errs() << "BOLT-WARNING: number of basic blocks mismatch\n";
132
    ProfileMatched = false;
133
  }
134

135
  BinaryFunction::BasicBlockOrderType Order;
136
  if (IsDFSOrder)
137
    llvm::copy(BF.dfs(), std::back_inserter(Order));
138
  else
139
    llvm::copy(BF.getLayout().blocks(), std::back_inserter(Order));
140

141
  for (const yaml::bolt::BinaryBasicBlockProfile &YamlBB : YamlBF.Blocks) {
142
    if (YamlBB.Index >= Order.size()) {
143
      if (opts::Verbosity >= 2)
144
        errs() << "BOLT-WARNING: index " << YamlBB.Index
145
               << " is out of bounds\n";
146
      ++MismatchedBlocks;
147
      continue;
148
    }
149

150
    BinaryBasicBlock &BB = *Order[YamlBB.Index];
151

152
    // Basic samples profile (without LBR) does not have branches information
153
    // and needs a special processing.
154
    if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE) {
155
      if (!YamlBB.EventCount) {
156
        BB.setExecutionCount(0);
157
        continue;
158
      }
159
      uint64_t NumSamples = YamlBB.EventCount * 1000;
160
      if (NormalizeByInsnCount && BB.getNumNonPseudos())
161
        NumSamples /= BB.getNumNonPseudos();
162
      else if (NormalizeByCalls)
163
        NumSamples /= BB.getNumCalls() + 1;
164

165
      BB.setExecutionCount(NumSamples);
166
      if (BB.isEntryPoint())
167
        FunctionExecutionCount += NumSamples;
168
      continue;
169
    }
170

171
    BB.setExecutionCount(YamlBB.ExecCount);
172

173
    for (const yaml::bolt::CallSiteInfo &YamlCSI : YamlBB.CallSites) {
174
      BinaryFunction *Callee = YamlCSI.DestId < YamlProfileToFunction.size()
175
                                   ? YamlProfileToFunction[YamlCSI.DestId]
176
                                   : nullptr;
177
      bool IsFunction = Callee ? true : false;
178
      MCSymbol *CalleeSymbol = nullptr;
179
      if (IsFunction)
180
        CalleeSymbol = Callee->getSymbolForEntryID(YamlCSI.EntryDiscriminator);
181

182
      BF.getAllCallSites().emplace_back(CalleeSymbol, YamlCSI.Count,
183
                                        YamlCSI.Mispreds, YamlCSI.Offset);
184

185
      if (YamlCSI.Offset >= BB.getOriginalSize()) {
186
        if (opts::Verbosity >= 2)
187
          errs() << "BOLT-WARNING: offset " << YamlCSI.Offset
188
                 << " out of bounds in block " << BB.getName() << '\n';
189
        ++MismatchedCalls;
190
        continue;
191
      }
192

193
      MCInst *Instr =
194
          BF.getInstructionAtOffset(BB.getInputOffset() + YamlCSI.Offset);
195
      if (!Instr) {
196
        if (opts::Verbosity >= 2)
197
          errs() << "BOLT-WARNING: no instruction at offset " << YamlCSI.Offset
198
                 << " in block " << BB.getName() << '\n';
199
        ++MismatchedCalls;
200
        continue;
201
      }
202
      if (!BC.MIB->isCall(*Instr) && !BC.MIB->isIndirectBranch(*Instr)) {
203
        if (opts::Verbosity >= 2)
204
          errs() << "BOLT-WARNING: expected call at offset " << YamlCSI.Offset
205
                 << " in block " << BB.getName() << '\n';
206
        ++MismatchedCalls;
207
        continue;
208
      }
209

210
      auto setAnnotation = [&](StringRef Name, uint64_t Count) {
211
        if (BC.MIB->hasAnnotation(*Instr, Name)) {
212
          if (opts::Verbosity >= 1)
213
            errs() << "BOLT-WARNING: ignoring duplicate " << Name
214
                   << " info for offset 0x" << Twine::utohexstr(YamlCSI.Offset)
215
                   << " in function " << BF << '\n';
216
          return;
217
        }
218
        BC.MIB->addAnnotation(*Instr, Name, Count);
219
      };
220

221
      if (BC.MIB->isIndirectCall(*Instr) || BC.MIB->isIndirectBranch(*Instr)) {
222
        auto &CSP = BC.MIB->getOrCreateAnnotationAs<IndirectCallSiteProfile>(
223
            *Instr, "CallProfile");
224
        CSP.emplace_back(CalleeSymbol, YamlCSI.Count, YamlCSI.Mispreds);
225
      } else if (BC.MIB->getConditionalTailCall(*Instr)) {
226
        setAnnotation("CTCTakenCount", YamlCSI.Count);
227
        setAnnotation("CTCMispredCount", YamlCSI.Mispreds);
228
      } else {
229
        setAnnotation("Count", YamlCSI.Count);
230
      }
231
    }
232

233
    for (const yaml::bolt::SuccessorInfo &YamlSI : YamlBB.Successors) {
234
      if (YamlSI.Index >= Order.size()) {
235
        if (opts::Verbosity >= 1)
236
          errs() << "BOLT-WARNING: index out of bounds for profiled block\n";
237
        ++MismatchedEdges;
238
        continue;
239
      }
240

241
      BinaryBasicBlock *ToBB = Order[YamlSI.Index];
242
      if (!BB.getSuccessor(ToBB->getLabel())) {
243
        // Allow passthrough blocks.
244
        BinaryBasicBlock *FTSuccessor = BB.getConditionalSuccessor(false);
245
        if (FTSuccessor && FTSuccessor->succ_size() == 1 &&
246
            FTSuccessor->getSuccessor(ToBB->getLabel())) {
247
          BinaryBasicBlock::BinaryBranchInfo &FTBI =
248
              FTSuccessor->getBranchInfo(*ToBB);
249
          FTBI.Count += YamlSI.Count;
250
          FTBI.MispredictedCount += YamlSI.Mispreds;
251
          ToBB = FTSuccessor;
252
        } else {
253
          if (opts::Verbosity >= 1)
254
            errs() << "BOLT-WARNING: no successor for block " << BB.getName()
255
                   << " that matches index " << YamlSI.Index << " or block "
256
                   << ToBB->getName() << '\n';
257
          ++MismatchedEdges;
258
          continue;
259
        }
260
      }
261

262
      BinaryBasicBlock::BinaryBranchInfo &BI = BB.getBranchInfo(*ToBB);
263
      BI.Count += YamlSI.Count;
264
      BI.MispredictedCount += YamlSI.Mispreds;
265
    }
266
  }
267

268
  // If basic block profile wasn't read it should be 0.
269
  for (BinaryBasicBlock &BB : BF)
270
    if (BB.getExecutionCount() == BinaryBasicBlock::COUNT_NO_PROFILE)
271
      BB.setExecutionCount(0);
272

273
  if (YamlBP.Header.Flags & BinaryFunction::PF_SAMPLE)
274
    BF.setExecutionCount(FunctionExecutionCount);
275

276
  ProfileMatched &= !MismatchedBlocks && !MismatchedCalls && !MismatchedEdges;
277

278
  if (!ProfileMatched) {
279
    if (opts::Verbosity >= 1)
280
      errs() << "BOLT-WARNING: " << MismatchedBlocks << " blocks, "
281
             << MismatchedCalls << " calls, and " << MismatchedEdges
282
             << " edges in profile did not match function " << BF << '\n';
283

284
    if (YamlBF.NumBasicBlocks != BF.size())
285
      ++BC.Stats.NumStaleFuncsWithEqualBlockCount;
286

287
    if (opts::InferStaleProfile && inferStaleProfile(BF, YamlBF))
288
      ProfileMatched = true;
289
  }
290
  if (ProfileMatched)
291
    BF.markProfiled(YamlBP.Header.Flags);
292

293
  return ProfileMatched;
294
}
295

296
Error YAMLProfileReader::preprocessProfile(BinaryContext &BC) {
297
  ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
298
      MemoryBuffer::getFileOrSTDIN(Filename);
299
  if (std::error_code EC = MB.getError()) {
300
    errs() << "ERROR: cannot open " << Filename << ": " << EC.message() << "\n";
301
    return errorCodeToError(EC);
302
  }
303
  yaml::Input YamlInput(MB.get()->getBuffer());
304

305
  // Consume YAML file.
306
  YamlInput >> YamlBP;
307
  if (YamlInput.error()) {
308
    errs() << "BOLT-ERROR: syntax error parsing profile in " << Filename
309
           << " : " << YamlInput.error().message() << '\n';
310
    return errorCodeToError(YamlInput.error());
311
  }
312

313
  // Sanity check.
314
  if (YamlBP.Header.Version != 1)
315
    return make_error<StringError>(
316
        Twine("cannot read profile : unsupported version"),
317
        inconvertibleErrorCode());
318

319
  if (YamlBP.Header.EventNames.find(',') != StringRef::npos)
320
    return make_error<StringError>(
321
        Twine("multiple events in profile are not supported"),
322
        inconvertibleErrorCode());
323

324
  // Match profile to function based on a function name.
325
  buildNameMaps(BC);
326

327
  // Preliminary assign function execution count.
328
  for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs)) {
329
    if (!BF)
330
      continue;
331
    if (!BF->hasProfile()) {
332
      BF->setExecutionCount(YamlBF.ExecCount);
333
    } else {
334
      if (opts::Verbosity >= 1) {
335
        errs() << "BOLT-WARNING: dropping duplicate profile for " << YamlBF.Name
336
               << '\n';
337
      }
338
      BF = nullptr;
339
    }
340
  }
341

342
  return Error::success();
343
}
344

345
bool YAMLProfileReader::profileMatches(
346
    const yaml::bolt::BinaryFunctionProfile &Profile, const BinaryFunction &BF) {
347
  if (opts::IgnoreHash)
348
    return Profile.NumBasicBlocks == BF.size();
349
  return Profile.Hash == static_cast<uint64_t>(BF.getHash());
350
}
351

352
bool YAMLProfileReader::mayHaveProfileData(const BinaryFunction &BF) {
353
  if (opts::MatchProfileWithFunctionHash)
354
    return true;
355
  for (StringRef Name : BF.getNames())
356
    if (ProfileFunctionNames.contains(Name))
357
      return true;
358
  for (StringRef Name : BF.getNames()) {
359
    if (const std::optional<StringRef> CommonName = getLTOCommonName(Name)) {
360
      if (LTOCommonNameMap.contains(*CommonName))
361
        return true;
362
    }
363
  }
364

365
  return false;
366
}
367

368
size_t YAMLProfileReader::matchWithExactName() {
369
  size_t MatchedWithExactName = 0;
370
  // This first pass assigns profiles that match 100% by name and by hash.
371
  for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs)) {
372
    if (!BF)
373
      continue;
374
    BinaryFunction &Function = *BF;
375
    // Clear function call count that may have been set while pre-processing
376
    // the profile.
377
    Function.setExecutionCount(BinaryFunction::COUNT_NO_PROFILE);
378

379
    if (profileMatches(YamlBF, Function)) {
380
      matchProfileToFunction(YamlBF, Function);
381
      ++MatchedWithExactName;
382
    }
383
  }
384
  return MatchedWithExactName;
385
}
386

387
size_t YAMLProfileReader::matchWithHash(BinaryContext &BC) {
388
  // Iterates through profiled functions to match the first binary function with
389
  // the same exact hash. Serves to match identical, renamed functions.
390
  // Collisions are possible where multiple functions share the same exact hash.
391
  size_t MatchedWithHash = 0;
392
  if (opts::MatchProfileWithFunctionHash) {
393
    DenseMap<size_t, BinaryFunction *> StrictHashToBF;
394
    StrictHashToBF.reserve(BC.getBinaryFunctions().size());
395

396
    for (auto &[_, BF] : BC.getBinaryFunctions())
397
      StrictHashToBF[BF.getHash()] = &BF;
398

399
    for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) {
400
      if (YamlBF.Used)
401
        continue;
402
      auto It = StrictHashToBF.find(YamlBF.Hash);
403
      if (It != StrictHashToBF.end() && !ProfiledFunctions.count(It->second)) {
404
        BinaryFunction *BF = It->second;
405
        matchProfileToFunction(YamlBF, *BF);
406
        ++MatchedWithHash;
407
      }
408
    }
409
  }
410
  return MatchedWithHash;
411
}
412

413
size_t YAMLProfileReader::matchWithLTOCommonName() {
414
  // This second pass allows name ambiguity for LTO private functions.
415
  size_t MatchedWithLTOCommonName = 0;
416
  for (const auto &[CommonName, LTOProfiles] : LTOCommonNameMap) {
417
    if (!LTOCommonNameFunctionMap.contains(CommonName))
418
      continue;
419
    std::unordered_set<BinaryFunction *> &Functions =
420
        LTOCommonNameFunctionMap[CommonName];
421
    // Return true if a given profile is matched to one of BinaryFunctions with
422
    // matching LTO common name.
423
    auto matchProfile = [&](yaml::bolt::BinaryFunctionProfile *YamlBF) {
424
      if (YamlBF->Used)
425
        return false;
426
      for (BinaryFunction *BF : Functions) {
427
        if (!ProfiledFunctions.count(BF) && profileMatches(*YamlBF, *BF)) {
428
          matchProfileToFunction(*YamlBF, *BF);
429
          ++MatchedWithLTOCommonName;
430
          return true;
431
        }
432
      }
433
      return false;
434
    };
435
    bool ProfileMatched = llvm::any_of(LTOProfiles, matchProfile);
436

437
    // If there's only one function with a given name, try to match it
438
    // partially.
439
    if (!ProfileMatched && LTOProfiles.size() == 1 && Functions.size() == 1 &&
440
        !LTOProfiles.front()->Used &&
441
        !ProfiledFunctions.count(*Functions.begin())) {
442
      matchProfileToFunction(*LTOProfiles.front(), **Functions.begin());
443
      ++MatchedWithLTOCommonName;
444
    }
445
  }
446
  return MatchedWithLTOCommonName;
447
}
448

449
size_t YAMLProfileReader::matchWithNameSimilarity(BinaryContext &BC) {
450
  if (opts::NameSimilarityFunctionMatchingThreshold == 0)
451
    return 0;
452

453
  size_t MatchedWithNameSimilarity = 0;
454
  ItaniumPartialDemangler Demangler;
455

456
  // Demangle and derive namespace from function name.
457
  auto DemangleName = [&](std::string &FunctionName) {
458
    StringRef RestoredName = NameResolver::restore(FunctionName);
459
    return demangle(RestoredName);
460
  };
461
  auto DeriveNameSpace = [&](std::string &DemangledName) {
462
    if (Demangler.partialDemangle(DemangledName.c_str()))
463
      return std::string("");
464
    std::vector<char> Buffer(DemangledName.begin(), DemangledName.end());
465
    size_t BufferSize;
466
    char *NameSpace =
467
        Demangler.getFunctionDeclContextName(&Buffer[0], &BufferSize);
468
    return std::string(NameSpace, BufferSize);
469
  };
470

471
  // Maps namespaces to associated function block counts and gets profile
472
  // function names and namespaces to minimize the number of BFs to process and
473
  // avoid repeated name demangling/namespace derivation.
474
  StringMap<std::set<uint32_t>> NamespaceToProfiledBFSizes;
475
  std::vector<std::string> ProfileBFDemangledNames;
476
  ProfileBFDemangledNames.reserve(YamlBP.Functions.size());
477
  std::vector<std::string> ProfiledBFNamespaces;
478
  ProfiledBFNamespaces.reserve(YamlBP.Functions.size());
479

480
  for (auto &YamlBF : YamlBP.Functions) {
481
    std::string YamlBFDemangledName = DemangleName(YamlBF.Name);
482
    ProfileBFDemangledNames.push_back(YamlBFDemangledName);
483
    std::string YamlBFNamespace = DeriveNameSpace(YamlBFDemangledName);
484
    ProfiledBFNamespaces.push_back(YamlBFNamespace);
485
    NamespaceToProfiledBFSizes[YamlBFNamespace].insert(YamlBF.NumBasicBlocks);
486
  }
487

488
  StringMap<std::vector<BinaryFunction *>> NamespaceToBFs;
489

490
  // Maps namespaces to BFs excluding binary functions with no equal sized
491
  // profiled functions belonging to the same namespace.
492
  for (BinaryFunction *BF : BC.getAllBinaryFunctions()) {
493
    std::string DemangledName = BF->getDemangledName();
494
    std::string Namespace = DeriveNameSpace(DemangledName);
495

496
    auto NamespaceToProfiledBFSizesIt =
497
        NamespaceToProfiledBFSizes.find(Namespace);
498
    // Skip if there are no ProfileBFs with a given \p Namespace.
499
    if (NamespaceToProfiledBFSizesIt == NamespaceToProfiledBFSizes.end())
500
      continue;
501
    // Skip if there are no ProfileBFs in a given \p Namespace with
502
    // equal number of blocks.
503
    if (NamespaceToProfiledBFSizesIt->second.count(BF->size()) == 0)
504
      continue;
505
    auto NamespaceToBFsIt = NamespaceToBFs.find(Namespace);
506
    if (NamespaceToBFsIt == NamespaceToBFs.end())
507
      NamespaceToBFs[Namespace] = {BF};
508
    else
509
      NamespaceToBFsIt->second.push_back(BF);
510
  }
511

512
  // Iterates through all profiled functions and binary functions belonging to
513
  // the same namespace and matches based on edit distance threshold.
514
  assert(YamlBP.Functions.size() == ProfiledBFNamespaces.size() &&
515
         ProfiledBFNamespaces.size() == ProfileBFDemangledNames.size());
516
  for (size_t I = 0; I < YamlBP.Functions.size(); ++I) {
517
    yaml::bolt::BinaryFunctionProfile &YamlBF = YamlBP.Functions[I];
518
    std::string &YamlBFNamespace = ProfiledBFNamespaces[I];
519
    if (YamlBF.Used)
520
      continue;
521
    // Skip if there are no BFs in a given \p Namespace.
522
    auto It = NamespaceToBFs.find(YamlBFNamespace);
523
    if (It == NamespaceToBFs.end())
524
      continue;
525

526
    std::string &YamlBFDemangledName = ProfileBFDemangledNames[I];
527
    std::vector<BinaryFunction *> BFs = It->second;
528
    unsigned MinEditDistance = UINT_MAX;
529
    BinaryFunction *ClosestNameBF = nullptr;
530

531
    // Determines BF the closest to the profiled function, in the
532
    // same namespace.
533
    for (BinaryFunction *BF : BFs) {
534
      if (ProfiledFunctions.count(BF))
535
        continue;
536
      if (BF->size() != YamlBF.NumBasicBlocks)
537
        continue;
538
      std::string BFDemangledName = BF->getDemangledName();
539
      unsigned BFEditDistance =
540
          StringRef(BFDemangledName).edit_distance(YamlBFDemangledName);
541
      if (BFEditDistance < MinEditDistance) {
542
        MinEditDistance = BFEditDistance;
543
        ClosestNameBF = BF;
544
      }
545
    }
546

547
    if (ClosestNameBF &&
548
        MinEditDistance <= opts::NameSimilarityFunctionMatchingThreshold) {
549
      matchProfileToFunction(YamlBF, *ClosestNameBF);
550
      ++MatchedWithNameSimilarity;
551
    }
552
  }
553

554
  return MatchedWithNameSimilarity;
555
}
556

557
Error YAMLProfileReader::readProfile(BinaryContext &BC) {
558
  if (opts::Verbosity >= 1) {
559
    outs() << "BOLT-INFO: YAML profile with hash: ";
560
    switch (YamlBP.Header.HashFunction) {
561
    case HashFunction::StdHash:
562
      outs() << "std::hash\n";
563
      break;
564
    case HashFunction::XXH3:
565
      outs() << "xxh3\n";
566
      break;
567
    }
568
  }
569
  YamlProfileToFunction.resize(YamlBP.Functions.size() + 1);
570

571
  // Computes hash for binary functions.
572
  if (opts::MatchProfileWithFunctionHash) {
573
    for (auto &[_, BF] : BC.getBinaryFunctions()) {
574
      BF.computeHash(YamlBP.Header.IsDFSOrder, YamlBP.Header.HashFunction);
575
    }
576
  } else if (!opts::IgnoreHash) {
577
    for (BinaryFunction *BF : ProfileBFs) {
578
      if (!BF)
579
        continue;
580
      BF->computeHash(YamlBP.Header.IsDFSOrder, YamlBP.Header.HashFunction);
581
    }
582
  }
583

584
  const size_t MatchedWithExactName = matchWithExactName();
585
  const size_t MatchedWithHash = matchWithHash(BC);
586
  const size_t MatchedWithLTOCommonName = matchWithLTOCommonName();
587
  const size_t MatchedWithNameSimilarity = matchWithNameSimilarity(BC);
588

589
  for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs))
590
    if (!YamlBF.Used && BF && !ProfiledFunctions.count(BF))
591
      matchProfileToFunction(YamlBF, *BF);
592

593

594
  for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions)
595
    if (!YamlBF.Used && opts::Verbosity >= 1)
596
      errs() << "BOLT-WARNING: profile ignored for function " << YamlBF.Name
597
             << '\n';
598

599
  if (opts::Verbosity >= 1) {
600
    outs() << "BOLT-INFO: matched " << MatchedWithExactName
601
           << " functions with identical names\n";
602
    outs() << "BOLT-INFO: matched " << MatchedWithHash
603
           << " functions with hash\n";
604
    outs() << "BOLT-INFO: matched " << MatchedWithLTOCommonName
605
           << " functions with matching LTO common names\n";
606
    outs() << "BOLT-INFO: matched " << MatchedWithNameSimilarity
607
           << " functions with similar names\n";
608
  }
609

610
  // Set for parseFunctionProfile().
611
  NormalizeByInsnCount = usesEvent("cycles") || usesEvent("instructions");
612
  NormalizeByCalls = usesEvent("branches");
613

614
  uint64_t NumUnused = 0;
615
  for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) {
616
    if (YamlBF.Id >= YamlProfileToFunction.size()) {
617
      // Such profile was ignored.
618
      ++NumUnused;
619
      continue;
620
    }
621
    if (BinaryFunction *BF = YamlProfileToFunction[YamlBF.Id])
622
      parseFunctionProfile(*BF, YamlBF);
623
    else
624
      ++NumUnused;
625
  }
626

627
  BC.setNumUnusedProfiledObjects(NumUnused);
628

629
  if (opts::Lite && opts::MatchProfileWithFunctionHash) {
630
    for (BinaryFunction *BF : BC.getAllBinaryFunctions())
631
      if (!BF->hasProfile())
632
        BF->setIgnored();
633
  }
634

635
  return Error::success();
636
}
637

638
bool YAMLProfileReader::usesEvent(StringRef Name) const {
639
  return YamlBP.Header.EventNames.find(std::string(Name)) != StringRef::npos;
640
}
641

642
} // end namespace bolt
643
} // end namespace llvm
644

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.