File: TraceHTR.h

package info (click to toggle)
llvm-toolchain-18 1%3A18.1.8-18
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,908,340 kB
  • sloc: cpp: 6,667,937; ansic: 1,440,452; asm: 883,619; python: 230,549; objc: 76,880; f90: 74,238; lisp: 35,989; pascal: 16,571; sh: 10,229; perl: 7,459; ml: 5,047; awk: 3,523; makefile: 2,987; javascript: 2,149; xml: 892; fortran: 649; cs: 573
file content (409 lines) | stat: -rw-r--r-- 13,966 bytes parent folder | download | duplicates (10)
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
//===-- TraceHTR.h --------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_TARGET_TRACE_HTR_H
#define LLDB_TARGET_TRACE_HTR_H

#include "lldb/Target/Thread.h"
#include "lldb/Target/Trace.h"

#include <optional>
#include <unordered_map>
#include <unordered_set>

namespace lldb_private {

/// Metadata associated with an HTR block
/// See lldb/docs/htr.rst for comprehensive HTR documentation
class HTRBlockMetadata {
public:
  /// Constructor for a block's metadata.
  ///
  /// \param[in] first_instruction_load_address
  ///     The load address of the block's first instruction.
  ///
  /// \param[in] num_instructions
  ///     The total number of instructions in the block.
  ///
  /// \param[in] func_calls
  ///     The map of a function name to the number of times it is called from
  ///     the block.
  HTRBlockMetadata(lldb::addr_t first_instruction_load_address,
                   size_t num_instructions,
                   llvm::DenseMap<ConstString, size_t> &&func_calls)
      : m_first_instruction_load_address(first_instruction_load_address),
        m_num_instructions(num_instructions), m_func_calls(func_calls) {}

  /// Merge two \a HTRBlockMetadata in place.
  ///
  /// \param[in][out] merged_metadata
  ///     Metadata that metadata_to_merge will be merged into.
  ///
  /// \param[in] metadata_to_merge
  ///     Metadata to merge into merged_metadata.
  static void MergeMetadata(HTRBlockMetadata &merged_metadata,
                            HTRBlockMetadata const &metadata_to_merge);
  /// Get the number of instructions in the block.
  ///
  /// \return
  ///     The number of instructions in the block.
  size_t GetNumInstructions() const;

  /// Get the name of the most frequently called function from the block.
  ///
  /// \return
  ///     The name of the function that is called the most from this block or
  ///     std::nullopt if no function is called from this block.
  std::optional<llvm::StringRef> GetMostFrequentlyCalledFunction() const;

  /// Get the load address of the first instruction in the block.
  ///
  /// \return
  ///     The load address of the first instruction in the block.
  lldb::addr_t GetFirstInstructionLoadAddress() const;

  /// Get the function calls map for the block.
  /// Function calls are identified in the instruction layer by finding 'call'
  /// instructions and determining the function they are calling. As these
  /// instructions are merged into blocks, we merge these different function
  /// calls into a single map containing the function names to the number of
  /// times it is called from this block.
  ///
  /// \return
  ///     The mapping of function name to the number of times it is called from
  ///     this block.
  llvm::DenseMap<ConstString, size_t> const &GetFunctionCalls() const;

private:
  lldb::addr_t m_first_instruction_load_address;
  size_t m_num_instructions;
  llvm::DenseMap<ConstString, size_t> m_func_calls;
};

/// Block structure representing a sequence of trace "units" (ie instructions).
/// Sequences of blocks are merged to create a new, single block
/// See lldb/docs/htr.rst for comprehensive HTR documentation
class HTRBlock {
public:
  /// Constructor for a block of an HTR layer.
  ///
  /// \param[in] offset
  ///     The offset of the start of this block in the previous layer.
  ///
  /// \param[in] size
  ///     Number of blocks/instructions that make up this block in the previous
  ///     layer.
  ///
  /// \param[in] metadata
  ///     General metadata for this block.
  HTRBlock(size_t offset, size_t size, HTRBlockMetadata metadata)
      : m_offset(offset), m_size(size), m_metadata(metadata) {}

  /// Get the offset of the start of this block in the previous layer.
  ///
  /// \return
  ///     The offset of the block.
  size_t GetOffset() const;

  /// Get the number of blocks/instructions that make up this block in the
  /// previous layer.
  ///
  /// \return
  ///     The size of the block.
  size_t GetSize() const;

