summaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm18/include/llvm/ProfileData/RawMemProfReader.h
blob: 5521cfcb109321923968e871bc03debbaab370db (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#pragma once

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#ifndef LLVM_PROFILEDATA_RAWMEMPROFREADER_H_
#define LLVM_PROFILEDATA_RAWMEMPROFREADER_H_
//===- MemProfReader.h - Instrumented memory profiling reader ---*- C++ -*-===//
//
// 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 "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/ProfileData/MemProf.h"
#include "llvm/ProfileData/MemProfData.inc"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"

#include <functional>

namespace llvm {
namespace memprof {
// A class for memprof profile data populated directly from external
// sources.
// TODO: Rename this file to MemProfReader.h to better reflect the contents.
class MemProfReader {
public:
  // The MemProfReader only holds memory profile information.
  InstrProfKind getProfileKind() const { return InstrProfKind::MemProf; }

  using GuidMemProfRecordPair = std::pair<GlobalValue::GUID, MemProfRecord>;
  using Iterator = InstrProfIterator<GuidMemProfRecordPair, MemProfReader>;
  Iterator end() { return Iterator(); }
  Iterator begin() {
    Iter = FunctionProfileData.begin();
    return Iterator(this);
  }

  // Return a const reference to the internal Id to Frame mappings.
  const llvm::DenseMap<FrameId, Frame> &getFrameMapping() const {
    return IdToFrame;
  }

  // Return a const reference to the internal function profile data.
  const llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord> &
  getProfileData() const {
    return FunctionProfileData;
  }

  virtual Error
  readNextRecord(GuidMemProfRecordPair &GuidRecord,
                 std::function<const Frame(const FrameId)> Callback = nullptr) {
    if (FunctionProfileData.empty())
      return make_error<InstrProfError>(instrprof_error::empty_raw_profile);

    if (Iter == FunctionProfileData.end())
      return make_error<InstrProfError>(instrprof_error::eof);

    if (Callback == nullptr)
      Callback =
          std::bind(&MemProfReader::idToFrame, this, std::placeholders::_1);

    const IndexedMemProfRecord &IndexedRecord = Iter->second;
    GuidRecord = {Iter->first, MemProfRecord(IndexedRecord, Callback)};
    Iter++;
    return Error::success();
  }

  // Allow default construction for derived classes which can populate the
  // contents after construction.
  MemProfReader() = default;
  virtual ~MemProfReader() = default;

  // Initialize the MemProfReader with the frame mappings and profile contents.
  MemProfReader(
      llvm::DenseMap<FrameId, Frame> FrameIdMap,
      llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord> ProfData)
      : IdToFrame(std::move(FrameIdMap)),
        FunctionProfileData(std::move(ProfData)) {}

protected:
  // A helper method to extract the frame from the IdToFrame map.
  const Frame &idToFrame(const FrameId Id) const {
    auto It = IdToFrame.find(Id);
    assert(It != IdToFrame.end() && "Id not found in map.");
    return It->getSecond();
  }
  // A mapping from FrameId (a hash of the contents) to the frame.
  llvm::DenseMap<FrameId, Frame> IdToFrame;
  // A mapping from function GUID, hash of the canonical function symbol to the
  // memprof profile data for that function, i.e allocation and callsite info.
  llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord> FunctionProfileData;
  // An iterator to the internal function profile data structure.
  llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord>::iterator Iter;
};

// Map from id (recorded from sanitizer stack depot) to virtual addresses for
// each program counter address in the callstack.
using CallStackMap = llvm::DenseMap<uint64_t, llvm::SmallVector<uint64_t>>;

// Specializes the MemProfReader class to populate the contents from raw binary
// memprof profiles from instrumentation based profiling.
class RawMemProfReader final : public MemProfReader {
public:
  RawMemProfReader(const RawMemProfReader &) = delete;
  RawMemProfReader &operator=(const RawMemProfReader &) = delete;
  virtual ~RawMemProfReader() override = default;

  // Prints the contents of the profile in YAML format.
  void printYAML(raw_ostream &OS);

  // Return true if the \p DataBuffer starts with magic bytes indicating it is
  // a raw binary memprof profile.
  static bool hasFormat(const MemoryBuffer &DataBuffer);
  // Return true if the file at \p Path starts with magic bytes indicating it is
  // a raw binary memprof profile.
  static bool hasFormat(const StringRef Path);

  // Create a RawMemProfReader after sanity checking the contents of the file at
  // \p Path or the \p Buffer. The binary from which the profile has been
  // collected is specified via a path in \p ProfiledBinary.
  static Expected<std::unique_ptr<RawMemProfReader>>
  create(const Twine &Path, StringRef ProfiledBinary, bool KeepName = false);
  static Expected<std::unique_ptr<RawMemProfReader>>
  create(std::unique_ptr<MemoryBuffer> Buffer, StringRef ProfiledBinary,
         bool KeepName = false);

  // Returns a list of build ids recorded in the segment information.
  static std::vector<std::string> peekBuildIds(MemoryBuffer *DataBuffer);

  virtual Error
  readNextRecord(GuidMemProfRecordPair &GuidRecord,
                 std::function<const Frame(const FrameId)> Callback) override;

  // Constructor for unittests only.
  RawMemProfReader(std::unique_ptr<llvm::symbolize::SymbolizableModule> Sym,
                   llvm::SmallVectorImpl<SegmentEntry> &Seg,
                   llvm::MapVector<uint64_t, MemInfoBlock> &Prof,
                   CallStackMap &SM, bool KeepName = false)
      : SegmentInfo(Seg.begin(), Seg.end()), CallstackProfileData(Prof),
        StackMap(SM), KeepSymbolName(KeepName) {
    // We don't call initialize here since there is no raw profile to read. The
    // test should pass in the raw profile as structured data.

    // If there is an error here then the mock symbolizer has not been
    // initialized properly.
    if (Error E = symbolizeAndFilterStackFrames(std::move(Sym)))
      report_fatal_error(std::move(E));
    if (Error E = mapRawProfileToRecords())
      report_fatal_error(std::move(E));
  }

private:
  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);
  // Initialize the segment mapping information for symbolization.
  Error setupForSymbolization();
  // 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
  // the entire callstack is pruned, we drop the entry from the profile.
  Error symbolizeAndFilterStackFrames(
      std::unique_ptr<llvm::symbolize::SymbolizableModule> Symbolizer);
  // Construct memprof records for each function and store it in the
  // `FunctionProfileData` map. A function may have allocation profile data or
  // callsite data or both.
  Error mapRawProfileToRecords();

  object::SectionedAddress getModuleOffset(uint64_t VirtualAddress);

  // The profiled binary.
  object::OwningBinary<object::Binary> Binary;
  // The preferred load address of the executable segment.
  uint64_t PreferredTextSegmentAddress = 0;
  // The base address of the text segment in the process during profiling.
  uint64_t ProfiledTextSegmentStart = 0;
  // The limit address of the text segment in the process during profiling.
  uint64_t ProfiledTextSegmentEnd = 0;

  // The memory mapped segment information for all executable segments in the
  // profiled binary (filtered from the raw profile using the build id).
  llvm::SmallVector<SegmentEntry, 2> SegmentInfo;

  // A map from callstack id (same as key in CallStackMap below) to the heap
  // information recorded for that allocation context.
  llvm::MapVector<uint64_t, MemInfoBlock> CallstackProfileData;
  CallStackMap StackMap;

  // Cached symbolization from PC to Frame.
  llvm::DenseMap<uint64_t, llvm::SmallVector<FrameId>> SymbolizedFrame;

  // Whether to keep the symbol name for each frame after hashing.
  bool KeepSymbolName = false;
  // A mapping of the hash to symbol name, only used if KeepSymbolName is true.
  llvm::DenseMap<uint64_t, std::string> GuidToSymbolName;
};
} // namespace memprof
} // namespace llvm

#endif // LLVM_PROFILEDATA_RAWMEMPROFREADER_H_

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif