blob: 07c218aa9746675e478e21d4e3e6241b20f9945f [file] [log] [blame]
//===- RawMemProfReader.cpp - Instrumented memory profiling reader --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains support for reading MemProf profiling data.
//
//===----------------------------------------------------------------------===//
#include <cstdint>
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ProfileData/MemProfData.inc"
#include "llvm/ProfileData/RawMemProfReader.h"
namespace llvm {
namespace memprof {
namespace {
struct Summary {
uint64_t Version;
uint64_t TotalSizeBytes;
uint64_t NumSegments;
uint64_t NumMIBInfo;
uint64_t NumStackOffsets;
};
Summary computeSummary(const char *Start) {
auto *H = reinterpret_cast<const Header *>(Start);
return Summary{
H->Version,
H->TotalSize,
*reinterpret_cast<const uint64_t *>(Start + H->SegmentOffset),
*reinterpret_cast<const uint64_t *>(Start + H->MIBOffset),
*reinterpret_cast<const uint64_t *>(Start + H->StackOffset),
};
}
} // namespace
Expected<std::unique_ptr<RawMemProfReader>>
RawMemProfReader::create(const Twine &Path) {
auto BufferOr = MemoryBuffer::getFileOrSTDIN(Path, /*IsText=*/true);
if (std::error_code EC = BufferOr.getError())
return errorCodeToError(EC);
std::unique_ptr<MemoryBuffer> Buffer(BufferOr.get().release());
if (Buffer->getBufferSize() == 0)
return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
if (!RawMemProfReader::hasFormat(*Buffer))
return make_error<InstrProfError>(instrprof_error::bad_magic);
if (Buffer->getBufferSize() < sizeof(Header)) {
return make_error<InstrProfError>(instrprof_error::truncated);
}
// The size of the buffer can be > header total size since we allow repeated
// serialization of memprof profiles to the same file.
uint64_t TotalSize = 0;
const char *Next = Buffer->getBufferStart();
while (Next < Buffer->getBufferEnd()) {
auto *H = reinterpret_cast<const Header *>(Next);
if (H->Version != MEMPROF_RAW_VERSION) {
return make_error<InstrProfError>(instrprof_error::unsupported_version);
}
TotalSize += H->TotalSize;
Next += H->TotalSize;
}
if (Buffer->getBufferSize() != TotalSize) {
return make_error<InstrProfError>(instrprof_error::malformed);
}
return std::make_unique<RawMemProfReader>(std::move(Buffer));
}
bool RawMemProfReader::hasFormat(const MemoryBuffer &Buffer) {
if (Buffer.getBufferSize() < sizeof(uint64_t))
return false;
uint64_t Magic = *reinterpret_cast<const uint64_t *>(Buffer.getBufferStart());
return Magic == MEMPROF_RAW_MAGIC_64;
}
void RawMemProfReader::printSummaries(raw_ostream &OS) const {
int Count = 0;
const char *Next = DataBuffer->getBufferStart();
while (Next < DataBuffer->getBufferEnd()) {
auto Summary = computeSummary(Next);
OS << "MemProf Profile " << ++Count << "\n";
OS << " Version: " << Summary.Version << "\n";
OS << " TotalSizeBytes: " << Summary.TotalSizeBytes << "\n";
OS << " NumSegments: " << Summary.NumSegments << "\n";
OS << " NumMIBInfo: " << Summary.NumMIBInfo << "\n";
OS << " NumStackOffsets: " << Summary.NumStackOffsets << "\n";
// TODO: Print the build ids once we can record them using the
// sanitizer_procmaps library for linux.
auto *H = reinterpret_cast<const Header *>(Next);
Next += H->TotalSize;
}
}
} // namespace memprof
} // namespace llvm