  /// Get the metadata for this block.
  ///
  /// \return
  ///     The metadata of the block.
  HTRBlockMetadata const &GetMetadata() const;

private:
  /// Offset in the previous layer
  size_t m_offset;
  /// Number of blocks/instructions that make up this block in the previous
  /// layer
  size_t m_size;
  /// General metadata for this block
  HTRBlockMetadata m_metadata;
};

/// HTR layer interface
/// See lldb/docs/htr.rst for comprehensive HTR documentation
class IHTRLayer {
public:
  /// Construct new HTR layer.
  //
  /// \param[in] id
  ///     The layer's id.
  IHTRLayer(size_t id) : m_layer_id(id) {}

  /// Get the ID of the layer.
  ///
  /// \return
  ///     The layer ID of this layer.
  size_t GetLayerId() const;

  /// Get the metadata of a unit (instruction or block) in the layer.
  ///
  /// \param[in] index
  ///     The position of the unit in the layer.
  ///
  /// \return
  ///     The metadata of the unit in the layer.
  virtual HTRBlockMetadata GetMetadataByIndex(size_t index) const = 0;

  /// Get the total number of units (instruction or block) in this layer.
  ///
  /// \return
  ///     The total number of units in the layer.
  virtual size_t GetNumUnits() const = 0;

  /// Creates a new block from the result of merging a contiguous sequence of
  /// "units" (instructions or blocks depending on layer type) in this layer
  /// This allows the implementation class to decide how to store/generate this
  /// metadata. For example, in the case of the instruction layer we want to
  /// lazily generate this metadata instead of storing it for each instruction.
  ///
  /// \param[in] start_unit_index
  ///     The index of the first unit to be merged.
  ///
  /// \param[in] num_units
  ///     The number of units to be merged. Must be >= 1, since merging 0 blocks
  ///     does not make sense.
  ///
  /// \return
  ///     A new block instance representing the merge of the specified units.
  HTRBlock MergeUnits(size_t start_unit_index, size_t num_units);

  virtual ~IHTRLayer() = default;

protected:
  /// ID of the layer.
  size_t m_layer_id;
};

/// "Base" layer of HTR representing the dynamic instructions of the trace.
/// See lldb/docs/htr.rst for comprehensive HTR documentation
class HTRInstructionLayer : public IHTRLayer {
public:
  /// Construct new instruction layer.
  //
  /// \param[in] id
  ///     The layer's id.
  HTRInstructionLayer(size_t id) : IHTRLayer(id) {}

  size_t GetNumUnits() const override;

  HTRBlockMetadata GetMetadataByIndex(size_t index) const override;

  /// Get the dynamic instruction trace.
  ///
  /// \return
  ///     The dynamic instruction trace.
  llvm::ArrayRef<lldb::addr_t> GetInstructionTrace() const;

  /// Add metadata for a 'call' instruction of the trace.
  ///
  /// \param[in] load_addr
  ///     The load address of the 'call' instruction.
  ///
  /// \param[in] func_name
  ///     The name of the function the 'call' instruction is calling if it can
  ///     be determined, std::nullopt otherwise.
  void AddCallInstructionMetadata(lldb::addr_t load_addr,
                                  std::optional<ConstString> func_name);

  /// Append the load address of an instruction to the dynamic instruction
  /// trace.
  ///
  /// \param[in] load_addr
  ///     The load address of the instruction.
  void AppendInstruction(lldb::addr_t load_addr);

private:
  // Dynamic instructions of trace are stored in chronological order.
  std::vector<lldb::addr_t> m_instruction_trace;
  // Only store metadata for instructions of interest (call instructions)
  // If we stored metadata for each instruction this would be wasteful since
  // most instructions don't contain useful metadata

  // This map contains the load address of all the call instructions.
  // load address maps to the name of the function it calls (std::nullopt if
  // function name can't be determined)
  std::unordered_map<lldb::addr_t, std::optional<ConstString>> m_call_isns;
};

/// HTR layer composed of blocks of the trace.
/// See lldb/docs/htr.rst for comprehensive HTR documentation
class HTRBlockLayer : public IHTRLayer {
public:
  /// Construct new block layer.
  //
  /// \param[in] id
  ///     The layer's id.
  HTRBlockLayer(size_t id) : IHTRLayer(id) {}

  size_t GetNumUnits() const override;

  HTRBlockMetadata GetMetadataByIndex(size_t index) const override;

  /// Get an \a HTRBlock from its block id.
  ///
  /// \param[in] block_id
  ///     The id of the block to retrieve.
  ///
  /// \return
  ///     The \a HTRBlock with the specified id, nullptr if no there is no block
  ///     in the layer with the specified block id.
  HTRBlock const *GetBlockById(size_t block_id) const;

  /// Get the block ID trace for this layer.
  /// This block ID trace stores the block ID of each block that occured in the
  /// trace and the block defs map maps block ID to the corresponding \a
  /// HTRBlock.
  ///
  /// \return
  ///     The block ID trace for this layer.
  llvm::ArrayRef<size_t> GetBlockIdTrace() const;

