Skip to content

Commit 0579818

Browse files
committed
Merge branch 'main' into branch-protection-pauthabi
2 parents fcd090c + 94b2b1d commit 0579818

File tree

496 files changed

+25019
-9846
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

496 files changed

+25019
-9846
lines changed

bolt/docs/CommandLineArgumentReference.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,10 @@
688688

689689
Use a modified clustering algorithm geared towards minimizing branches
690690

691+
- `--name-similarity-function-matching-threshold=<uint>`
692+
693+
Match functions using namespace and edit distance.
694+
691695
- `--no-inline`
692696

693697
Disable all inlining (overrides other inlining options)

bolt/docs/OptimizingLinux.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ $ perf2bolt -p perf.data -o perf.fdata vmlinux
4444

4545
Under a high load, `perf.data` should be several gigabytes in size and you should expect the converted `perf.fdata` not to exceed 100 MB.
4646

47+
Profiles collected from multiple workloads could be joined into a single profile using `merge-fdata` utility:
48+
```bash
49+
$ merge-fdata perf.1.fdata perf.2.fdata ... perf.<N>.fdata > perf.merged.fdata
50+
```
51+
4752
Two changes are required for the kernel build. The first one is optional but highly recommended. It introduces a BOLT-reserved space into `vmlinux` code section:
4853

4954

bolt/include/bolt/Core/DebugData.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,15 @@ class DebugRangesSectionWriter {
210210
static bool classof(const DebugRangesSectionWriter *Writer) {
211211
return Writer->getKind() == RangesWriterKind::DebugRangesWriter;
212212
}
213+
214+
/// Append a range to the main buffer.
215+
void appendToRangeBuffer(const DebugBufferVector &CUBuffer);
216+
217+
/// Sets Unit DIE to be updated for CU.
218+
void setDie(DIE *Die) { this->Die = Die; }
219+
220+
/// Returns Unit DIE to be updated for CU.
221+
DIE *getDie() const { return Die; }
213222

214223
/// Writes out range lists for a current CU being processed.
215224
void virtual finalizeSection(){};
@@ -232,6 +241,9 @@ class DebugRangesSectionWriter {
232241
static constexpr uint64_t EmptyRangesOffset{0};
233242

234243
private:
244+
/// Stores Unit DIE to be updated for CU.
245+
DIE *Die{0};
246+
235247
RangesWriterKind Kind;
236248
};
237249

bolt/include/bolt/Profile/YAMLProfileReader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ class YAMLProfileReader : public ProfileReaderBase {
9393
ProfiledFunctions.emplace(&BF);
9494
}
9595

96+
/// Matches functions with similarly named profiled functions.
97+
uint64_t matchWithNameSimilarity(BinaryContext &BC);
98+
9699
/// Check if the profile uses an event with a given \p Name.
97100
bool usesEvent(StringRef Name) const;
98101
};

bolt/include/bolt/Rewrite/DWARFRewriter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ class DWARFRewriter {
8989
/// Store Rangelists writer for each DWO CU.
9090
RangeListsDWOWriers RangeListsWritersByCU;
9191

92+
/// Stores ranges writer for each DWO CU.
93+
std::unordered_map<uint64_t, std::unique_ptr<DebugRangesSectionWriter>>
94+
LegacyRangesWritersByCU;
95+
9296
std::mutex LocListDebugInfoPatchesMutex;
9397

9498
/// Dwo id specific its RangesBase.

bolt/lib/Core/BinaryContext.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2403,16 +2403,8 @@ BinaryContext::calculateEmittedSize(BinaryFunction &BF, bool FixBranches) {
24032403
Streamer->emitLabel(SplitStartLabel);
24042404
emitFunctionBody(*Streamer, BF, FF, /*EmitCodeOnly=*/true);
24052405
Streamer->emitLabel(SplitEndLabel);
2406-
// To avoid calling MCObjectStreamer::flushPendingLabels() which is
2407-
// private
2408-
Streamer->emitBytes(StringRef(""));
2409-
Streamer->switchSection(Section);
24102406
}
24112407

2412-
// To avoid calling MCObjectStreamer::flushPendingLabels() which is private or
2413-
// MCStreamer::Finish(), which does more than we want
2414-
Streamer->emitBytes(StringRef(""));
2415-
24162408
MCAssembler &Assembler =
24172409
static_cast<MCObjectStreamer *>(Streamer.get())->getAssembler();
24182410
Assembler.layout();

bolt/lib/Core/DebugData.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ uint64_t DebugRangesSectionWriter::getSectionOffset() {
177177
return SectionOffset;
178178
}
179179

180+
void DebugRangesSectionWriter::appendToRangeBuffer(
181+
const DebugBufferVector &CUBuffer) {
182+
*RangesStream << CUBuffer;
183+
SectionOffset = RangesBuffer->size();
184+
}
185+
180186
DebugAddrWriter *DebugRangeListsSectionWriter::AddrWriter = nullptr;
181187

182188
uint64_t DebugRangeListsSectionWriter::addRanges(

bolt/lib/Profile/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_llvm_library(LLVMBOLTProfile
1010
DISABLE_LLVM_LINK_LLVM_DYLIB
1111

1212
LINK_COMPONENTS
13+
Demangle
1314
Support
1415
TransformUtils
1516
)

bolt/lib/Profile/YAMLProfileReader.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
#include "bolt/Core/BinaryFunction.h"
1212
#include "bolt/Passes/MCF.h"
1313
#include "bolt/Profile/ProfileYAMLMapping.h"
14+
#include "bolt/Utils/NameResolver.h"
1415
#include "bolt/Utils/Utils.h"
1516
#include "llvm/ADT/STLExtras.h"
17+
#include "llvm/ADT/edit_distance.h"
18+
#include "llvm/Demangle/Demangle.h"
1619
#include "llvm/Support/CommandLine.h"
1720

1821
using namespace llvm;
@@ -24,6 +27,11 @@ extern cl::OptionCategory BoltOptCategory;
2427
extern cl::opt<bool> InferStaleProfile;
2528
extern cl::opt<bool> Lite;
2629

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+
2735
static llvm::cl::opt<bool>
2836
IgnoreHash("profile-ignore-hash",
2937
cl::desc("ignore hash while reading function profile"),
@@ -350,6 +358,111 @@ bool YAMLProfileReader::mayHaveProfileData(const BinaryFunction &BF) {
350358
return false;
351359
}
352360

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+
353466
Error YAMLProfileReader::readProfile(BinaryContext &BC) {
354467
if (opts::Verbosity >= 1) {
355468
outs() << "BOLT-INFO: YAML profile with hash: ";
@@ -461,6 +574,12 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
461574
if (!YamlBF.Used && BF && !ProfiledFunctions.count(BF))
462575
matchProfileToFunction(YamlBF, *BF);
463576

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+
464583
for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions)
465584
if (!YamlBF.Used && opts::Verbosity >= 1)
466585
errs() << "BOLT-WARNING: profile ignored for function " << YamlBF.Name
@@ -473,6 +592,8 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
473592
<< " functions with hash\n";
474593
outs() << "BOLT-INFO: matched " << MatchedWithLTOCommonName
475594
<< " functions with matching LTO common names\n";
595+
outs() << "BOLT-INFO: matched " << MatchedWithNameSimilarity
596+
<< " functions with similar names\n";
476597
}
477598

478599
// Set for parseFunctionProfile().

0 commit comments

Comments
 (0)