[llvm] 37fd3c9 - [memprof] Add a MemProfReader base class.
Snehasish Kumar via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 30 13:38:13 PDT 2023
Author: Snehasish Kumar
Date: 2023-08-30T20:20:55Z
New Revision: 37fd3c96b917096d8a550038f6e61cdf0fc4174f
URL: https://github.com/llvm/llvm-project/commit/37fd3c96b917096d8a550038f6e61cdf0fc4174f
DIFF: https://github.com/llvm/llvm-project/commit/37fd3c96b917096d8a550038f6e61cdf0fc4174f.diff
LOG: [memprof] Add a MemProfReader base class.
Add a MemProfReader base class which can be used directly where
symbolization and processing a raw profile is unnecessary.
Reviewed By: tejohnson
Differential Revision: https://reviews.llvm.org/D159141
Added:
Modified:
llvm/include/llvm/ProfileData/RawMemProfReader.h
llvm/lib/ProfileData/RawMemProfReader.cpp
llvm/unittests/ProfileData/MemProfTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ProfileData/RawMemProfReader.h b/llvm/include/llvm/ProfileData/RawMemProfReader.h
index 4141cfb42e0d96..796183aacc7237 100644
--- a/llvm/include/llvm/ProfileData/RawMemProfReader.h
+++ b/llvm/include/llvm/ProfileData/RawMemProfReader.h
@@ -26,19 +26,95 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
-#include <cstddef>
+#include <functional>
namespace llvm {
namespace memprof {
+// A class for memprof profile data populated directly from external
+// sources.
+// TODO: Rename this file to MemProfReader.h to better reflect the contents.
+class MemProfReader {
+public:
+ // The MemProfReader only holds memory profile information.
+ InstrProfKind getProfileKind() const { return InstrProfKind::MemProf; }
+
+ using GuidMemProfRecordPair = std::pair<GlobalValue::GUID, MemProfRecord>;
+ using Iterator = InstrProfIterator<GuidMemProfRecordPair, MemProfReader>;
+ Iterator end() { return Iterator(); }
+ Iterator begin() {
+ Iter = FunctionProfileData.begin();
+ return Iterator(this);
+ }
+
+ // Return a const reference to the internal Id to Frame mappings.
+ const llvm::DenseMap<FrameId, Frame> &getFrameMapping() const {
+ return IdToFrame;
+ }
+
+ // Return a const reference to the internal function profile data.
+ const llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord> &
+ getProfileData() const {
+ return FunctionProfileData;
+ }
+
+ virtual Error
+ readNextRecord(GuidMemProfRecordPair &GuidRecord,
+ std::function<const Frame(const FrameId)> Callback = nullptr) {
+ if (FunctionProfileData.empty())
+ return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
+
+ if (Iter == FunctionProfileData.end())
+ return make_error<InstrProfError>(instrprof_error::eof);
+
+ if (Callback == nullptr)
+ Callback =
+ std::bind(&MemProfReader::idToFrame, this, std::placeholders::_1);
+
+ const IndexedMemProfRecord &IndexedRecord = Iter->second;
+ GuidRecord = {Iter->first, MemProfRecord(IndexedRecord, Callback)};
+ Iter++;
+ return Error::success();
+ }
+
+ // Allow default construction for derived classes which can populate the
+ // contents after construction.
+ MemProfReader() = default;
+ virtual ~MemProfReader() = default;
+
+ // Initialize the MemProfReader with the frame mappings and profile contents.
+ MemProfReader(
+ llvm::DenseMap<FrameId, Frame> FrameIdMap,
+ llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord> ProfData)
+ : IdToFrame(std::move(FrameIdMap)),
+ FunctionProfileData(std::move(ProfData)) {}
+
+protected:
+ // A helper method to extract the frame from the IdToFrame map.
+ const Frame &idToFrame(const FrameId Id) const {
+ auto It = IdToFrame.find(Id);
+ assert(It != IdToFrame.end() && "Id not found in map.");
+ return It->getSecond();
+ }
+ // A mapping from FrameId (a hash of the contents) to the frame.
+ llvm::DenseMap<FrameId, Frame> IdToFrame;
+ // A mapping from function GUID, hash of the canonical function symbol to the
+ // memprof profile data for that function, i.e allocation and callsite info.
+ llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord> FunctionProfileData;
+ // An iterator to the internal function profile data structure.
+ llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord>::iterator Iter;
+};
// Map from id (recorded from sanitizer stack depot) to virtual addresses for
// each program counter address in the callstack.
using CallStackMap = llvm::DenseMap<uint64_t, llvm::SmallVector<uint64_t>>;
-class RawMemProfReader {
+// Specializes the MemProfReader class to populate the contents from raw binary
+// memprof profiles from instrumentation based profiling.
+class RawMemProfReader final : public MemProfReader {
public:
RawMemProfReader(const RawMemProfReader &) = delete;
RawMemProfReader &operator=(const RawMemProfReader &) = delete;
+ virtual ~RawMemProfReader() override = default;
// Prints the contents of the profile in YAML format.
void printYAML(raw_ostream &OS);
@@ -62,18 +138,9 @@ class RawMemProfReader {
// Returns a list of build ids recorded in the segment information.
static std::vector<std::string> peekBuildIds(MemoryBuffer *DataBuffer);
- using GuidMemProfRecordPair = std::pair<GlobalValue::GUID, MemProfRecord>;
- using Iterator = InstrProfIterator<GuidMemProfRecordPair, RawMemProfReader>;
- Iterator end() { return Iterator(); }
- Iterator begin() {
- Iter = FunctionProfileData.begin();
- return Iterator(this);
- }
-
- Error readNextRecord(GuidMemProfRecordPair &GuidRecord);
-
- // The RawMemProfReader only holds memory profile information.
- InstrProfKind getProfileKind() const { return InstrProfKind::MemProf; }
+ virtual Error
+ readNextRecord(GuidMemProfRecordPair &GuidRecord,
+ std::function<const Frame(const FrameId)> Callback) override;
// Constructor for unittests only.
RawMemProfReader(std::unique_ptr<llvm::symbolize::SymbolizableModule> Sym,
@@ -93,17 +160,6 @@ class RawMemProfReader {
report_fatal_error(std::move(E));
}
- // Return a const reference to the internal Id to Frame mappings.
- const llvm::DenseMap<FrameId, Frame> &getFrameMapping() const {
- return IdToFrame;
- }
-
- // Return a const reference to the internal function profile data.
- const llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord> &
- getProfileData() const {
- return FunctionProfileData;
- }
-
private:
RawMemProfReader(object::OwningBinary<object::Binary> &&Bin, bool KeepName)
: Binary(std::move(Bin)), KeepSymbolName(KeepName) {}
@@ -123,13 +179,6 @@ class RawMemProfReader {
// callsite data or both.
Error mapRawProfileToRecords();
- // A helper method to extract the frame from the IdToFrame map.
- const Frame &idToFrame(const FrameId Id) const {
- auto It = IdToFrame.find(Id);
- assert(It != IdToFrame.end() && "Id not found in map.");
- return It->getSecond();
- }
-
object::SectionedAddress getModuleOffset(uint64_t VirtualAddress);
// The profiled binary.
@@ -154,10 +203,6 @@ class RawMemProfReader {
// Cached symbolization from PC to Frame.
llvm::DenseMap<uint64_t, llvm::SmallVector<FrameId>> SymbolizedFrame;
- llvm::DenseMap<FrameId, Frame> IdToFrame;
-
- llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord> FunctionProfileData;
- llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord>::iterator Iter;
// Whether to keep the symbol name for each frame after hashing.
bool KeepSymbolName = false;
diff --git a/llvm/lib/ProfileData/RawMemProfReader.cpp b/llvm/lib/ProfileData/RawMemProfReader.cpp
index dbf67ecae6846b..0716ec53ce3f43 100644
--- a/llvm/lib/ProfileData/RawMemProfReader.cpp
+++ b/llvm/lib/ProfileData/RawMemProfReader.cpp
@@ -645,13 +645,12 @@ RawMemProfReader::getModuleOffset(const uint64_t VirtualAddress) {
return object::SectionedAddress{VirtualAddress};
}
-Error RawMemProfReader::readNextRecord(GuidMemProfRecordPair &GuidRecord) {
- if (FunctionProfileData.empty())
- return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
-
- if (Iter == FunctionProfileData.end())
- return make_error<InstrProfError>(instrprof_error::eof);
-
+Error RawMemProfReader::readNextRecord(
+ GuidMemProfRecordPair &GuidRecord,
+ std::function<const Frame(const FrameId)> Callback) {
+ // Create a new callback for the RawMemProfRecord iterator so that we can
+ // provide the symbol name if the reader was initialized with KeepSymbolName =
+ // true. This is useful for debugging and testing.
auto IdToFrameCallback = [this](const FrameId Id) {
Frame F = this->idToFrame(Id);
if (!this->KeepSymbolName)
@@ -661,11 +660,7 @@ Error RawMemProfReader::readNextRecord(GuidMemProfRecordPair &GuidRecord) {
F.SymbolName = Iter->getSecond();
return F;
};
-
- const IndexedMemProfRecord &IndexedRecord = Iter->second;
- GuidRecord = {Iter->first, MemProfRecord(IndexedRecord, IdToFrameCallback)};
- Iter++;
- return Error::success();
+ return MemProfReader::readNextRecord(GuidRecord, IdToFrameCallback);
}
} // namespace memprof
} // namespace llvm
diff --git a/llvm/unittests/ProfileData/MemProfTest.cpp b/llvm/unittests/ProfileData/MemProfTest.cpp
index 8c01e4d0593232..5984be98d798a8 100644
--- a/llvm/unittests/ProfileData/MemProfTest.cpp
+++ b/llvm/unittests/ProfileData/MemProfTest.cpp
@@ -3,14 +3,10 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
-#include "llvm/IR/Function.h"
#include "llvm/IR/Value.h"
#include "llvm/Object/ObjectFile.h"
-#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ProfileData/MemProfData.inc"
#include "llvm/ProfileData/RawMemProfReader.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/MD5.h"
#include "llvm/Support/raw_ostream.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -29,6 +25,7 @@ using ::llvm::memprof::Frame;
using ::llvm::memprof::FrameId;
using ::llvm::memprof::IndexedMemProfRecord;
using ::llvm::memprof::MemInfoBlock;
+using ::llvm::memprof::MemProfReader;
using ::llvm::memprof::MemProfRecord;
using ::llvm::memprof::MemProfSchema;
using ::llvm::memprof::Meta;
@@ -358,4 +355,38 @@ TEST(MemProf, SymbolizationFilter) {
EXPECT_THAT(Records[0].AllocSites[0].CallStack[0],
FrameContains("foo", 5U, 30U, false));
}
+
+TEST(MemProf, BaseMemProfReader) {
+ llvm::DenseMap<FrameId, Frame> FrameIdMap;
+ Frame F1(/*Hash=*/IndexedMemProfRecord::getGUID("foo"), /*LineOffset=*/20,
+ /*Column=*/5, /*IsInlineFrame=*/true);
+ Frame F2(/*Hash=*/IndexedMemProfRecord::getGUID("bar"), /*LineOffset=*/10,
+ /*Column=*/2, /*IsInlineFrame=*/false);
+ FrameIdMap.insert({F1.hash(), F1});
+ FrameIdMap.insert({F2.hash(), F2});
+
+ llvm::MapVector<llvm::GlobalValue::GUID, IndexedMemProfRecord> ProfData;
+ IndexedMemProfRecord FakeRecord;
+ MemInfoBlock Block;
+ Block.AllocCount = 1U, Block.TotalAccessDensity = 4,
+ Block.TotalLifetime = 200001;
+ std::array<FrameId, 2> CallStack{F1.hash(), F2.hash()};
+ FakeRecord.AllocSites.emplace_back(/*CS=*/CallStack, /*MB=*/Block);
+ ProfData.insert({F1.hash(), FakeRecord});
+
+ MemProfReader Reader(FrameIdMap, ProfData);
+
+ llvm::SmallVector<MemProfRecord, 1> Records;
+ for (const auto &KeyRecordPair : Reader) {
+ Records.push_back(KeyRecordPair.second);
+ }
+
+ ASSERT_EQ(Records.size(), 1U);
+ ASSERT_EQ(Records[0].AllocSites.size(), 1U);
+ ASSERT_EQ(Records[0].AllocSites[0].CallStack.size(), 2U);
+ EXPECT_THAT(Records[0].AllocSites[0].CallStack[0],
+ FrameContains("foo", 20U, 5U, true));
+ EXPECT_THAT(Records[0].AllocSites[0].CallStack[1],
+ FrameContains("bar", 10U, 2U, false));
+}
} // namespace
More information about the llvm-commits
mailing list