  /// Appends a new block to the layer.
  ///
  /// \param[in] block_id
  ///     The block id of the new block.
  ///
  /// \param[in] block
  ///     The new \a HTRBlock to be appended to the layer. This block is moved
  ///     into the layer.
  void AppendNewBlock(size_t block_id, HTRBlock &&block);

  /// Appends a repeated block to the layer.
  ///
  /// \param[in] block_id
  ///     The block id of the repeated block.
  void AppendRepeatedBlock(size_t block_id);

private:
  /// Maps a unique Block ID to the corresponding HTRBlock
  std::unordered_map<size_t, HTRBlock> m_block_defs;
  /// Reduce memory footprint by just storing a trace of block IDs and use
  /// m_block_defs to map a block_id to its corresponding HTRBlock
  std::vector<size_t> m_block_id_trace;
};

typedef std::unique_ptr<lldb_private::HTRBlockLayer> HTRBlockLayerUP;
typedef std::unique_ptr<lldb_private::HTRInstructionLayer>
    HTRInstructionLayerUP;

/// Top-level HTR class
/// See lldb/docs/htr.rst for comprehensive HTR documentation
class TraceHTR {

public:
  /// Constructor for a trace's HTR.
  ///
  /// \param[in] thread
  ///     The thread the trace belongs to.
  ///
  /// \param[in] cursor
  ///     The trace cursor that gives access to the trace's contents.
  TraceHTR(Thread &thread, TraceCursor &cursor);

  /// Executes passes on the HTR layers until no further
  /// summarization/compression is achieved
  void ExecutePasses();

  /// Export HTR layers to the specified format and outfile.
  ///
  /// \param[in] outfile
  ///     The file that the exported HTR data will be written to.
  ///
  /// \return
  ///     Success if the export is successful, Error otherwise.
  llvm::Error Export(std::string outfile);

  /// Get the block layers of this HTR.
  ///
  /// \return
  ///     The block layers of this HTR.
  llvm::ArrayRef<HTRBlockLayerUP> GetBlockLayers() const;

  /// Get the instruction layer of this HTR.
  ///
  /// \return
  ///     The instruction layer of this HTR.
  HTRInstructionLayer const &GetInstructionLayer() const;

  /// Add a new block layer to this HTR.
  ///
  /// \param[in]
  ///     The new block layer to be added.
  void AddNewBlockLayer(HTRBlockLayerUP &&block_layer);

private:
  // There is a single instruction layer per HTR
  HTRInstructionLayerUP m_instruction_layer_up;
  // There are one or more block layers per HTR
  std::vector<HTRBlockLayerUP> m_block_layer_ups;
};

// Serialization functions for exporting HTR to Chrome Trace Format
llvm::json::Value toJSON(const TraceHTR &htr);
llvm::json::Value toJSON(const HTRBlock &block);
llvm::json::Value toJSON(const HTRBlockMetadata &metadata);

/// The HTR passes are defined below:

/// Creates a new layer by merging the "basic super blocks" in the current layer
///
/// A "basic super block" is the longest sequence of blocks that always occur in
/// the same order. (The concept is akin to “Basic Block" in compiler theory,
/// but refers to dynamic occurrences rather than CFG nodes)
///
/// Procedure to find all basic super blocks:
//
///   - For each block, compute the number of distinct predecessor and
///   successor blocks.
///       Predecessor - the block that occurs directly before (to the left of)
///       the current block Successor  - the block that occurs directly after
///       (to the right of) the current block
///   - A block with more than one distinct successor is always the start of a
///   super block, the super block will continue until the next block with
///   more than one distinct predecessor or successor.
///
/// The implementation makes use of two terms - 'heads' and 'tails' known as
/// the 'endpoints' of a basic super block:
///   A 'head' is defined to be a block in the trace that doesn't have a
///   unique predecessor
///   A 'tail' is defined to be a block in the trace that doesn't have a
///   unique successor
///
/// A basic super block is defined to be a sequence of blocks between two
/// endpoints
///
/// A head represents the start of the next group, so the current group
/// ends at the block preceding the head and the next group begins with
/// this head block
///
/// A tail represents the end of the current group, so the current group
/// ends with the tail block and the next group begins with the
/// following block.
///
/// See lldb/docs/htr.rst for comprehensive HTR documentation
///
/// \param[in] layer
///     The layer to execute the pass on.
///
/// \return
///     A new layer instance representing the merge of blocks in the
///     previous layer
HTRBlockLayerUP BasicSuperBlockMerge(IHTRLayer &layer);

} // namespace lldb_private

#endif // LLDB_TARGET_TRACE_HTR_H