mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-14 17:06:38 +00:00
[lld-macho] Refactor BPSectionOrderer with CRTP. NFC
PR #117514 refactored BPSectionOrderer to be used by the ELF port but introduced some inefficiency: * BPSectionBase/BPSymbol are wrappers around a single pointer. The numbers of sections and symbols could be huge, and the extra allocations are memory inefficient. * Reconstructing the returned DenseMap (since BPSectionBase != InputSectin) is wasteful. This patch refactors BPSectionOrderer with Curiously Recurring Template Pattern and eliminates the inefficiency. In addition, `symbolToSectionIdxs` is removed and `rootSymbolToSectionIdxs` building is moved to lld/MachO: while getting sections for symbols is cheap in Mach-O, it is awkward and inefficient in the ELF port. While here, add a file-level comment and replace some `StringMap<*>` (which copies strings) with `DenseMap<CachedHashStringRef, *>`. Pull Request: https://github.com/llvm/llvm-project/pull/124482
This commit is contained in:
parent
c489108912
commit
e0c7f081f1
@ -24,7 +24,6 @@ set_source_files_properties("${version_inc}"
|
||||
|
||||
add_lld_library(lldCommon
|
||||
Args.cpp
|
||||
BPSectionOrdererBase.cpp
|
||||
CommonLinkerContext.cpp
|
||||
DriverDispatcher.cpp
|
||||
DWARF.cpp
|
||||
@ -48,7 +47,6 @@ add_lld_library(lldCommon
|
||||
Demangle
|
||||
MC
|
||||
Option
|
||||
ProfileData
|
||||
Support
|
||||
Target
|
||||
TargetParser
|
||||
|
@ -8,39 +8,141 @@
|
||||
|
||||
#include "BPSectionOrderer.h"
|
||||
#include "InputSection.h"
|
||||
#include "Relocations.h"
|
||||
#include "Symbols.h"
|
||||
#include "lld/Common/BPSectionOrdererBase.inc"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StableHashing.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/xxhash.h"
|
||||
|
||||
#define DEBUG_TYPE "bp-section-orderer"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace lld::macho;
|
||||
|
||||
namespace {
|
||||
struct BPOrdererMachO;
|
||||
}
|
||||
template <> struct lld::BPOrdererTraits<struct BPOrdererMachO> {
|
||||
using Section = macho::InputSection;
|
||||
using Symbol = macho::Symbol;
|
||||
};
|
||||
namespace {
|
||||
struct BPOrdererMachO : lld::BPOrderer<BPOrdererMachO> {
|
||||
static uint64_t getSize(const Section &sec) { return sec.getSize(); }
|
||||
static bool isCodeSection(const Section &sec) {
|
||||
return macho::isCodeSection(&sec);
|
||||
}
|
||||
static SmallVector<Symbol *, 0> getSymbols(const Section &sec) {
|
||||
SmallVector<Symbol *, 0> symbols;
|
||||
for (auto *sym : sec.symbols)
|
||||
if (auto *d = llvm::dyn_cast_or_null<Defined>(sym))
|
||||
symbols.emplace_back(d);
|
||||
return symbols;
|
||||
}
|
||||
|
||||
// Linkage names can be prefixed with "_" or "l_" on Mach-O. See
|
||||
// Mangler::getNameWithPrefix() for details.
|
||||
std::optional<StringRef> static getResolvedLinkageName(llvm::StringRef name) {
|
||||
if (name.consume_front("_") || name.consume_front("l_"))
|
||||
return name;
|
||||
return {};
|
||||
}
|
||||
|
||||
static void
|
||||
getSectionHashes(const Section &sec, llvm::SmallVectorImpl<uint64_t> &hashes,
|
||||
const llvm::DenseMap<const void *, uint64_t> §ionToIdx) {
|
||||
constexpr unsigned windowSize = 4;
|
||||
|
||||
// Calculate content hashes: k-mers and the last k-1 bytes.
|
||||
ArrayRef<uint8_t> data = sec.data;
|
||||
if (data.size() >= windowSize)
|
||||
for (size_t i = 0; i <= data.size() - windowSize; ++i)
|
||||
hashes.push_back(llvm::support::endian::read32le(data.data() + i));
|
||||
for (uint8_t byte : data.take_back(windowSize - 1))
|
||||
hashes.push_back(byte);
|
||||
|
||||
// Calculate relocation hashes
|
||||
for (const auto &r : sec.relocs) {
|
||||
if (r.length == 0 || r.referent.isNull() || r.offset >= data.size())
|
||||
continue;
|
||||
|
||||
uint64_t relocHash = getRelocHash(r, sectionToIdx);
|
||||
uint32_t start = (r.offset < windowSize) ? 0 : r.offset - windowSize + 1;
|
||||
for (uint32_t i = start; i < r.offset + r.length; i++) {
|
||||
auto window = data.drop_front(i).take_front(windowSize);
|
||||
hashes.push_back(xxh3_64bits(window) ^ relocHash);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::sort(hashes);
|
||||
hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end());
|
||||
}
|
||||
|
||||
static llvm::StringRef getSymName(const Symbol &sym) { return sym.getName(); }
|
||||
static uint64_t getSymValue(const Symbol &sym) {
|
||||
if (auto *d = dyn_cast<Defined>(&sym))
|
||||
return d->value;
|
||||
return 0;
|
||||
}
|
||||
static uint64_t getSymSize(const Symbol &sym) {
|
||||
if (auto *d = dyn_cast<Defined>(&sym))
|
||||
return d->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static uint64_t
|
||||
getRelocHash(const Reloc &reloc,
|
||||
const llvm::DenseMap<const void *, uint64_t> §ionToIdx) {
|
||||
auto *isec = reloc.getReferentInputSection();
|
||||
std::optional<uint64_t> sectionIdx;
|
||||
if (auto it = sectionToIdx.find(isec); it != sectionToIdx.end())
|
||||
sectionIdx = it->second;
|
||||
uint64_t kind = -1, value = 0;
|
||||
if (isec)
|
||||
kind = uint64_t(isec->kind());
|
||||
|
||||
if (auto *sym = reloc.referent.dyn_cast<Symbol *>()) {
|
||||
kind = (kind << 8) | uint8_t(sym->kind());
|
||||
if (auto *d = llvm::dyn_cast<Defined>(sym))
|
||||
value = d->value;
|
||||
}
|
||||
return llvm::stable_hash_combine(kind, sectionIdx.value_or(0), value,
|
||||
reloc.addend);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
DenseMap<const InputSection *, int> lld::macho::runBalancedPartitioning(
|
||||
StringRef profilePath, bool forFunctionCompression, bool forDataCompression,
|
||||
bool compressionSortStartupFunctions, bool verbose) {
|
||||
|
||||
SmallVector<std::unique_ptr<BPSectionBase>> sections;
|
||||
// Collect candidate sections and associated symbols.
|
||||
SmallVector<InputSection *> sections;
|
||||
DenseMap<CachedHashStringRef, DenseSet<unsigned>> rootSymbolToSectionIdxs;
|
||||
for (const auto *file : inputFiles) {
|
||||
for (auto *sec : file->sections) {
|
||||
for (auto &subsec : sec->subsections) {
|
||||
auto *isec = subsec.isec;
|
||||
if (!isec || isec->data.empty() || !isec->data.data())
|
||||
if (!isec || isec->data.empty())
|
||||
continue;
|
||||
sections.emplace_back(std::make_unique<BPSectionMacho>(isec));
|
||||
size_t idx = sections.size();
|
||||
sections.emplace_back(isec);
|
||||
for (auto *sym : BPOrdererMachO::getSymbols(*isec)) {
|
||||
auto rootName = getRootSymbol(sym->getName());
|
||||
rootSymbolToSectionIdxs[CachedHashStringRef(rootName)].insert(idx);
|
||||
if (auto linkageName =
|
||||
BPOrdererMachO::getResolvedLinkageName(rootName))
|
||||
rootSymbolToSectionIdxs[CachedHashStringRef(*linkageName)].insert(
|
||||
idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto reorderedSections = BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
profilePath, forFunctionCompression, forDataCompression,
|
||||
compressionSortStartupFunctions, verbose, sections);
|
||||
|
||||
DenseMap<const InputSection *, int> result;
|
||||
for (const auto &[sec, priority] : reorderedSections) {
|
||||
result.try_emplace(
|
||||
static_cast<const InputSection *>(
|
||||
static_cast<const BPSectionMacho *>(sec)->getSection()),
|
||||
priority);
|
||||
}
|
||||
return result;
|
||||
return BPOrdererMachO::computeOrder(profilePath, forFunctionCompression,
|
||||
forDataCompression,
|
||||
compressionSortStartupFunctions, verbose,
|
||||
sections, rootSymbolToSectionIdxs);
|
||||
}
|
||||
|
@ -14,134 +14,18 @@
|
||||
#ifndef LLD_MACHO_BPSECTION_ORDERER_H
|
||||
#define LLD_MACHO_BPSECTION_ORDERER_H
|
||||
|
||||
#include "InputSection.h"
|
||||
#include "Relocations.h"
|
||||
#include "Symbols.h"
|
||||
#include "lld/Common/BPSectionOrdererBase.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StableHashing.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/xxhash.h"
|
||||
|
||||
namespace lld::macho {
|
||||
|
||||
class InputSection;
|
||||
|
||||
class BPSymbolMacho : public BPSymbol {
|
||||
const Symbol *sym;
|
||||
|
||||
public:
|
||||
explicit BPSymbolMacho(const Symbol *s) : sym(s) {}
|
||||
|
||||
llvm::StringRef getName() const override { return sym->getName(); }
|
||||
|
||||
const Defined *asDefined() const {
|
||||
return llvm::dyn_cast_or_null<Defined>(sym);
|
||||
}
|
||||
|
||||
std::optional<uint64_t> getValue() const override {
|
||||
if (auto *d = asDefined())
|
||||
return d->value;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<uint64_t> getSize() const override {
|
||||
if (auto *d = asDefined())
|
||||
return d->size;
|
||||
return {};
|
||||
}
|
||||
|
||||
const Symbol *getSymbol() const { return sym; }
|
||||
};
|
||||
|
||||
class BPSectionMacho : public BPSectionBase {
|
||||
const InputSection *isec;
|
||||
|
||||
public:
|
||||
explicit BPSectionMacho(const InputSection *sec) : isec(sec) {}
|
||||
|
||||
const void *getSection() const override { return isec; }
|
||||
|
||||
uint64_t getSize() const override { return isec->getSize(); }
|
||||
|
||||
bool isCodeSection() const override { return macho::isCodeSection(isec); }
|
||||
|
||||
SmallVector<std::unique_ptr<BPSymbol>> getSymbols() const override {
|
||||
SmallVector<std::unique_ptr<BPSymbol>> symbols;
|
||||
for (auto *sym : isec->symbols)
|
||||
if (auto *d = llvm::dyn_cast_or_null<Defined>(sym))
|
||||
symbols.emplace_back(std::make_unique<BPSymbolMacho>(d));
|
||||
return symbols;
|
||||
}
|
||||
|
||||
// Linkage names can be prefixed with "_" or "l_" on Mach-O. See
|
||||
// Mangler::getNameWithPrefix() for details.
|
||||
std::optional<StringRef>
|
||||
getResolvedLinkageName(llvm::StringRef name) const override {
|
||||
if (name.consume_front("_") || name.consume_front("l_"))
|
||||
return name;
|
||||
return {};
|
||||
}
|
||||
|
||||
void getSectionHashes(llvm::SmallVectorImpl<uint64_t> &hashes,
|
||||
const llvm::DenseMap<const void *, uint64_t>
|
||||
§ionToIdx) const override {
|
||||
constexpr unsigned windowSize = 4;
|
||||
|
||||
// Calculate content hashes: k-mers and the last k-1 bytes.
|
||||
ArrayRef<uint8_t> data = isec->data;
|
||||
if (data.size() >= windowSize)
|
||||
for (size_t i = 0; i <= data.size() - windowSize; ++i)
|
||||
hashes.push_back(llvm::support::endian::read32le(data.data() + i));
|
||||
for (uint8_t byte : data.take_back(windowSize - 1))
|
||||
hashes.push_back(byte);
|
||||
|
||||
// Calculate relocation hashes
|
||||
for (const auto &r : isec->relocs) {
|
||||
if (r.length == 0 || r.referent.isNull() || r.offset >= data.size())
|
||||
continue;
|
||||
|
||||
uint64_t relocHash = getRelocHash(r, sectionToIdx);
|
||||
uint32_t start = (r.offset < windowSize) ? 0 : r.offset - windowSize + 1;
|
||||
for (uint32_t i = start; i < r.offset + r.length; i++) {
|
||||
auto window = data.drop_front(i).take_front(windowSize);
|
||||
hashes.push_back(xxh3_64bits(window) ^ relocHash);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::sort(hashes);
|
||||
hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end());
|
||||
}
|
||||
|
||||
private:
|
||||
static uint64_t
|
||||
getRelocHash(const Reloc &reloc,
|
||||
const llvm::DenseMap<const void *, uint64_t> §ionToIdx) {
|
||||
auto *isec = reloc.getReferentInputSection();
|
||||
std::optional<uint64_t> sectionIdx;
|
||||
if (auto it = sectionToIdx.find(isec); it != sectionToIdx.end())
|
||||
sectionIdx = it->second;
|
||||
uint64_t kind = -1, value = 0;
|
||||
if (isec)
|
||||
kind = uint64_t(isec->kind());
|
||||
|
||||
if (auto *sym = reloc.referent.dyn_cast<Symbol *>()) {
|
||||
kind = (kind << 8) | uint8_t(sym->kind());
|
||||
if (auto *d = llvm::dyn_cast<Defined>(sym))
|
||||
value = d->value;
|
||||
}
|
||||
return llvm::stable_hash_combine(kind, sectionIdx.value_or(0), value,
|
||||
reloc.addend);
|
||||
}
|
||||
};
|
||||
|
||||
/// Run Balanced Partitioning to find the optimal function and data order to
|
||||
/// improve startup time and compressed size.
|
||||
///
|
||||
/// It is important that .subsections_via_symbols is used to ensure functions
|
||||
/// and data are in their own sections and thus can be reordered.
|
||||
llvm::DenseMap<const lld::macho::InputSection *, int>
|
||||
llvm::DenseMap<const InputSection *, int>
|
||||
runBalancedPartitioning(llvm::StringRef profilePath,
|
||||
bool forFunctionCompression, bool forDataCompression,
|
||||
bool compressionSortStartupFunctions, bool verbose);
|
||||
|
@ -50,6 +50,7 @@ add_lld_library(lldMachO
|
||||
Object
|
||||
Option
|
||||
Passes
|
||||
ProfileData
|
||||
Support
|
||||
TargetParser
|
||||
TextAPI
|
||||
|
@ -1,70 +0,0 @@
|
||||
//===- BPSectionOrdererBase.h ---------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the common interfaces which may be used by
|
||||
// BPSectionOrderer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_COMMON_BP_SECTION_ORDERER_BASE_H
|
||||
#define LLD_COMMON_BP_SECTION_ORDERER_BASE_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace lld {
|
||||
|
||||
class BPSymbol {
|
||||
|
||||
public:
|
||||
virtual ~BPSymbol() = default;
|
||||
virtual llvm::StringRef getName() const = 0;
|
||||
virtual std::optional<uint64_t> getValue() const = 0;
|
||||
virtual std::optional<uint64_t> getSize() const = 0;
|
||||
};
|
||||
|
||||
class BPSectionBase {
|
||||
public:
|
||||
virtual ~BPSectionBase() = default;
|
||||
virtual uint64_t getSize() const = 0;
|
||||
virtual bool isCodeSection() const = 0;
|
||||
virtual llvm::SmallVector<std::unique_ptr<BPSymbol>> getSymbols() const = 0;
|
||||
virtual const void *getSection() const = 0;
|
||||
virtual void getSectionHashes(
|
||||
llvm::SmallVectorImpl<uint64_t> &hashes,
|
||||
const llvm::DenseMap<const void *, uint64_t> §ionToIdx) const = 0;
|
||||
virtual std::optional<llvm::StringRef>
|
||||
getResolvedLinkageName(llvm::StringRef name) const = 0;
|
||||
|
||||
/// Symbols can be appended with "(.__uniq.xxxx)?.llvm.yyyy" where "xxxx" and
|
||||
/// "yyyy" are numbers that could change between builds. We need to use the
|
||||
/// root symbol name before this suffix so these symbols can be matched with
|
||||
/// profiles which may have different suffixes.
|
||||
static llvm::StringRef getRootSymbol(llvm::StringRef Name) {
|
||||
auto [P0, S0] = Name.rsplit(".llvm.");
|
||||
auto [P1, S1] = P0.rsplit(".__uniq.");
|
||||
return P1;
|
||||
}
|
||||
|
||||
/// Reorders sections using balanced partitioning algorithm based on profile
|
||||
/// data.
|
||||
static llvm::DenseMap<const BPSectionBase *, int>
|
||||
reorderSectionsByBalancedPartitioning(
|
||||
llvm::StringRef profilePath, bool forFunctionCompression,
|
||||
bool forDataCompression, bool compressionSortStartupFunctions,
|
||||
bool verbose,
|
||||
llvm::SmallVector<std::unique_ptr<BPSectionBase>> &inputSections);
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
@ -1,31 +1,76 @@
|
||||
//===- BPSectionOrdererBase.cpp -------------------------------------------===//
|
||||
//===- BPSectionOrdererBase.inc ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the common BPSectionOrderer interface using the Curiously
|
||||
// Recurring Template Pattern and dispatches to the BalancedPartitioning
|
||||
// algorithm implemented in LLVMSupport. The optimized section layout attempts
|
||||
// to group similar sections together (resulting in a smaller compressed app
|
||||
// size) and utilize a temporal profile file to reduce page faults during
|
||||
// program startup.
|
||||
//
|
||||
// Clients should derive from BPOrderer, providing concrete implementations for
|
||||
// section and symbol representations. Include this file in a .cpp file to
|
||||
// specialize the template for the derived class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Common/BPSectionOrdererBase.h"
|
||||
#include "lld/Common/ErrorHandler.h"
|
||||
#include "llvm/ADT/CachedHashString.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/ProfileData/InstrProfReader.h"
|
||||
#include "llvm/Support/BalancedPartitioning.h"
|
||||
#include "llvm/Support/TimeProfiler.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#define DEBUG_TYPE "bp-section-orderer"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace lld;
|
||||
|
||||
namespace lld {
|
||||
template <class D> struct BPOrdererTraits;
|
||||
|
||||
template <class D> struct BPOrderer {
|
||||
using Section = typename BPOrdererTraits<D>::Section;
|
||||
using Symbol = typename BPOrdererTraits<D>::Symbol;
|
||||
|
||||
// Compute a section order using the Balanced Partitioning algorithm.
|
||||
//
|
||||
// * for*Compresion: Improve Lempel-Ziv compression by grouping
|
||||
// similar sections together.
|
||||
// * profilePath: Utilize a temporal profile file to reduce page faults during
|
||||
// program startup.
|
||||
// * compressionSortStartupFunctions: if profilePath is specified, allocate
|
||||
// extra utility vertices to prioritize nearby function similarity.
|
||||
static auto
|
||||
computeOrder(llvm::StringRef profilePath, bool forFunctionCompression,
|
||||
bool forDataCompression, bool compressionSortStartupFunctions,
|
||||
bool verbose, llvm::ArrayRef<Section *> sections,
|
||||
const DenseMap<CachedHashStringRef, DenseSet<unsigned>>
|
||||
&rootSymbolToSectionIdxs)
|
||||
-> llvm::DenseMap<const Section *, int>;
|
||||
};
|
||||
} // namespace lld
|
||||
|
||||
using UtilityNodes = SmallVector<BPFunctionNode::UtilityNodeT>;
|
||||
|
||||
template <class D>
|
||||
static SmallVector<std::pair<unsigned, UtilityNodes>> getUnsForCompression(
|
||||
ArrayRef<const BPSectionBase *> sections,
|
||||
ArrayRef<const typename D::Section *> sections,
|
||||
const DenseMap<const void *, uint64_t> §ionToIdx,
|
||||
ArrayRef<unsigned> sectionIdxs,
|
||||
DenseMap<unsigned, SmallVector<unsigned>> *duplicateSectionIdxs,
|
||||
@ -38,7 +83,7 @@ static SmallVector<std::pair<unsigned, UtilityNodes>> getUnsForCompression(
|
||||
|
||||
for (unsigned sectionIdx : sectionIdxs) {
|
||||
const auto *isec = sections[sectionIdx];
|
||||
isec->getSectionHashes(hashes, sectionToIdx);
|
||||
D::getSectionHashes(*isec, hashes, sectionToIdx);
|
||||
sectionHashes.emplace_back(sectionIdx, std::move(hashes));
|
||||
hashes.clear();
|
||||
}
|
||||
@ -96,36 +141,27 @@ static SmallVector<std::pair<unsigned, UtilityNodes>> getUnsForCompression(
|
||||
return sectionUns;
|
||||
}
|
||||
|
||||
llvm::DenseMap<const BPSectionBase *, int>
|
||||
BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
llvm::StringRef profilePath, bool forFunctionCompression,
|
||||
bool forDataCompression, bool compressionSortStartupFunctions, bool verbose,
|
||||
SmallVector<std::unique_ptr<BPSectionBase>> &inputSections) {
|
||||
TimeTraceScope timeScope("Setup Balanced Partitioning");
|
||||
SmallVector<const BPSectionBase *> sections;
|
||||
DenseMap<const void *, uint64_t> sectionToIdx;
|
||||
StringMap<DenseSet<unsigned>> symbolToSectionIdxs;
|
||||
/// Symbols can be appended with "(.__uniq.xxxx)?.llvm.yyyy" where "xxxx" and
|
||||
/// "yyyy" are numbers that could change between builds. We need to use the
|
||||
/// root symbol name before this suffix so these symbols can be matched with
|
||||
/// profiles which may have different suffixes.
|
||||
inline StringRef getRootSymbol(StringRef name) {
|
||||
auto [P0, S0] = name.rsplit(".llvm.");
|
||||
auto [P1, S1] = P0.rsplit(".__uniq.");
|
||||
return P1;
|
||||
}
|
||||
|
||||
// Process input sections
|
||||
for (const auto &isec : inputSections) {
|
||||
unsigned sectionIdx = sections.size();
|
||||
sectionToIdx.try_emplace(isec->getSection(), sectionIdx);
|
||||
sections.emplace_back(isec.get());
|
||||
for (auto &sym : isec->getSymbols())
|
||||
symbolToSectionIdxs[sym->getName()].insert(sectionIdx);
|
||||
}
|
||||
StringMap<DenseSet<unsigned>> rootSymbolToSectionIdxs;
|
||||
for (auto &entry : symbolToSectionIdxs) {
|
||||
StringRef name = entry.getKey();
|
||||
auto §ionIdxs = entry.getValue();
|
||||
name = BPSectionBase::getRootSymbol(name);
|
||||
rootSymbolToSectionIdxs[name].insert(sectionIdxs.begin(),
|
||||
sectionIdxs.end());
|
||||
if (auto resolvedLinkageName =
|
||||
sections[*sectionIdxs.begin()]->getResolvedLinkageName(name))
|
||||
rootSymbolToSectionIdxs[resolvedLinkageName.value()].insert(
|
||||
sectionIdxs.begin(), sectionIdxs.end());
|
||||
}
|
||||
template <class D>
|
||||
auto BPOrderer<D>::computeOrder(
|
||||
StringRef profilePath, bool forFunctionCompression, bool forDataCompression,
|
||||
bool compressionSortStartupFunctions, bool verbose,
|
||||
ArrayRef<Section *> sections,
|
||||
const DenseMap<CachedHashStringRef, DenseSet<unsigned>>
|
||||
&rootSymbolToSectionIdxs) -> DenseMap<const Section *, int> {
|
||||
TimeTraceScope timeScope("Setup Balanced Partitioning");
|
||||
DenseMap<const void *, uint64_t> sectionToIdx;
|
||||
for (auto [i, isec] : llvm::enumerate(sections))
|
||||
sectionToIdx.try_emplace(isec, i);
|
||||
|
||||
BPFunctionNode::UtilityNodeT maxUN = 0;
|
||||
DenseMap<unsigned, UtilityNodes> startupSectionIdxUNs;
|
||||
@ -150,17 +186,18 @@ BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
size_t cutoffTimestamp = 1;
|
||||
auto &trace = traces[traceIdx].FunctionNameRefs;
|
||||
for (size_t timestamp = 0; timestamp < trace.size(); timestamp++) {
|
||||
auto [Filename, ParsedFuncName] = getParsedIRPGOName(
|
||||
auto [_, parsedFuncName] = getParsedIRPGOName(
|
||||
reader->getSymtab().getFuncOrVarName(trace[timestamp]));
|
||||
ParsedFuncName = BPSectionBase::getRootSymbol(ParsedFuncName);
|
||||
parsedFuncName = getRootSymbol(parsedFuncName);
|
||||
|
||||
auto sectionIdxsIt = rootSymbolToSectionIdxs.find(ParsedFuncName);
|
||||
auto sectionIdxsIt =
|
||||
rootSymbolToSectionIdxs.find(CachedHashStringRef(parsedFuncName));
|
||||
if (sectionIdxsIt == rootSymbolToSectionIdxs.end())
|
||||
continue;
|
||||
auto §ionIdxs = sectionIdxsIt->getValue();
|
||||
auto §ionIdxs = sectionIdxsIt->second;
|
||||
// If the same symbol is found in multiple sections, they might be
|
||||
// identical, so we arbitrarily use the size from the first section.
|
||||
currentSize += sections[*sectionIdxs.begin()]->getSize();
|
||||
currentSize += D::getSize(*sections[*sectionIdxs.begin()]);
|
||||
|
||||
// Since BalancedPartitioning is sensitive to the initial order, we need
|
||||
// to explicitly define it to be ordered by earliest timestamp.
|
||||
@ -193,7 +230,7 @@ BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
if (startupSectionIdxUNs.count(sectionIdx))
|
||||
continue;
|
||||
const auto *isec = sections[sectionIdx];
|
||||
if (isec->isCodeSection()) {
|
||||
if (D::isCodeSection(*isec)) {
|
||||
if (forFunctionCompression)
|
||||
sectionIdxsForFunctionCompression.push_back(sectionIdx);
|
||||
} else {
|
||||
@ -207,8 +244,8 @@ BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
for (auto &[sectionIdx, uns] : startupSectionIdxUNs)
|
||||
startupIdxs.push_back(sectionIdx);
|
||||
auto unsForStartupFunctionCompression =
|
||||
getUnsForCompression(sections, sectionToIdx, startupIdxs,
|
||||
/*duplicateSectionIdxs=*/nullptr, maxUN);
|
||||
getUnsForCompression<D>(sections, sectionToIdx, startupIdxs,
|
||||
/*duplicateSectionIdxs=*/nullptr, maxUN);
|
||||
for (auto &[sectionIdx, compressionUns] :
|
||||
unsForStartupFunctionCompression) {
|
||||
auto &uns = startupSectionIdxUNs[sectionIdx];
|
||||
@ -221,10 +258,10 @@ BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
// Map a section index (order directly) to a list of duplicate section indices
|
||||
// (not ordered directly).
|
||||
DenseMap<unsigned, SmallVector<unsigned>> duplicateSectionIdxs;
|
||||
auto unsForFunctionCompression = getUnsForCompression(
|
||||
auto unsForFunctionCompression = getUnsForCompression<D>(
|
||||
sections, sectionToIdx, sectionIdxsForFunctionCompression,
|
||||
&duplicateSectionIdxs, maxUN);
|
||||
auto unsForDataCompression = getUnsForCompression(
|
||||
auto unsForDataCompression = getUnsForCompression<D>(
|
||||
sections, sectionToIdx, sectionIdxsForDataCompression,
|
||||
&duplicateSectionIdxs, maxUN);
|
||||
|
||||
@ -263,7 +300,7 @@ BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
unsigned numDuplicateCodeSections = 0;
|
||||
unsigned numDataCompressionSections = 0;
|
||||
unsigned numDuplicateDataSections = 0;
|
||||
SetVector<const BPSectionBase *> orderedSections;
|
||||
SetVector<const Section *> orderedSections;
|
||||
// Order startup functions,
|
||||
for (auto &node : nodesForStartup) {
|
||||
const auto *isec = sections[node.Id];
|
||||
@ -320,23 +357,22 @@ BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
const uint64_t pageSize = (1 << 14);
|
||||
uint64_t currentAddress = 0;
|
||||
for (const auto *isec : orderedSections) {
|
||||
for (auto &sym : isec->getSymbols()) {
|
||||
uint64_t startAddress = currentAddress + sym->getValue().value_or(0);
|
||||
uint64_t endAddress = startAddress + sym->getSize().value_or(0);
|
||||
for (auto *sym : D::getSymbols(*isec)) {
|
||||
uint64_t startAddress = currentAddress + D::getSymValue(*sym);
|
||||
uint64_t endAddress = startAddress + D::getSymSize(*sym);
|
||||
uint64_t firstPage = startAddress / pageSize;
|
||||
// I think the kernel might pull in a few pages when one it touched,
|
||||
// so it might be more accurate to force lastPage to be aligned by
|
||||
// 4?
|
||||
uint64_t lastPage = endAddress / pageSize;
|
||||
StringRef rootSymbol = sym->getName();
|
||||
rootSymbol = BPSectionBase::getRootSymbol(rootSymbol);
|
||||
StringRef rootSymbol = D::getSymName(*sym);
|
||||
rootSymbol = getRootSymbol(rootSymbol);
|
||||
symbolToPageNumbers.try_emplace(rootSymbol, firstPage, lastPage);
|
||||
if (auto resolvedLinkageName =
|
||||
isec->getResolvedLinkageName(rootSymbol))
|
||||
if (auto resolvedLinkageName = D::getResolvedLinkageName(rootSymbol))
|
||||
symbolToPageNumbers.try_emplace(resolvedLinkageName.value(),
|
||||
firstPage, lastPage);
|
||||
}
|
||||
currentAddress += isec->getSize();
|
||||
currentAddress += D::getSize(*isec);
|
||||
}
|
||||
|
||||
// The area under the curve F where F(t) is the total number of page
|
||||
@ -348,7 +384,7 @@ BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
auto traceId = trace.FunctionNameRefs[step];
|
||||
auto [Filename, ParsedFuncName] =
|
||||
getParsedIRPGOName(reader->getSymtab().getFuncOrVarName(traceId));
|
||||
ParsedFuncName = BPSectionBase::getRootSymbol(ParsedFuncName);
|
||||
ParsedFuncName = getRootSymbol(ParsedFuncName);
|
||||
auto it = symbolToPageNumbers.find(ParsedFuncName);
|
||||
if (it != symbolToPageNumbers.end()) {
|
||||
auto &[firstPage, lastPage] = it->getValue();
|
||||
@ -363,7 +399,7 @@ BPSectionBase::reorderSectionsByBalancedPartitioning(
|
||||
}
|
||||
}
|
||||
|
||||
DenseMap<const BPSectionBase *, int> sectionPriorities;
|
||||
DenseMap<const Section *, int> sectionPriorities;
|
||||
int prio = -orderedSections.size();
|
||||
for (const auto *isec : orderedSections)
|
||||
sectionPriorities[isec] = prio++;
|
Loading…
x
Reference in New Issue
Block a user