Skip to content

Commit a212d8d

Browse files
committed
[MemProf] Memprof profile matching and annotation
Profile matching and IR annotation for memprof profiles. See also related RFCs: RFC: Sanitizer-based Heap Profiler [1] RFC: A binary serialization format for MemProf [2] RFC: IR metadata format for MemProf [3]* * Note that the IR metadata format has changed from the RFC during implementation, as described in the preceeding patch adding the basic metadata and verification support. The matching is performed during the normal PGO annotation phase, to ensure that the inlines applied in the IR at that point are a subset of the inlines in the profiled binary and thus reflected in the profile's call stacks. This is important because the call frames are associated with functions in the profile based on the inlining in the symbolized call stacks, and this simplifies locating the subset of profile data relevant for matching onto each function's IR. The PGOInstrumentationUse pass is enhanced to perform matching for whatever combination of memprof and regular PGO profile data exists in the profile. Using the utilities introduced in D128854: The memprof profile data for each context is converted to "cold" or "notcold" based on parameterized thresholds for size, access count, and lifetime. The memprof allocation contexts are trimmed to the minimal amount of context required to uniquely identify whether the context is cold or not cold. For allocations where all profiled contexts have the same allocation type, no memprof metadata is attached and instead the allocation call is directly annotated with an attribute specifying the alloction type. This is the same attributed that will be applied to allocation calls once cloned for different contexts, and later used during LibCall simplification to emit allocation hints [4]. Depends on D128141 and D128854. [1] https://lists.llvm.org/pipermail/llvm-dev/2020-June/142744.html [2] https://lists.llvm.org/pipermail/llvm-dev/2021-September/153007.html [3] https://discourse.llvm.org/t/rfc-ir-metadata-format-for-memprof/59165 [4] google/tcmalloc@ab87cf3 Differential Revision: https://reviews.llvm.org/D128142
1 parent 98907f8 commit a212d8d

File tree

13 files changed

+853
-3
lines changed

13 files changed

