Skip to content

[MemProf] Summary section cleanup (NFC) #142003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion llvm/include/llvm/ProfileData/IndexedMemProfData.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,6 @@ Error writeMemProf(
ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema,
std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData,
memprof::MemProfSummary *MemProfSum);
std::unique_ptr<memprof::MemProfSummary> MemProfSum);
} // namespace llvm
#endif
35 changes: 35 additions & 0 deletions llvm/include/llvm/ProfileData/MemProfCommon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===- MemProfCommon.h - MemProf common utilities ---------------*- 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 MemProf common utilities.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_PROFILEDATA_MEMPROFCOMMON_H
#define LLVM_PROFILEDATA_MEMPROFCOMMON_H

#include "llvm/IR/ModuleSummaryIndex.h"

namespace llvm {
namespace memprof {

struct Frame;

/// Return the allocation type for a given set of memory profile values.
AllocationType getAllocType(uint64_t TotalLifetimeAccessDensity,
uint64_t AllocCount, uint64_t TotalLifetime);

/// Helper to generate a single hash id for a given callstack, used for emitting
/// matching statistics and useful for uniquing such statistics across modules.
/// Also used to dedup contexts when computing the summary.
uint64_t computeFullStackId(ArrayRef<Frame> CallStack);

} // namespace memprof
} // namespace llvm

#endif // LLVM_PROFILEDATA_MEMPROFCOMMON_H
13 changes: 1 addition & 12 deletions llvm/include/llvm/ProfileData/MemProfSummary.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,18 @@
//
//===----------------------------------------------------------------------===//
//
// This file contains MemProf summary support and related interfaces.
// This file contains MemProf summary support.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_PROFILEDATA_MEMPROFSUMMARY_H
#define LLVM_PROFILEDATA_MEMPROFSUMMARY_H

#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ProfileData/MemProf.h"

