Files
gps/tools/local/circt/include/llvm/ProfileData/DataAccessProf.h
T
2026-07-12 11:01:51 +03:00

228 lines
8.6 KiB
C++

//===- DataAccessProf.h - Data access profile format support ---------*- 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 contains support to construct and use data access profiles.
//
// For the original RFC of this pass please see
// https://discourse.llvm.org/t/rfc-profile-guided-static-data-partitioning/83744
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_PROFILEDATA_DATAACCESSPROF_H_
#define LLVM_PROFILEDATA_DATAACCESSPROF_H_
#include "llvm/ADT/DenseMapInfoVariant.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/StringSaver.h"
#include <cstdint>
#include <optional>
#include <variant>
namespace llvm {
namespace memprof {
/// The location of data in the source code. Used by profile lookup API.
struct SourceLocation {
SourceLocation(StringRef FileNameRef, uint32_t Line)
: FileName(FileNameRef.str()), Line(Line) {}
// Empty constructor is used in yaml conversion.
SourceLocation() = default;
/// The filename where the data is located.
std::string FileName;
/// The line number in the source code.
uint32_t Line;
};
namespace internal {
// Conceptually similar to SourceLocation except that FileNames are StringRef of
// which strings are owned by `DataAccessProfData`. Used by `DataAccessProfData`
// to represent data locations internally.
struct SourceLocationRef {
SourceLocationRef(StringRef FileNameRef, uint32_t Line)
: FileName(FileNameRef), Line(Line) {}
// The filename where the data is located.
StringRef FileName;
// The line number in the source code.
uint32_t Line;
};
// The data access profiles for a symbol. Used by `DataAccessProfData`
// to represent records internally.
struct DataAccessProfRecordRef {
DataAccessProfRecordRef(uint64_t SymbolID, uint64_t AccessCount,
bool IsStringLiteral)
: SymbolID(SymbolID), AccessCount(AccessCount),
IsStringLiteral(IsStringLiteral) {}
// Represents a data symbol. The semantic comes in two forms: a symbol index
// for symbol name if `IsStringLiteral` is false, or the hash of a string
// content if `IsStringLiteral` is true. For most of the symbolizable static
// data, the mangled symbol names remain stable relative to the source code
// and therefore used to identify symbols across binary releases. String
// literals have unstable name patterns like `.str.N[.llvm.hash]`, so we use
// the content hash instead. This is a required field.
uint64_t SymbolID;
// The access count of symbol. Required.
uint64_t AccessCount;
// True iff this is a record for string literal (symbols with name pattern
// `.str.*` in the symbol table). Required.
bool IsStringLiteral;
// The locations of data in the source code. Optional.
llvm::SmallVector<SourceLocationRef, 0> Locations;
};
} // namespace internal
// SymbolID is either a string representing symbol name if the symbol has
// stable mangled name relative to source code, or a uint64_t representing the
// content hash of a string literal (with unstable name patterns like
// `.str.N[.llvm.hash]`). The StringRef is owned by the class's saver object.
using SymbolHandleRef = std::variant<StringRef, uint64_t>;
// The senamtic is the same as `SymbolHandleRef` above. The strings are owned.
using SymbolHandle = std::variant<std::string, uint64_t>;
/// The data access profiles for a symbol.
struct DataAccessProfRecord {
public:
DataAccessProfRecord(SymbolHandleRef SymHandleRef, uint64_t AccessCount,
ArrayRef<internal::SourceLocationRef> LocRefs)
: AccessCount(AccessCount) {
if (std::holds_alternative<StringRef>(SymHandleRef)) {
SymHandle = std::get<StringRef>(SymHandleRef).str();
} else
SymHandle = std::get<uint64_t>(SymHandleRef);
for (auto Loc : LocRefs)
Locations.emplace_back(Loc.FileName, Loc.Line);
}
// Empty constructor is used in yaml conversion.
DataAccessProfRecord() = default;
SymbolHandle SymHandle;
uint64_t AccessCount = 0;
// The locations of data in the source code. Optional.
SmallVector<SourceLocation> Locations;
};
/// Encapsulates the data access profile data and the methods to operate on
/// it. This class provides profile look-up, serialization and
/// deserialization.
class DataAccessProfData {
public:
// Use MapVector to keep input order of strings for serialization and
// deserialization.
using StringToIndexMap = llvm::MapVector<StringRef, uint64_t>;
DataAccessProfData() : Saver(Allocator) {}
/// Serialize profile data to the output stream.
/// Storage layout:
/// - Serialized strings.
/// - The encoded hashes.
/// - Records.
LLVM_ABI Error serialize(ProfOStream &OS) const;
/// Deserialize this class from the given buffer.
LLVM_ABI Error deserialize(const unsigned char *&Ptr);
/// Returns a profile record for \p SymbolID, or std::nullopt if there
/// isn't a record. Internally, this function will canonicalize the symbol
/// name before the lookup.
LLVM_ABI std::optional<DataAccessProfRecord>
getProfileRecord(const SymbolHandleRef SymID) const;
/// Returns true if \p SymID is seen in profiled binaries and cold.
LLVM_ABI bool isKnownColdSymbol(const SymbolHandleRef SymID) const;
/// Methods to set symbolized data access profile. Returns error if
/// duplicated symbol names or content hashes are seen. The user of this
/// class should aggregate counters that correspond to the same symbol name
/// or with the same string literal hash before calling 'set*' methods.
LLVM_ABI Error setDataAccessProfile(SymbolHandleRef SymbolID,
uint64_t AccessCount);
/// Similar to the method above, for records with \p Locations representing
/// the `filename:line` where this symbol shows up. Note because of linker's
/// merge of identical symbols (e.g., unnamed_addr string literals), one
/// symbol is likely to have multiple locations.
LLVM_ABI Error setDataAccessProfile(SymbolHandleRef SymbolID,
uint64_t AccessCount,
ArrayRef<SourceLocation> Locations);
/// Add a symbol that's seen in the profiled binary without samples.
LLVM_ABI Error addKnownSymbolWithoutSamples(SymbolHandleRef SymbolID);
/// The following methods return array reference for various internal data
/// structures.
ArrayRef<StringToIndexMap::value_type> getStrToIndexMapRef() const {
return StrToIndexMap.getArrayRef();
}
ArrayRef<
MapVector<SymbolHandleRef, internal::DataAccessProfRecordRef>::value_type>
getRecords() const {
return Records.getArrayRef();
}
ArrayRef<StringRef> getKnownColdSymbols() const {
return KnownColdSymbols.getArrayRef();
}
ArrayRef<uint64_t> getKnownColdHashes() const {
return KnownColdHashes.getArrayRef();
}
[[nodiscard]] bool empty() const {
return Records.empty() && KnownColdSymbols.empty() &&
KnownColdHashes.empty();
}
private:
/// Serialize the symbol strings into the output stream.
Error serializeSymbolsAndFilenames(ProfOStream &OS) const;
/// Deserialize the symbol strings from \p Ptr and increment \p Ptr to the
/// start of the next payload.
Error deserializeSymbolsAndFilenames(const unsigned char *&Ptr,
const uint64_t NumSampledSymbols,
const uint64_t NumColdKnownSymbols);
/// Decode the records and increment \p Ptr to the start of the next
/// payload.
Error deserializeRecords(const unsigned char *&Ptr);
/// A helper function to compute a storage index for \p SymbolID.
uint64_t getEncodedIndex(const SymbolHandleRef SymbolID) const;
// Keeps owned copies of the input strings.
// NOTE: Keep `Saver` initialized before other class members that reference
// its string copies and destructed after they are destructed.
llvm::BumpPtrAllocator Allocator;
llvm::UniqueStringSaver Saver;
// `Records` stores the records.
MapVector<SymbolHandleRef, internal::DataAccessProfRecordRef> Records;
StringToIndexMap StrToIndexMap;
llvm::SetVector<uint64_t> KnownColdHashes;
llvm::SetVector<StringRef> KnownColdSymbols;
};
} // namespace memprof
} // namespace llvm
#endif // LLVM_PROFILEDATA_DATAACCESSPROF_H_