+853
-3
lines changed

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1306,7 +1306,10 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts,
13061306
}
13071307
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader =
13081308
std::move(ReaderOrErr.get());
1309-
if (PGOReader->isIRLevelProfile()) {
1309+
// Currently memprof profiles are only added at the IR level. Mark the profile
1310+
// type as IR in that case as well and the subsequent matching needs to detect
1311+
// which is available (might be one or both).
1312+
if (PGOReader->isIRLevelProfile() || PGOReader->hasMemoryProfile()) {
13101313
if (PGOReader->hasCSIRLevelProfile())
13111314
Opts.setProfileUse(CodeGenOptions::ProfileCSIRInstr);
13121315
else

clang/test/CodeGen/Inputs/memprof.exe

1.35 MB
Binary file not shown.
1.1 KB
Binary file not shown.

clang/test/CodeGen/memprof.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Test if memprof instrumentation and use pass are invoked.
2+
//
3+
// Instrumentation:
4+
// Ensure Pass MemProfilerPass and ModuleMemProfilerPass are invoked.
5+
// RUN: %clang_cc1 -O2 -fmemory-profile %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=INSTRUMENT
6+
// INSTRUMENT: Running pass: MemProfilerPass on main
7+
// INSTRUMENT: Running pass: ModuleMemProfilerPass on [module]
8+
9+
// TODO: Use text profile inputs once that is available for memprof.
10+
//
11+
// The following commands were used to compile the source to instrumented
12+
// executables and collect raw binary format profiles:
13+
//
14+
// # Collect memory profile:
15+
// $ clang++ -fuse-ld=lld -no-pie -Wl,--no-rosegment -gmlt \
16+
// -fdebug-info-for-profiling -mno-omit-leaf-frame-pointer \
17+
// -fno-omit-frame-pointer -fno-optimize-sibling-calls -m64 -Wl,-build-id \
18+
// memprof.cpp -o memprof.exe -fmemory-profile
19+
// $ env MEMPROF_OPTIONS=log_path=stdout ./memprof.exe > memprof.memprofraw
20+
//
21+
// RUN: llvm-profdata merge %S/Inputs/memprof.memprofraw --profiled-binary %S/Inputs/memprof.exe -o %t.memprofdata
22+
23+
// Profile use:
24+
// Ensure Pass PGOInstrumentationUse is invoked with the memprof-only profile.
25+
// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t.memprofdata %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=USE
26+
// USE: Running pass: PGOInstrumentationUse on [module]
27+
28+
char *foo() {
29+
return new char[10];
30+
}
31+
int main() {
32+
char *a = foo();
33+
delete[] a;
34+
return 0;
35+
}

llvm/include/llvm/Analysis/MemoryBuiltins.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ bool isAllocationFn(const Value *V, const TargetLibraryInfo *TLI);
5656
bool isAllocationFn(const Value *V,
5757
function_ref<const TargetLibraryInfo &(Function &)> GetTLI);
5858

59+
/// Tests if a value is a call or invoke to a library function that
60+
/// allocates memory via new.
61+
bool isNewLikeFn(const Value *V, const TargetLibraryInfo *TLI);
62+
5963
/// Tests if a value is a call or invoke to a library function that
6064
/// allocates memory similar to malloc or calloc.
6165
bool isMallocOrCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI);

llvm/include/llvm/ProfileData/InstrProfReader.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ class InstrProfReader {
118118
/// Return true if the profile only instruments function entries.
119119
virtual bool functionEntryOnly() const = 0;
120120

121+
/// Return true if profile includes a memory profile.
122+
virtual bool hasMemoryProfile() const = 0;
123+
121124
/// Returns a BitsetEnum describing the attributes of the profile. To check
122125
/// individual attributes prefer using the helpers above.
123126
virtual InstrProfKind getProfileKind() const = 0;
@@ -233,6 +236,11 @@ class TextInstrProfReader : public InstrProfReader {
233236
return static_cast<bool>(ProfileKind & InstrProfKind::FunctionEntryOnly);
234237
}
235238

239+
bool hasMemoryProfile() const override {
240+
// TODO: Add support for text format memory profiles.
241+
return false;
242+
}
243+
236244
InstrProfKind getProfileKind() const override { return ProfileKind; }
237245

238246
/// Read the header.
@@ -322,6 +330,12 @@ class RawInstrProfReader : public InstrProfReader {
322330
return (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) != 0;
323331
}
324332

333+
bool hasMemoryProfile() const override {
334+
// Memory profiles have a separate raw format, so this should never be set.
335+
assert(!(Version & VARIANT_MASK_MEMPROF));
336+
return false;
337+
}
338+
325339
/// Returns a BitsetEnum describing the attributes of the raw instr profile.
326340
InstrProfKind getProfileKind() const override;
327341

@@ -466,6 +480,7 @@ struct InstrProfReaderIndexBase {
466480
virtual bool instrEntryBBEnabled() const = 0;
467481
virtual bool hasSingleByteCoverage() const = 0;
468482
virtual bool functionEntryOnly() const = 0;
483+
virtual bool hasMemoryProfile() const = 0;
469484
virtual InstrProfKind getProfileKind() const = 0;
470485
virtual Error populateSymtab(InstrProfSymtab &) = 0;
471486
};
@@ -532,6 +547,10 @@ class InstrProfReaderIndex : public InstrProfReaderIndexBase {
532547
return (FormatVersion & VARIANT_MASK_FUNCTION_ENTRY_ONLY) != 0;
533548
}
534549

550+
bool hasMemoryProfile() const override {
551+
return (FormatVersion & VARIANT_MASK_MEMPROF) != 0;
552+
}
553+
535554
InstrProfKind getProfileKind() const override;
536555

537556
Error populateSymtab(InstrProfSymtab &Symtab) override {
@@ -605,6 +624,8 @@ class IndexedInstrProfReader : public InstrProfReader {
605624

606625
bool functionEntryOnly() const override { return Index->functionEntryOnly(); }
607626

627+
bool hasMemoryProfile() const override { return Index->hasMemoryProfile(); }
628+
608629
/// Returns a BitsetEnum describing the attributes of the indexed instr
609630
/// profile.
610631
InstrProfKind getProfileKind() const override {

llvm/lib/Analysis/MemoryBuiltins.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ bool llvm::isAllocationFn(
303303
checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc);
304304
}
305305

306+
/// Tests if a value is a call or invoke to a library function that
307+
/// allocates memory via new.
308+
bool llvm::isNewLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
309+
return getAllocationData(V, OpNewLike, TLI).hasValue();
310+
}
311+
306312
/// Tests if a value is a call or invoke to a library function that
307313
/// allocates uninitialized memory (such as malloc).
308314
static bool isMallocLikeFn(const Value *V, const TargetLibraryInfo *TLI) {

0 commit comments

Comments
 (0)