namespace llvm {
namespace memprof {

/// Return the allocation type for a given set of memory profile values.
AllocationType getAllocType(uint64_t TotalLifetimeAccessDensity,
uint64_t AllocCount, uint64_t TotalLifetime);

/// Helper to generate a single hash id for a given callstack, used for emitting
/// matching statistics and useful for uniquing such statistics across modules.
/// Also used to dedup contexts when computing the summary.
uint64_t computeFullStackId(ArrayRef<Frame> CallStack);

class MemProfSummary {
private:
/// The number of summary fields below, which is used to enable some forwards
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/ProfileData/MemProfSummaryBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ class MemProfSummaryBuilder {
// instances of the same allocations.
DenseSet<uint64_t> Contexts;

// Helper called by the public raw and indexed profile addRecord interfaces.
void addRecord(uint64_t, const PortableMemInfoBlock &);

protected:
uint64_t MaxColdTotalSize = 0;
uint64_t MaxWarmTotalSize = 0;
uint64_t MaxHotTotalSize = 0;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/ProfileData/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_llvm_component_library(LLVMProfileData
InstrProfWriter.cpp
ItaniumManglingCanonicalizer.cpp
MemProf.cpp
MemProfCommon.cpp
MemProfReader.cpp
MemProfRadixTree.cpp
MemProfSummary.cpp
Expand Down
11 changes: 6 additions & 5 deletions llvm/lib/ProfileData/IndexedMemProfData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ static Error writeMemProfRadixTreeBased(
memprof::IndexedVersion Version, bool MemProfFullSchema,
std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData =
nullptr,
memprof::MemProfSummary *MemProfSum = nullptr) {
std::unique_ptr<memprof::MemProfSummary> MemProfSum = nullptr) {
assert((Version == memprof::Version3 || Version == memprof::Version4) &&
"Unsupported version for radix tree format");

Expand Down Expand Up @@ -303,26 +303,27 @@ static Error writeMemProfV4(
ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
bool MemProfFullSchema,
std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData,
memprof::MemProfSummary *MemProfSum) {
std::unique_ptr<memprof::MemProfSummary> MemProfSum) {
return writeMemProfRadixTreeBased(
OS, MemProfData, memprof::Version4, MemProfFullSchema,
std::move(DataAccessProfileData), MemProfSum);
std::move(DataAccessProfileData), std::move(MemProfSum));
}

// Write out the MemProf data in a requested version.
Error writeMemProf(
ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema,
std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData,
memprof::MemProfSummary *MemProfSum) {
std::unique_ptr<memprof::MemProfSummary> MemProfSum) {
switch (MemProfVersionRequested) {
case memprof::Version2:
return writeMemProfV2(OS, MemProfData, MemProfFullSchema);
case memprof::Version3:
return writeMemProfV3(OS, MemProfData, MemProfFullSchema);
case memprof::Version4:
return writeMemProfV4(OS, MemProfData, MemProfFullSchema,
std::move(DataAccessProfileData), MemProfSum);
std::move(DataAccessProfileData),
std::move(MemProfSum));
}

return make_error<InstrProfError>(
Expand Down
5 changes: 1 addition & 4 deletions llvm/lib/ProfileData/InstrProfWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,12 +618,9 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
if (static_cast<bool>(ProfileKind & InstrProfKind::MemProf)) {
MemProfSectionStart = OS.tell();

// Get the finalized MemProf summary that was built when adding records.
auto MemProfSum = MemProfSumBuilder.getSummary();

if (auto E = writeMemProf(
OS, MemProfData, MemProfVersionRequested, MemProfFullSchema,
std::move(DataAccessProfileData), MemProfSum.get()))
std::move(DataAccessProfileData), MemProfSumBuilder.getSummary()))
return E;
}

Expand Down
81 changes: 81 additions & 0 deletions llvm/lib/ProfileData/MemProfCommon.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//=-- MemProfCommon.cpp - MemProf common utilities ---------------=//
//
// 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 MemProf common utilities.
//
//===----------------------------------------------------------------------===//

#include "llvm/ProfileData/MemProfCommon.h"
#include "llvm/ProfileData/MemProf.h"
#include "llvm/Support/BLAKE3.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/HashBuilder.h"

using namespace llvm;
using namespace llvm::memprof;

// Upper bound on lifetime access density (accesses per byte per lifetime sec)
// for marking an allocation cold.
cl::opt<float> MemProfLifetimeAccessDensityColdThreshold(
"memprof-lifetime-access-density-cold-threshold", cl::init(0.05),
cl::Hidden,
cl::desc("The threshold the lifetime access density (accesses per byte per "
"lifetime sec) must be under to consider an allocation cold"));

// Lower bound on lifetime to mark an allocation cold (in addition to accesses
// per byte per sec above). This is to avoid pessimizing short lived objects.
cl::opt<unsigned> MemProfAveLifetimeColdThreshold(
"memprof-ave-lifetime-cold-threshold", cl::init(200), cl::Hidden,
cl::desc("The average lifetime (s) for an allocation to be considered "
"cold"));

// Lower bound on average lifetime accesses density (total life time access
// density / alloc count) for marking an allocation hot.
cl::opt<unsigned> MemProfMinAveLifetimeAccessDensityHotThreshold(
"memprof-min-ave-lifetime-access-density-hot-threshold", cl::init(1000),
cl::Hidden,
cl::desc("The minimum TotalLifetimeAccessDensity / AllocCount for an "
"allocation to be considered hot"));

cl::opt<bool>
MemProfUseHotHints("memprof-use-hot-hints", cl::init(false), cl::Hidden,
cl::desc("Enable use of hot hints (only supported for "
"unambigously hot allocations)"));

AllocationType llvm::memprof::getAllocType(uint64_t TotalLifetimeAccessDensity,
uint64_t AllocCount,
uint64_t TotalLifetime) {
// The access densities are multiplied by 100 to hold 2 decimal places of
// precision, so need to divide by 100.
if (((float)TotalLifetimeAccessDensity) / AllocCount / 100 <
MemProfLifetimeAccessDensityColdThreshold
// Lifetime is expected to be in ms, so convert the threshold to ms.
&& ((float)TotalLifetime) / AllocCount >=
MemProfAveLifetimeColdThreshold * 1000)
return AllocationType::Cold;

// The access densities are multiplied by 100 to hold 2 decimal places of
// precision, so need to divide by 100.
if (MemProfUseHotHints &&
((float)TotalLifetimeAccessDensity) / AllocCount / 100 >
MemProfMinAveLifetimeAccessDensityHotThreshold)
return AllocationType::Hot;

return AllocationType::NotCold;
}

uint64_t llvm::memprof::computeFullStackId(ArrayRef<Frame> CallStack) {
llvm::HashBuilder<llvm::TruncatedBLAKE3<8>, llvm::endianness::little>
HashBuilder;
for (auto &F : CallStack)
HashBuilder.add(F.Function, F.LineOffset, F.Column);
llvm::BLAKE3Result<8> Hash = HashBuilder.final();
uint64_t Id;
std::memcpy(&Id, Hash.data(), sizeof(Hash));
return Id;
}
66 changes: 1 addition & 65 deletions llvm/lib/ProfileData/MemProfSummary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,79 +6,15 @@
//
//===----------------------------------------------------------------------===//
//
// This file contains MemProf summary support and related interfaces.
// This file contains MemProf summary support.
//
//===----------------------------------------------------------------------===//

#include "llvm/ProfileData/MemProfSummary.h"
#include "llvm/Support/BLAKE3.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/HashBuilder.h"

using namespace llvm;
using namespace llvm::memprof;

// Upper bound on lifetime access density (accesses per byte per lifetime sec)
// for marking an allocation cold.
cl::opt<float> MemProfLifetimeAccessDensityColdThreshold(
"memprof-lifetime-access-density-cold-threshold", cl::init(0.05),
cl::Hidden,
cl::desc("The threshold the lifetime access density (accesses per byte per "
"lifetime sec) must be under to consider an allocation cold"));

// Lower bound on lifetime to mark an allocation cold (in addition to accesses
// per byte per sec above). This is to avoid pessimizing short lived objects.
cl::opt<unsigned> MemProfAveLifetimeColdThreshold(
"memprof-ave-lifetime-cold-threshold", cl::init(200), cl::Hidden,
cl::desc("The average lifetime (s) for an allocation to be considered "
"cold"));

// Lower bound on average lifetime accesses density (total life time access
// density / alloc count) for marking an allocation hot.
cl::opt<unsigned> MemProfMinAveLifetimeAccessDensityHotThreshold(
"memprof-min-ave-lifetime-access-density-hot-threshold", cl::init(1000),
cl::Hidden,
cl::desc("The minimum TotalLifetimeAccessDensity / AllocCount for an "
"allocation to be considered hot"));

cl::opt<bool>
MemProfUseHotHints("memprof-use-hot-hints", cl::init(false), cl::Hidden,
cl::desc("Enable use of hot hints (only supported for "
"unambigously hot allocations)"));

AllocationType llvm::memprof::getAllocType(uint64_t TotalLifetimeAccessDensity,
uint64_t AllocCount,
uint64_t TotalLifetime) {
// The access densities are multiplied by 100 to hold 2 decimal places of
// precision, so need to divide by 100.
if (((float)TotalLifetimeAccessDensity) / AllocCount / 100 <
MemProfLifetimeAccessDensityColdThreshold
// Lifetime is expected to be in ms, so convert the threshold to ms.
&& ((float)TotalLifetime) / AllocCount >=
MemProfAveLifetimeColdThreshold * 1000)
return AllocationType::Cold;

// The access densities are multiplied by 100 to hold 2 decimal places of
// precision, so need to divide by 100.
if (MemProfUseHotHints &&
((float)TotalLifetimeAccessDensity) / AllocCount / 100 >
MemProfMinAveLifetimeAccessDensityHotThreshold)
return AllocationType::Hot;

return AllocationType::NotCold;
}

uint64_t llvm::memprof::computeFullStackId(ArrayRef<Frame> CallStack) {
llvm::HashBuilder<llvm::TruncatedBLAKE3<8>, llvm::endianness::little>
HashBuilder;
for (auto &F : CallStack)
HashBuilder.add(F.Function, F.LineOffset, F.Column);
llvm::BLAKE3Result<8> Hash = HashBuilder.final();
uint64_t Id;
std::memcpy(&Id, Hash.data(), sizeof(Hash));
return Id;
}

void MemProfSummary::printSummaryYaml(raw_ostream &OS) const {
// For now emit as YAML comments, since they aren't read on input.
OS << "---\n";
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/ProfileData/MemProfSummaryBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "llvm/ProfileData/MemProfSummaryBuilder.h"
#include "llvm/ProfileData/MemProfCommon.h"

using namespace llvm;
using namespace llvm::memprof;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#include "llvm/IR/Value.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/ProfileData/MemProfSummary.h"
#include "llvm/ProfileData/MemProfCommon.h"
#include "llvm/Support/BLAKE3.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
Expand Down
12 changes: 5 additions & 7 deletions llvm/unittests/ProfileData/MemProfTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,20 @@
#include "llvm/IR/Value.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/ProfileData/IndexedMemProfData.h"
#include "llvm/ProfileData/MemProfCommon.h"
#include "llvm/ProfileData/MemProfData.inc"
#include "llvm/ProfileData/MemProfRadixTree.h"
#include "llvm/ProfileData/MemProfReader.h"
#include "llvm/ProfileData/MemProfSummary.h"
#include "llvm/Support/raw_ostream.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include <initializer_list>

using namespace llvm;

extern cl::opt<float> MemProfLifetimeAccessDensityColdThreshold;
extern cl::opt<unsigned> MemProfAveLifetimeColdThreshold;
extern cl::opt<unsigned> MemProfMinAveLifetimeAccessDensityHotThreshold;
extern cl::opt<bool> MemProfUseHotHints;
extern llvm::cl::opt<float> MemProfLifetimeAccessDensityColdThreshold;
extern llvm::cl::opt<unsigned> MemProfAveLifetimeColdThreshold;
extern llvm::cl::opt<unsigned> MemProfMinAveLifetimeAccessDensityHotThreshold;
extern llvm::cl::opt<bool> MemProfUseHotHints;

namespace llvm {
namespace memprof {
Expand Down
Loading