Skip to content

Commit bb39151

Browse files
[MemProf] Support for random hotness when writing profile (#113998)
Add support for generating random hotness in the memprof profile writer, to be used for testing. The random seed is printed to stderr, and an additional option enables providing a specific seed in order to reproduce a particular random profile.
1 parent 9a7519f commit bb39151

File tree

5 files changed

+86
-6
lines changed

5 files changed

+86
-6
lines changed

llvm/include/llvm/ProfileData/InstrProfWriter.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,20 @@ class InstrProfWriter {
7878
// Whether to serialize the full schema.
7979
bool MemProfFullSchema;
8080

81+
// Whether to generated random memprof hotness for testing.
82+
bool MemprofGenerateRandomHotness;
83+
8184
public:
85+
// For memprof testing, random hotness can be assigned to the contexts if
86+
// MemprofGenerateRandomHotness is enabled. The random seed can be either
87+
// provided by MemprofGenerateRandomHotnessSeed, or if that is 0, one will be
88+
// generated in the writer using the current time.
8289
InstrProfWriter(
8390
bool Sparse = false, uint64_t TemporalProfTraceReservoirSize = 0,
8491
uint64_t MaxTemporalProfTraceLength = 0, bool WritePrevVersion = false,
8592
memprof::IndexedVersion MemProfVersionRequested = memprof::Version0,
86-
bool MemProfFullSchema = false);
93+
bool MemProfFullSchema = false, bool MemprofGenerateRandomHotness = false,
94+
unsigned MemprofGenerateRandomHotnessSeed = 0);
8795
~InstrProfWriter();
8896

8997
StringMap<ProfilingData> &getProfileData() { return FunctionData; }

llvm/include/llvm/ProfileData/MemProf.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,15 @@ struct PortableMemInfoBlock {
147147
return Name; \
148148
}
149149
#include "llvm/ProfileData/MIBEntryDef.inc"
150+
#undef MIBEntryDef
151+
152+
// Define setters for each type which can be called by the writer.
153+
#define MIBEntryDef(NameTag, Name, Type) \
154+
void set##Name(Type NewVal) { \
155+
assert(Schema[llvm::to_underlying(Meta::Name)]); \
156+
Name = NewVal; \
157+
}
158+
#include "llvm/ProfileData/MIBEntryDef.inc"
150159
#undef MIBEntryDef
151160

152161
void clear() { *this = PortableMemInfoBlock(); }

llvm/lib/ProfileData/InstrProfWriter.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ProfileData/InstrProf.h"
2020
#include "llvm/ProfileData/MemProf.h"
2121
#include "llvm/ProfileData/ProfileCommon.h"
22+
#include "llvm/Support/CommandLine.h"
2223
#include "llvm/Support/Compression.h"
2324
#include "llvm/Support/Endian.h"
2425
#include "llvm/Support/EndianStream.h"
@@ -184,13 +185,25 @@ class InstrProfRecordWriterTrait {
184185
InstrProfWriter::InstrProfWriter(
185186
bool Sparse, uint64_t TemporalProfTraceReservoirSize,
186187
uint64_t MaxTemporalProfTraceLength, bool WritePrevVersion,
187-
memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema)
188+
memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema,
189+
bool MemprofGenerateRandomHotness,
190+
unsigned MemprofGenerateRandomHotnessSeed)
188191
: Sparse(Sparse), MaxTemporalProfTraceLength(MaxTemporalProfTraceLength),
189192
TemporalProfTraceReservoirSize(TemporalProfTraceReservoirSize),
190193
InfoObj(new InstrProfRecordWriterTrait()),
191194
WritePrevVersion(WritePrevVersion),
192195
MemProfVersionRequested(MemProfVersionRequested),
193-
MemProfFullSchema(MemProfFullSchema) {}
196+
MemProfFullSchema(MemProfFullSchema),
197+
MemprofGenerateRandomHotness(MemprofGenerateRandomHotness) {
198+
// Set up the random number seed if requested.
199+
if (MemprofGenerateRandomHotness) {
200+
unsigned seed = MemprofGenerateRandomHotnessSeed
201+
? MemprofGenerateRandomHotnessSeed
202+
: std::time(nullptr);
203+
errs() << "random hotness seed = " << seed << "\n";
204+
std::srand(seed);
205+
}
206+
}
194207

195208
InstrProfWriter::~InstrProfWriter() { delete InfoObj; }
196209

@@ -273,13 +286,34 @@ void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
273286

274287
void InstrProfWriter::addMemProfRecord(
275288
const Function::GUID Id, const memprof::IndexedMemProfRecord &Record) {
276-
auto [Iter, Inserted] = MemProfData.Records.insert({Id, Record});
289+
auto NewRecord = Record;
290+
// Provoke random hotness values if requested. We specify the lifetime access
291+
// density and lifetime length that will result in a cold or not cold hotness.
292+
// See the logic in getAllocType() in Analysis/MemoryProfileInfo.cpp.
293+
if (MemprofGenerateRandomHotness) {
294+
for (auto &Alloc : NewRecord.AllocSites) {
295+
// To get a not cold context, set the lifetime access density to the
296+
// maximum value and the lifetime to 0.
297+
uint64_t NewTLAD = std::numeric_limits<uint64_t>::max();
298+
uint64_t NewTL = 0;
299+
bool IsCold = std::rand() % 2;
300+
if (IsCold) {
301+
// To get a cold context, set the lifetime access density to 0 and the
302+
// lifetime to the maximum value.
303+
NewTLAD = 0;
304+
NewTL = std::numeric_limits<uint64_t>::max();
305+
}
306+
Alloc.Info.setTotalLifetimeAccessDensity(NewTLAD);
307+
Alloc.Info.setTotalLifetime(NewTL);
308+
}
309+
}
310+
auto [Iter, Inserted] = MemProfData.Records.insert({Id, NewRecord});
277311
// If we inserted a new record then we are done.
278312
if (Inserted) {
279313
return;
280314
}
281315
memprof::IndexedMemProfRecord &Existing = Iter->second;
282-
Existing.merge(Record);
316+
Existing.merge(NewRecord);
283317
}
284318

