1 //===- RawMemProfReader.cpp - Instrumented memory profiling reader --------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains support for reading MemProf profiling data.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include <cstdint>
14 
15 #include "llvm/ProfileData/InstrProf.h"
16 #include "llvm/ProfileData/MemProfData.inc"
17 #include "llvm/ProfileData/RawMemProfReader.h"
18 
19 namespace llvm {
20 namespace memprof {
21 namespace {
22 
23 struct Summary {
24   uint64_t Version;
25   uint64_t TotalSizeBytes;
26   uint64_t NumSegments;
27   uint64_t NumMIBInfo;
28   uint64_t NumStackOffsets;
29 };
30 
31 Summary computeSummary(const char *Start) {
32   auto *H = reinterpret_cast<const Header *>(Start);
33 
34   return Summary{
35       H->Version,
36       H->TotalSize,
37       *reinterpret_cast<const uint64_t *>(Start + H->SegmentOffset),
38       *reinterpret_cast<const uint64_t *>(Start + H->MIBOffset),
39       *reinterpret_cast<const uint64_t *>(Start + H->StackOffset),
40   };
41 }
42 
43 } // namespace
44 
45 Expected<std::unique_ptr<RawMemProfReader>>
46 RawMemProfReader::create(const Twine &Path) {
47   auto BufferOr = MemoryBuffer::getFileOrSTDIN(Path, /*IsText=*/true);
48   if (std::error_code EC = BufferOr.getError())
49     return errorCodeToError(EC);
50 
51   std::unique_ptr<MemoryBuffer> Buffer(BufferOr.get().release());
52 
53   if (Buffer->getBufferSize() == 0)
54     return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
55 
56   if (!RawMemProfReader::hasFormat(*Buffer))
57     return make_error<InstrProfError>(instrprof_error::bad_magic);
58 
59   if (Buffer->getBufferSize() < sizeof(Header)) {
60     return make_error<InstrProfError>(instrprof_error::truncated);
61   }
62 
63   // The size of the buffer can be > header total size since we allow repeated
64   // serialization of memprof profiles to the same file.
65   uint64_t TotalSize = 0;
66   const char *Next = Buffer->getBufferStart();
67   while (Next < Buffer->getBufferEnd()) {
68     auto *H = reinterpret_cast<const Header *>(Next);
69     if (H->Version != MEMPROF_RAW_VERSION) {
70       return make_error<InstrProfError>(instrprof_error::unsupported_version);
71     }
72 
73     TotalSize += H->TotalSize;
74     Next += H->TotalSize;
75   }
76 
77   if (Buffer->getBufferSize() != TotalSize) {
78     return make_error<InstrProfError>(instrprof_error::malformed);
79   }
80 
81   return std::make_unique<RawMemProfReader>(std::move(Buffer));
82 }
83 
84 bool RawMemProfReader::hasFormat(const MemoryBuffer &Buffer) {
85   if (Buffer.getBufferSize() < sizeof(uint64_t))
86     return false;
87   uint64_t Magic = *reinterpret_cast<const uint64_t *>(Buffer.getBufferStart());
88   return Magic == MEMPROF_RAW_MAGIC_64;
89 }
90 
91 void RawMemProfReader::printSummaries(raw_ostream &OS) const {
92   int Count = 0;
93   const char *Next = DataBuffer->getBufferStart();
94   while (Next < DataBuffer->getBufferEnd()) {
95     auto Summary = computeSummary(Next);
96     OS << "MemProf Profile " << ++Count << "\n";
97     OS << "  Version: " << Summary.Version << "\n";
98     OS << "  TotalSizeBytes: " << Summary.TotalSizeBytes << "\n";
99     OS << "  NumSegments: " << Summary.NumSegments << "\n";
100     OS << "  NumMIBInfo: " << Summary.NumMIBInfo << "\n";
101     OS << "  NumStackOffsets: " << Summary.NumStackOffsets << "\n";
102     // TODO: Print the build ids once we can record them using the
103     // sanitizer_procmaps library for linux.
104 
105     auto *H = reinterpret_cast<const Header *>(Next);
106     Next += H->TotalSize;
107   }
108 }
109 
110 } // namespace memprof
111 } // namespace llvm
112