Skip to content

Commit 6bf8f08

Browse files
[memprof] Add InstrProfWriter::addMemProfData (#116528)
This patch adds InstrProfWriter::addMemProfData, which adds the complete MemProf profile (frames, call stacks, and records) to the writer context. Without this function, functions like loadInput in llvm-profdata.cpp and InstrProfWriter::mergeRecordsFromWriter must add one item (frame, call stack, or record) at a time. The new function std::moves the entire MemProf profile to the writer context if the destination is empty, which is the common use case. Otherwise, we fall back to adding one item at a time behind the scene. Here are a couple of reasons why we should add this function: - We've had a bug where we forgot to add one of the three data structures (frames, call stacks, and records) to the writer context, resulting in a nearly empty indexed profile. We should always package the three data structures together, especially on API boundaries. - We expose a little too much of the MemProf detail to InstrProfWriter. I'd like to gradually transform InstrProfReader/Writer to entities managing buffers (sequences of bytes), with actual serialization/deserialization left to external classes. We already do some of this in InstrProfReader, where InstrProfReader "contracts out" to IndexedMemProfReader to handle MemProf details. I am not changing loadInput or InstrProfWriter::mergeRecordsFromWriter for now because MemProfReader uses DenseMap for frames and call stacks, whereas MemProfData uses MapVector. I'll resolve these mismatches in subsequent patches.
1 parent b7d635e commit 6bf8f08

File tree

3 files changed

+84
-61
lines changed

3 files changed

+84
-61
lines changed

llvm/include/llvm/ProfileData/InstrProfWriter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ class InstrProfWriter {
130130
const llvm::SmallVector<memprof::FrameId> &CallStack,
131131
function_ref<void(Error)> Warn);
132132

133+
/// Add the entire MemProfData \p Incoming to the writer context.
134+
bool addMemProfData(memprof::IndexedMemProfData Incoming,
135+
function_ref<void(Error)> Warn);
136+
133137
// Add a binary id to the binary ids list.
134138
void addBinaryIds(ArrayRef<llvm::object::BuildID> BIs);
135139

llvm/lib/ProfileData/InstrProfWriter.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,35 @@ bool InstrProfWriter::addMemProfCallStack(
350350
return true;
351351
}
352352

353+
bool InstrProfWriter::addMemProfData(memprof::IndexedMemProfData Incoming,
354+
function_ref<void(Error)> Warn) {
355+
// TODO: Once we remove support for MemProf format Version V1, assert that
356+
// the three components (frames, call stacks, and records) are either all
357+
// empty or populated.
358+
359+
if (MemProfData.Frames.empty())
360+
MemProfData.Frames = std::move(Incoming.Frames);
361+
else
362+
for (const auto &[Id, F] : Incoming.Frames)
363+
if (addMemProfFrame(Id, F, Warn))
364+
return false;
365+
366+
if (MemProfData.CallStacks.empty())
367+
MemProfData.CallStacks = std::move(Incoming.CallStacks);
368+
else
369+
for (const auto &[CSId, CS] : Incoming.CallStacks)
370+
if (addMemProfCallStack(CSId, CS, Warn))
371+
return false;
372+
373+
if (MemProfData.Records.empty())
374+
MemProfData.Records = std::move(Incoming.Records);
375+
else
376+
for (const auto &[GUID, Record] : Incoming.Records)
377+
addMemProfRecord(GUID, Record);
378+
379+
return true;
380+
}
381+
353382
void InstrProfWriter::addBinaryIds(ArrayRef<llvm::object::BuildID> BIs) {
354383
llvm::append_range(BinaryIds, BIs);
355384
}

llvm/unittests/ProfileData/InstrProfTest.cpp

Lines changed: 51 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/Testing/Support/Error.h"
2222
#include "gtest/gtest.h"
2323
#include <cstdarg>
24+
#include <initializer_list>
2425
#include <optional>
2526

2627
using namespace llvm;
@@ -348,10 +349,10 @@ TEST_F(InstrProfTest, test_merge_traces_sampled) {
348349
using ::llvm::memprof::IndexedMemProfRecord;
349350
using ::llvm::memprof::MemInfoBlock;
350351
using FrameIdMapTy =
351-
llvm::DenseMap<::llvm::memprof::FrameId, ::llvm::memprof::Frame>;
352+
llvm::MapVector<::llvm::memprof::FrameId, ::llvm::memprof::Frame>;
352353
using CallStackIdMapTy =
353-
llvm::DenseMap<::llvm::memprof::CallStackId,
354-
::llvm::SmallVector<::llvm::memprof::FrameId>>;
354+
llvm::MapVector<::llvm::memprof::CallStackId,
355+
::llvm::SmallVector<::llvm::memprof::FrameId>>;
355356

356357
static FrameIdMapTy getFrameMapping() {
357358
FrameIdMapTy Mapping;
@@ -467,11 +468,11 @@ TEST_F(InstrProfTest, test_memprof_v0) {
467468
/*CallSiteFrames=*/{
468469
{4, 5},
469470
});
470-
const FrameIdMapTy IdToFrameMap = getFrameMapping();
471-
for (const auto &I : IdToFrameMap) {
472-
Writer.addMemProfFrame(I.first, I.getSecond(), Err);
473-
}
474-
Writer.addMemProfRecord(/*Id=*/0x9999, IndexedMR);
471+
472+
memprof::IndexedMemProfData MemProfData;
473+
MemProfData.Frames = getFrameMapping();
474+
MemProfData.Records.try_emplace(0x9999, IndexedMR);
475+
Writer.addMemProfData(MemProfData, Err);
475476

476477
auto Profile = Writer.writeBuffer();
477478
readProfile(std::move(Profile));
@@ -482,8 +483,8 @@ TEST_F(InstrProfTest, test_memprof_v0) {
482483

483484
std::optional<memprof::FrameId> LastUnmappedFrameId;
484485
auto IdToFrameCallback = [&](const memprof::FrameId Id) {
485-
auto Iter = IdToFrameMap.find(Id);
486-
if (Iter == IdToFrameMap.end()) {
486+
auto Iter = MemProfData.Frames.find(Id);
487+
if (Iter == MemProfData.Frames.end()) {
487488
LastUnmappedFrameId = Id;
488489
return memprof::Frame(0, 0, 0, false);
489490
}
@@ -508,15 +509,11 @@ TEST_F(InstrProfTest, test_memprof_v2_full_schema) {
508509
const IndexedMemProfRecord IndexedMR = makeRecordV2(
509510
/*AllocFrames=*/{0x111, 0x222},
510511
/*CallSiteFrames=*/{0x333}, MIB, memprof::getFullSchema());
511-
const FrameIdMapTy IdToFrameMap = getFrameMapping();
512-
const auto CSIdToCallStackMap = getCallStackMapping();
513-
for (const auto &I : IdToFrameMap) {
514-
Writer.addMemProfFrame(I.first, I.getSecond(), Err);
515-
}
516-
for (const auto &I : CSIdToCallStackMap) {
517-
Writer.addMemProfCallStack(I.first, I.getSecond(), Err);
518-
}
519-
Writer.addMemProfRecord(/*Id=*/0x9999, IndexedMR);
512+
memprof::IndexedMemProfData MemProfData;
513+
MemProfData.Frames = getFrameMapping();
514+
MemProfData.CallStacks = getCallStackMapping();
515+
MemProfData.Records.try_emplace(0x9999, IndexedMR);
516+
Writer.addMemProfData(MemProfData, Err);
520517

521518
auto Profile = Writer.writeBuffer();
522519
readProfile(std::move(Profile));
@@ -525,9 +522,10 @@ TEST_F(InstrProfTest, test_memprof_v2_full_schema) {
525522
ASSERT_THAT_ERROR(RecordOr.takeError(), Succeeded());
526523
const memprof::MemProfRecord &Record = RecordOr.get();
527524

528-
memprof::FrameIdConverter<decltype(IdToFrameMap)> FrameIdConv(IdToFrameMap);
529-
memprof::CallStackIdConverter<decltype(CSIdToCallStackMap)> CSIdConv(
530-
CSIdToCallStackMap, FrameIdConv);
525+
memprof::FrameIdConverter<decltype(MemProfData.Frames)> FrameIdConv(
526+
MemProfData.Frames);
527+
memprof::CallStackIdConverter<decltype(MemProfData.CallStacks)> CSIdConv(
528+
MemProfData.CallStacks, FrameIdConv);
531529

532530
const ::llvm::memprof::MemProfRecord WantRecord =
533531
IndexedMR.toMemProfRecord(CSIdConv);
@@ -550,15 +548,11 @@ TEST_F(InstrProfTest, test_memprof_v2_partial_schema) {
550548
const IndexedMemProfRecord IndexedMR = makeRecordV2(
551549
/*AllocFrames=*/{0x111, 0x222},
552550
/*CallSiteFrames=*/{0x333}, MIB, memprof::getHotColdSchema());
553-
const FrameIdMapTy IdToFrameMap = getFrameMapping();
554-
const auto CSIdToCallStackMap = getCallStackMapping();
555-
for (const auto &I : IdToFrameMap) {
556-
Writer.addMemProfFrame(I.first, I.getSecond(), Err);
557-
}
558-
for (const auto &I : CSIdToCallStackMap) {
559-
Writer.addMemProfCallStack(I.first, I.getSecond(), Err);
560-
}
561-
Writer.addMemProfRecord(/*Id=*/0x9999, IndexedMR);
551+
memprof::IndexedMemProfData MemProfData;
552+
MemProfData.Frames = getFrameMapping();
553+
MemProfData.CallStacks = getCallStackMapping();
554+
MemProfData.Records.try_emplace(0x9999, IndexedMR);
555+
Writer.addMemProfData(MemProfData, Err);
562556

563557
auto Profile = Writer.writeBuffer();
564558
readProfile(std::move(Profile));
@@ -567,9 +561,10 @@ TEST_F(InstrProfTest, test_memprof_v2_partial_schema) {
567561
ASSERT_THAT_ERROR(RecordOr.takeError(), Succeeded());
568562
const memprof::MemProfRecord &Record = RecordOr.get();
569563

570-
memprof::FrameIdConverter<decltype(IdToFrameMap)> FrameIdConv(IdToFrameMap);
571-
memprof::CallStackIdConverter<decltype(CSIdToCallStackMap)> CSIdConv(
572-
CSIdToCallStackMap, FrameIdConv);
564+
memprof::FrameIdConverter<decltype(MemProfData.Frames)> FrameIdConv(
565+
MemProfData.Frames);
566+
memprof::CallStackIdConverter<decltype(MemProfData.CallStacks)> CSIdConv(
567+
MemProfData.CallStacks, FrameIdConv);
573568

574569
const ::llvm::memprof::MemProfRecord WantRecord =
575570
IndexedMR.toMemProfRecord(CSIdConv);
@@ -601,23 +596,21 @@ TEST_F(InstrProfTest, test_caller_callee_pairs) {
601596
// Line: 7, Column: 8
602597
// new(...)
603598

604-
const std::pair<memprof::FrameId, memprof::Frame> Frames[] = {
605-
{0, {0x123, 1, 2, false}},
606-
{1, {0x234, 3, 4, true}},
607-
{2, {0x123, 5, 6, false}},
608-
{3, {0x345, 7, 8, true}}};
609-
for (const auto &[FrameId, Frame] : Frames)
610-
Writer.addMemProfFrame(FrameId, Frame, Err);
611-
612-
const std::pair<memprof::CallStackId, SmallVector<memprof::FrameId>>
613-
CallStacks[] = {{0x111, {1, 0}}, {0x222, {3, 2}}};
614-
for (const auto &[CSId, CallStack] : CallStacks)
615-
Writer.addMemProfCallStack(CSId, CallStack, Err);
616-
617599
const IndexedMemProfRecord IndexedMR = makeRecordV2(
618600
/*AllocFrames=*/{0x111, 0x222},
619601
/*CallSiteFrames=*/{}, MIB, memprof::getHotColdSchema());
620-
Writer.addMemProfRecord(/*Id=*/0x9999, IndexedMR);
602+
603+
memprof::IndexedMemProfData MemProfData;
604+
MemProfData.Frames.try_emplace(0, 0x123, 1, 2, false);
605+
MemProfData.Frames.try_emplace(1, 0x234, 3, 4, true);
606+
MemProfData.Frames.try_emplace(2, 0x123, 5, 6, false);
607+
MemProfData.Frames.try_emplace(3, 0x345, 7, 8, true);
608+
MemProfData.CallStacks.try_emplace(
609+
0x111, std::initializer_list<memprof::FrameId>{1, 0});
610+
MemProfData.CallStacks.try_emplace(
611+
0x222, std::initializer_list<memprof::FrameId>{3, 2});
612+
MemProfData.Records.try_emplace(0x9999, IndexedMR);
613+
Writer.addMemProfData(MemProfData, Err);
621614

622615
auto Profile = Writer.writeBuffer();
623616
readProfile(std::move(Profile));
@@ -681,19 +674,15 @@ TEST_F(InstrProfTest, test_memprof_merge) {
681674
ASSERT_THAT_ERROR(Writer2.mergeProfileKind(InstrProfKind::MemProf),
682675
Succeeded());
683676

684-
const FrameIdMapTy IdToFrameMap = getFrameMapping();
685-
for (const auto &I : IdToFrameMap) {
686-
Writer2.addMemProfFrame(I.first, I.getSecond(), Err);
687-
}
688-
689-
const auto CSIdToCallStackMap = getCallStackMapping();
690-
for (const auto &[CSId, CallStack] : CSIdToCallStackMap)
691-
Writer2.addMemProfCallStack(CSId, CallStack, Err);
692-
693677
const IndexedMemProfRecord IndexedMR = makeRecordV2(
694678
/*AllocFrames=*/{0x111, 0x222},
695679
/*CallSiteFrames=*/{}, makePartialMIB(), memprof::getHotColdSchema());
696-
Writer2.addMemProfRecord(/*Id=*/0x9999, IndexedMR);
680+
681+
memprof::IndexedMemProfData MemProfData;
682+
MemProfData.Frames = getFrameMapping();
683+
MemProfData.CallStacks = getCallStackMapping();
684+
MemProfData.Records.try_emplace(0x9999, IndexedMR);
685+
Writer2.addMemProfData(MemProfData, Err);
697686

698687
ASSERT_THAT_ERROR(Writer.mergeProfileKind(Writer2.getProfileKind()),
699688
Succeeded());
@@ -714,9 +703,10 @@ TEST_F(InstrProfTest, test_memprof_merge) {
714703

715704
std::optional<memprof::FrameId> LastUnmappedFrameId;
716705

717-
memprof::FrameIdConverter<decltype(IdToFrameMap)> FrameIdConv(IdToFrameMap);
718-
memprof::CallStackIdConverter<decltype(CSIdToCallStackMap)> CSIdConv(
719-
CSIdToCallStackMap, FrameIdConv);
706+
memprof::FrameIdConverter<decltype(MemProfData.Frames)> FrameIdConv(
707+
MemProfData.Frames);
708+
memprof::CallStackIdConverter<decltype(MemProfData.CallStacks)> CSIdConv(
709+
MemProfData.CallStacks, FrameIdConv);
720710

721711
const ::llvm::memprof::MemProfRecord WantRecord =
722712
IndexedMR.toMemProfRecord(CSIdConv);

0 commit comments

Comments
 (0)