Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
7 changes: 7 additions & 0 deletions llvm/include/llvm/ProfileData/InstrProfReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,9 @@ class IndexedMemProfReader {

DenseMap<uint64_t, SmallVector<memprof::CallEdgeTy, 0>>
getMemProfCallerCalleePairs() const;

// Return the entire MemProf profile.
memprof::AllMemProfData getAllMemProfData() const;
};

/// Reader for the indexed binary instrprof format.
Expand Down Expand Up @@ -823,6 +826,10 @@ class IndexedInstrProfReader : public InstrProfReader {
return MemProfReader.getMemProfCallerCalleePairs();
}

memprof::AllMemProfData getAllMemProfData() const {
return MemProfReader.getAllMemProfData();
}

/// Fill Counts with the profile data for the given function name.
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
std::vector<uint64_t> &Counts);
Expand Down
14 changes: 14 additions & 0 deletions llvm/include/llvm/ProfileData/MemProfReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,20 @@ class RawMemProfReader final : public MemProfReader {
class YAMLMemProfReader final : public MemProfReader {
public:
YAMLMemProfReader() = default;

// Return true if the \p DataBuffer starts with "---" indicating it is a YAML
// file.
static bool hasFormat(const MemoryBuffer &DataBuffer);
// Wrapper around hasFormat above, reading the file instead of the memory
// buffer.
static bool hasFormat(const StringRef Path);

// Create a YAMLMemProfReader after sanity checking the contents of the file
// at \p Path or the \p Buffer.
static Expected<std::unique_ptr<YAMLMemProfReader>> create(const Twine &Path);
static Expected<std::unique_ptr<YAMLMemProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer);

void parse(StringRef YAMLData);
};
} // namespace memprof
Expand Down
16 changes: 16 additions & 0 deletions llvm/lib/ProfileData/InstrProfReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,22 @@ IndexedMemProfReader::getMemProfCallerCalleePairs() const {
return Pairs;
}

memprof::AllMemProfData IndexedMemProfReader::getAllMemProfData() const {
memprof::AllMemProfData AllMemProfData;
AllMemProfData.HeapProfileRecords.reserve(
MemProfRecordTable->getNumEntries());
for (uint64_t Key : MemProfRecordTable->keys()) {
auto Record = getMemProfRecord(Key);
if (Record.takeError())
continue;
memprof::GUIDMemProfRecordPair Pair;
Pair.GUID = Key;
Pair.Record = std::move(*Record);
AllMemProfData.HeapProfileRecords.push_back(std::move(Pair));
}
return AllMemProfData;
}

Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
uint64_t FuncHash,
std::vector<uint64_t> &Counts) {
Expand Down
30 changes: 30 additions & 0 deletions llvm/lib/ProfileData/MemProfReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,36 @@ Error RawMemProfReader::readNextRecord(
return MemProfReader::readNextRecord(GuidRecord, IdToFrameCallback);
}

Expected<std::unique_ptr<YAMLMemProfReader>>
YAMLMemProfReader::create(const Twine &Path) {
auto BufferOr = MemoryBuffer::getFileOrSTDIN(Path);
if (std::error_code EC = BufferOr.getError())
return report(errorCodeToError(EC), Path.getSingleStringRef());

std::unique_ptr<MemoryBuffer> Buffer(BufferOr.get().release());
return create(std::move(Buffer));
}

Expected<std::unique_ptr<YAMLMemProfReader>>
YAMLMemProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
auto Reader = std::make_unique<YAMLMemProfReader>();
Reader->parse(Buffer->getBuffer());
return std::move(Reader);
}

bool YAMLMemProfReader::hasFormat(const StringRef Path) {
auto BufferOr = MemoryBuffer::getFileOrSTDIN(Path);
if (!BufferOr)
return false;

std::unique_ptr<MemoryBuffer> Buffer(BufferOr.get().release());
return hasFormat(*Buffer);
}

bool YAMLMemProfReader::hasFormat(const MemoryBuffer &Buffer) {
return Buffer.getBuffer().starts_with("---");
}

