class RawMemProfReader {
public:
- RawMemProfReader(std::unique_ptr<MemoryBuffer> DataBuffer)
- : DataBuffer(std::move(DataBuffer)) {}
RawMemProfReader(const RawMemProfReader &) = delete;
RawMemProfReader &operator=(const RawMemProfReader &) = delete;
}
private:
- RawMemProfReader(std::unique_ptr<MemoryBuffer> DataBuffer,
- object::OwningBinary<object::Binary> &&Bin, bool KeepName)
- : DataBuffer(std::move(DataBuffer)), Binary(std::move(Bin)),
- KeepSymbolName(KeepName) {}
- Error initialize();
- Error readRawProfile();
+ RawMemProfReader(object::OwningBinary<object::Binary> &&Bin, bool KeepName)
+ : Binary(std::move(Bin)), KeepSymbolName(KeepName) {}
+ // Initializes the RawMemProfReader with the contents in `DataBuffer`.
+ Error initialize(std::unique_ptr<MemoryBuffer> DataBuffer);
+ // Read and parse the contents of the `DataBuffer` as a binary format profile.
+ Error readRawProfile(std::unique_ptr<MemoryBuffer> DataBuffer);
// Symbolize and cache all the virtual addresses we encounter in the
// callstacks from the raw profile. Also prune callstack frames which we can't
// symbolize or those that belong to the runtime. For profile entries where
}
object::SectionedAddress getModuleOffset(uint64_t VirtualAddress);
- // Prints aggregate counts for each raw profile parsed from the DataBuffer in
- // YAML format.
- void printSummaries(raw_ostream &OS) const;
- std::unique_ptr<MemoryBuffer> DataBuffer;
object::OwningBinary<object::Binary> Binary;
std::unique_ptr<llvm::symbolize::SymbolizableModule> Symbolizer;
namespace llvm {
namespace memprof {
namespace {
-
-struct Summary {
- uint64_t Version;
- uint64_t TotalSizeBytes;
- uint64_t NumSegments;
- uint64_t NumMIBInfo;
- uint64_t NumStackOffsets;
-};
-
template <class T = uint64_t> inline T alignedRead(const char *Ptr) {
static_assert(std::is_pod<T>::value, "Not a pod type.");
assert(reinterpret_cast<size_t>(Ptr) % sizeof(T) == 0 && "Unaligned Read");
return *reinterpret_cast<const T *>(Ptr);
}
-Summary computeSummary(const char *Start) {
- auto *H = reinterpret_cast<const Header *>(Start);
-
- // Check alignment while reading the number of items in each section.
- return Summary{
- H->Version,
- H->TotalSize,
- alignedRead(Start + H->SegmentOffset),
- alignedRead(Start + H->MIBOffset),
- alignedRead(Start + H->StackOffset),
- };
-}
-
Error checkBuffer(const MemoryBuffer &Buffer) {
if (!RawMemProfReader::hasFormat(Buffer))
return make_error<InstrProfError>(instrprof_error::bad_magic);
}
// Use new here since constructor is private.
- std::unique_ptr<RawMemProfReader> Reader(new RawMemProfReader(
- std::move(Buffer), std::move(BinaryOr.get()), KeepName));
- if (Error E = Reader->initialize()) {
+ std::unique_ptr<RawMemProfReader> Reader(
+ new RawMemProfReader(std::move(BinaryOr.get()), KeepName));
+ if (Error E = Reader->initialize(std::move(Buffer))) {
return std::move(E);
}
return std::move(Reader);
}
void RawMemProfReader::printYAML(raw_ostream &OS) {
+ uint64_t NumAllocFunctions = 0, NumMibInfo = 0;
+ for (const auto &KV : FunctionProfileData) {
+ const size_t NumAllocSites = KV.second.AllocSites.size();
+ if (NumAllocSites > 0) {
+ NumAllocFunctions++;
+ NumMibInfo += NumAllocSites;
+ }
+ }
+
OS << "MemprofProfile:\n";
- // TODO: Update printSummaries to print out the data after the profile has
- // been symbolized and pruned. We can parse some raw profile characteristics
- // from the data buffer for additional information.
- printSummaries(OS);
+ OS << " Summary:\n";
+ OS << " Version: " << MEMPROF_RAW_VERSION << "\n";
+ OS << " NumSegments: " << SegmentInfo.size() << "\n";
+ OS << " NumMibInfo: " << NumMibInfo << "\n";
+ OS << " NumAllocFunctions: " << NumAllocFunctions << "\n";
+ OS << " NumStackOffsets: " << StackMap.size() << "\n";
// Print out the merged contents of the profiles.
OS << " Records:\n";
for (const auto &Entry : *this) {
}
}
-void RawMemProfReader::printSummaries(raw_ostream &OS) const {
- const char *Next = DataBuffer->getBufferStart();
- while (Next < DataBuffer->getBufferEnd()) {
- auto Summary = computeSummary(Next);
- OS << " -\n";
- OS << " Header:\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;
- }
-}
-
-Error RawMemProfReader::initialize() {
+Error RawMemProfReader::initialize(std::unique_ptr<MemoryBuffer> DataBuffer) {
const StringRef FileName = Binary.getBinary()->getFileName();
auto *ElfObject = dyn_cast<object::ELFObjectFileBase>(Binary.getBinary());
return report(SOFOr.takeError(), FileName);
Symbolizer = std::move(SOFOr.get());
- if (Error E = readRawProfile())
+ if (Error E = readRawProfile(std::move(DataBuffer)))
return E;
if (Error E = symbolizeAndFilterStackFrames())
return Error::success();
}
-Error RawMemProfReader::readRawProfile() {
+Error RawMemProfReader::readRawProfile(
+ std::unique_ptr<MemoryBuffer> DataBuffer) {
const char *Next = DataBuffer->getBufferStart();
while (Next < DataBuffer->getBufferEnd()) {
We expect 2 MIB entries, 1 each for the malloc calls in the program.
-CHECK: MemprofProfile:
-CHECK-NEXT: -
-CHECK-NEXT: Header:
-CHECK-NEXT: Version: 1
-CHECK-NEXT: TotalSizeBytes: 864
-CHECK-NEXT: NumSegments: 9
-CHECK-NEXT: NumMibInfo: 2
-CHECK-NEXT: NumStackOffsets: 2
-CHECK-NEXT: -
-CHECK-NEXT: Header:
-CHECK-NEXT: Version: 1
-CHECK-NEXT: TotalSizeBytes: 864
-CHECK-NEXT: NumSegments: 9
-CHECK-NEXT: NumMibInfo: 2
-CHECK-NEXT: NumStackOffsets: 2
+CHECK: MemprofProfile:
+CHECK-NEXT: Summary:
+CHECK-NEXT: Version: 1
+CHECK-NEXT: NumSegments: 9
+CHECK-NEXT: NumMibInfo: 2
+CHECK-NEXT: NumAllocFunctions: 1
+CHECK-NEXT: NumStackOffsets: 2
+
+CHECK: SymbolName: main
+CHECK-NEXT: LineOffset: 1
+CHECK-NEXT: Column: 21
+
+CHECK: SymbolName: main
+CHECK-NEXT: LineOffset: 5
+CHECK-NEXT: Column: 15