1 //===- RawMemProfReader.cpp - Instrumented memory profiling reader --------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains support for reading MemProf profiling data.
11 //===----------------------------------------------------------------------===//
14 #include <type_traits>
16 #include "llvm/ProfileData/InstrProf.h"
17 #include "llvm/ProfileData/MemProfData.inc"
18 #include "llvm/ProfileData/RawMemProfReader.h"
26 uint64_t TotalSizeBytes
;
29 uint64_t NumStackOffsets
;
32 template <class T
= uint64_t> inline T
alignedRead(const char *Ptr
) {
33 static_assert(std::is_pod
<T
>::value
, "Not a pod type.");
34 assert(reinterpret_cast<size_t>(Ptr
) % sizeof(T
) == 0 && "Unaligned Read");
35 return *reinterpret_cast<const T
*>(Ptr
);
38 Summary
computeSummary(const char *Start
) {
39 auto *H
= reinterpret_cast<const Header
*>(Start
);
41 // Check alignment while reading the number of items in each section.
45 alignedRead(Start
+ H
->SegmentOffset
),
46 alignedRead(Start
+ H
->MIBOffset
),
47 alignedRead(Start
+ H
->StackOffset
),
53 Expected
<std::unique_ptr
<RawMemProfReader
>>
54 RawMemProfReader::create(const Twine
&Path
) {
55 auto BufferOr
= MemoryBuffer::getFileOrSTDIN(Path
, /*IsText=*/true);
56 if (std::error_code EC
= BufferOr
.getError())
57 return errorCodeToError(EC
);
59 std::unique_ptr
<MemoryBuffer
> Buffer(BufferOr
.get().release());
61 if (Buffer
->getBufferSize() == 0)
62 return make_error
<InstrProfError
>(instrprof_error::empty_raw_profile
);
64 if (!RawMemProfReader::hasFormat(*Buffer
))
65 return make_error
<InstrProfError
>(instrprof_error::bad_magic
);
67 if (Buffer
->getBufferSize() < sizeof(Header
)) {
68 return make_error
<InstrProfError
>(instrprof_error::truncated
);
71 // The size of the buffer can be > header total size since we allow repeated
72 // serialization of memprof profiles to the same file.
73 uint64_t TotalSize
= 0;
74 const char *Next
= Buffer
->getBufferStart();
75 while (Next
< Buffer
->getBufferEnd()) {
76 auto *H
= reinterpret_cast<const Header
*>(Next
);
77 if (H
->Version
!= MEMPROF_RAW_VERSION
) {
78 return make_error
<InstrProfError
>(instrprof_error::unsupported_version
);
81 TotalSize
+= H
->TotalSize
;
85 if (Buffer
->getBufferSize() != TotalSize
) {
86 return make_error
<InstrProfError
>(instrprof_error::malformed
);
89 return std::make_unique
<RawMemProfReader
>(std::move(Buffer
));
92 bool RawMemProfReader::hasFormat(const MemoryBuffer
&Buffer
) {
93 if (Buffer
.getBufferSize() < sizeof(uint64_t))
95 // Aligned read to sanity check that the buffer was allocated with at least 8b
97 const uint64_t Magic
= alignedRead(Buffer
.getBufferStart());
98 return Magic
== MEMPROF_RAW_MAGIC_64
;
101 void RawMemProfReader::printSummaries(raw_ostream
&OS
) const {
103 const char *Next
= DataBuffer
->getBufferStart();
104 while (Next
< DataBuffer
->getBufferEnd()) {
105 auto Summary
= computeSummary(Next
);
106 OS
<< "MemProf Profile " << ++Count
<< "\n";
107 OS
<< " Version: " << Summary
.Version
<< "\n";
108 OS
<< " TotalSizeBytes: " << Summary
.TotalSizeBytes
<< "\n";
109 OS
<< " NumSegments: " << Summary
.NumSegments
<< "\n";
110 OS
<< " NumMIBInfo: " << Summary
.NumMIBInfo
<< "\n";
111 OS
<< " NumStackOffsets: " << Summary
.NumStackOffsets
<< "\n";
112 // TODO: Print the build ids once we can record them using the
113 // sanitizer_procmaps library for linux.
115 auto *H
= reinterpret_cast<const Header
*>(Next
);
116 Next
+= H
->TotalSize
;
120 } // namespace memprof