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