285319
bool InstrProfWriter::addMemProfFrame(const memprof::FrameId Id,

llvm/test/Transforms/PGOProfile/memprof.ll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,18 @@
6666
;; Check that the total sizes are reported if requested.
6767
; RUN: opt < %s -passes='memprof-use<profile-filename=%t.memprofdata>' -pgo-warn-missing-function -S -memprof-report-hinted-sizes 2>&1 | FileCheck %s --check-prefixes=TOTALSIZES
6868

69+
;; Make sure we emit a random hotness seed if requested.
70+
; RUN: llvm-profdata merge -memprof-random-hotness %S/Inputs/memprof.memprofraw --profiled-binary %S/Inputs/memprof.exe -o %t.memprofdatarand 2>&1 | FileCheck %s --check-prefix=RAND
71+
; RAND: random hotness seed =
72+
;; Can't check the exact values, but make sure applying the random profile
73+
;; succeeds with the same stats
74+
; RUN: opt < %s -passes='memprof-use<profile-filename=%t.memprofdatarand>' -pgo-warn-missing-function -S -stats 2>&1 | FileCheck %s --check-prefixes=ALL,MEMPROFONLY,MEMPROFSTATS
75+
76+
;; Make sure we use a specific random hotness seed if requested.
77+
; RUN: llvm-profdata merge -memprof-random-hotness -memprof-random-hotness-seed=1730170724 %S/Inputs/memprof.memprofraw --profiled-binary %S/Inputs/memprof.exe -o %t.memprofdatarand2 2>&1 | FileCheck %s --check-prefix=RAND2
78+
; RAND2: random hotness seed = 1730170724
79+
; RUN: opt < %s -passes='memprof-use<profile-filename=%t.memprofdatarand2>' -pgo-warn-missing-function -S -stats 2>&1 | FileCheck %s --check-prefixes=MEMPROFRAND2,ALL,MEMPROFONLY,MEMPROFSTATS
80+
6981
; MEMPROFMATCHINFO: MemProf notcold context with id 1093248920606587996 has total profiled size 10 is matched
7082
; MEMPROFMATCHINFO: MemProf notcold context with id 5725971306423925017 has total profiled size 10 is matched
7183
; MEMPROFMATCHINFO: MemProf notcold context with id 6792096022461663180 has total profiled size 10 is matched
@@ -372,6 +384,13 @@ for.end: ; preds = %for.cond
372384
; MEMPROFNOCOLINFO: ![[C10]] = !{i64 -4535090212904553409}
373385
; MEMPROFNOCOLINFO: ![[C11]] = !{i64 3577763375057267810}
374386

387+
;; For the specific random seed, this is the expected order of hotness
388+
; MEMPROFRAND2: !"cold"
389+
; MEMPROFRAND2: !"cold"
390+
; MEMPROFRAND2: !"cold"
391+
; MEMPROFRAND2: !"hot"
392+
; MEMPROFRAND2: !"hot"
393+
375394
; MEMPROFSTATS: 8 memprof - Number of alloc contexts in memory profile.
376395
; MEMPROFSTATS: 10 memprof - Number of callsites in memory profile.
377396
; MEMPROFSTATS: 6 memprof - Number of functions having valid memory profile.

llvm/tools/llvm-profdata/llvm-profdata.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,15 @@ cl::opt<bool> MemProfFullSchema(
342342
"memprof-full-schema", cl::Hidden, cl::sub(MergeSubcommand),
343343
cl::desc("Use the full schema for serialization"), cl::init(false));
344344

345+
static cl::opt<bool>
346+
MemprofGenerateRandomHotness("memprof-random-hotness", cl::init(false),
347+
cl::Hidden, cl::sub(MergeSubcommand),
348+
cl::desc("Generate random hotness values"));
349+
static cl::opt<unsigned> MemprofGenerateRandomHotnessSeed(
350+
"memprof-random-hotness-seed", cl::init(0), cl::Hidden,
351+
cl::sub(MergeSubcommand),
352+
cl::desc("Random hotness seed to use (0 to generate new seed)"));
353+
345354
// Options specific to overlap subcommand.
346355
cl::opt<std::string> BaseFilename(cl::Positional, cl::Required,
347356
cl::desc("<base profile file>"),
@@ -641,7 +650,8 @@ struct WriterContext {
641650
SmallSet<instrprof_error, 4> &WriterErrorCodes,
642651
uint64_t ReservoirSize = 0, uint64_t MaxTraceLength = 0)
643652
: Writer(IsSparse, ReservoirSize, MaxTraceLength, DoWritePrevVersion,
644-
MemProfVersionRequested, MemProfFullSchema),
653+
MemProfVersionRequested, MemProfFullSchema,
654+
MemprofGenerateRandomHotness, MemprofGenerateRandomHotnessSeed),
645655
ErrLock(ErrLock), WriterErrorCodes(WriterErrorCodes) {}
646656
};
647657

0 commit comments

Comments
 (0)