void YAMLMemProfReader::parse(StringRef YAMLData) {
memprof::AllMemProfData Doc;
yaml::Input Yin(YAMLData);
Expand Down
34 changes: 34 additions & 0 deletions llvm/test/tools/llvm-profdata/memprof-yaml.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
; REQUIRES: x86_64-linux
; RUN: split-file %s %t
; RUN: llvm-profdata merge %t/memprof-in.yaml -o %t/memprof-out.indexed
; RUN: llvm-profdata show --memory %t/memprof-out.indexed > %t/memprof-out.yaml
; RUN: cmp %t/memprof-in.yaml %t/memprof-out.yaml

; Verify that the YAML output is identical to the YAML input.
;--- memprof-in.yaml
---
HeapProfileRecords:
- GUID: 16045690981402826360
AllocSites:
- Callstack:
- { Function: 100, LineOffset: 11, Column: 10, IsInlineFrame: true }
- { Function: 200, LineOffset: 22, Column: 20, IsInlineFrame: false }
MemInfoBlock:
AllocCount: 111
TotalSize: 222
TotalLifetime: 333
TotalLifetimeAccessDensity: 444
- Callstack:
- { Function: 300, LineOffset: 33, Column: 30, IsInlineFrame: false }
- { Function: 400, LineOffset: 44, Column: 40, IsInlineFrame: true }
MemInfoBlock:
AllocCount: 555
TotalSize: 666
TotalLifetime: 777
TotalLifetimeAccessDensity: 888
CallSites:
- - { Function: 500, LineOffset: 55, Column: 50, IsInlineFrame: true }
- { Function: 600, LineOffset: 66, Column: 60, IsInlineFrame: false }
- - { Function: 700, LineOffset: 77, Column: 70, IsInlineFrame: true }
- { Function: 800, LineOffset: 88, Column: 80, IsInlineFrame: false }
...
79 changes: 67 additions & 12 deletions llvm/tools/llvm-profdata/llvm-profdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,43 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
return;
}

using ::llvm::memprof::YAMLMemProfReader;
if (YAMLMemProfReader::hasFormat(Input.Filename)) {
auto ReaderOrErr = YAMLMemProfReader::create(Input.Filename);
if (!ReaderOrErr)
exitWithError(ReaderOrErr.takeError(), Input.Filename);
std::unique_ptr<YAMLMemProfReader> Reader = std::move(ReaderOrErr.get());
// Check if the profile types can be merged, e.g. clang frontend profiles
// should not be merged with memprof profiles.
if (Error E = WC->Writer.mergeProfileKind(Reader->getProfileKind())) {
consumeError(std::move(E));
WC->Errors.emplace_back(
make_error<StringError>(
"Cannot merge MemProf profile with incompatible profile.",
std::error_code()),
Filename);
return;
}

auto MemProfError = [&](Error E) {
auto [ErrorCode, Msg] = InstrProfError::take(std::move(E));
WC->Errors.emplace_back(make_error<InstrProfError>(ErrorCode, Msg),
Filename);
};

auto MemProfData = Reader->takeMemProfData();

// Check for the empty input in case the YAML file is invalid.
if (MemProfData.Records.empty()) {
WC->Errors.emplace_back(
make_error<StringError>("The profile is empty.", std::error_code()),
Filename);
}

WC->Writer.addMemProfData(std::move(MemProfData), MemProfError);
return;
}

auto FS = vfs::getRealFileSystem();
// TODO: This only saves the first non-fatal error from InstrProfReader, and
// then added to WriterContext::Errors. However, this is not extensible, if
Expand Down Expand Up @@ -3242,18 +3279,36 @@ static int showSampleProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
static int showMemProfProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
if (SFormat == ShowFormat::Json)
exitWithError("JSON output is not supported for MemProf");
auto ReaderOr = llvm::memprof::RawMemProfReader::create(
Filename, ProfiledBinary, /*KeepNames=*/true);
if (Error E = ReaderOr.takeError())
// Since the error can be related to the profile or the binary we do not
// pass whence. Instead additional context is provided where necessary in
// the error message.
exitWithError(std::move(E), /*Whence*/ "");

std::unique_ptr<llvm::memprof::RawMemProfReader> Reader(
ReaderOr.get().release());

Reader->printYAML(OS);

// Show the raw profile in YAML.
if (memprof::RawMemProfReader::hasFormat(Filename)) {
auto ReaderOr = llvm::memprof::RawMemProfReader::create(
Filename, ProfiledBinary, /*KeepNames=*/true);
if (Error E = ReaderOr.takeError()) {
// Since the error can be related to the profile or the binary we do not
// pass whence. Instead additional context is provided where necessary in
// the error message.
exitWithError(std::move(E), /*Whence*/ "");
}

std::unique_ptr<llvm::memprof::RawMemProfReader> Reader(
ReaderOr.get().release());

Reader->printYAML(OS);
return 0;
}

// Show the indexed MemProf profile in YAML.
auto FS = vfs::getRealFileSystem();
auto ReaderOrErr = IndexedInstrProfReader::create(Filename, *FS);
if (Error E = ReaderOrErr.takeError())
exitWithError(std::move(E), Filename);

auto Reader = std::move(ReaderOrErr.get());
memprof::AllMemProfData Data = Reader->getAllMemProfData();
yaml::Output Yout(OS);
Yout << Data;

return 0;
}

Expand Down
Loading