1 //===-- TraceHTR.h --------------------------------------------------------===//
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 #ifndef LLDB_TARGET_TRACE_HTR_H
10 #define LLDB_TARGET_TRACE_HTR_H
11 
12 #include "lldb/Target/Thread.h"
13 #include "lldb/Target/Trace.h"
14 
15 #include <optional>
16 #include <unordered_map>
17 #include <unordered_set>
18 
19 namespace lldb_private {
20 
21 /// Metadata associated with an HTR block
22 /// See lldb/docs/htr.rst for comprehensive HTR documentation
23 class HTRBlockMetadata {
24 public:
25   /// Constructor for a block's metadata.
26   ///
27   /// \param[in] first_instruction_load_address
28   ///     The load address of the block's first instruction.
29   ///
30   /// \param[in] num_instructions
31   ///     The total number of instructions in the block.
32   ///
33   /// \param[in] func_calls
34   ///     The map of a function name to the number of times it is called from
35   ///     the block.
36   HTRBlockMetadata(lldb::addr_t first_instruction_load_address,
37                    size_t num_instructions,
38                    llvm::DenseMap<ConstString, size_t> &&func_calls)
39       : m_first_instruction_load_address(first_instruction_load_address),
40         m_num_instructions(num_instructions), m_func_calls(func_calls) {}
41 
42   /// Merge two \a HTRBlockMetadata in place.
43   ///
44   /// \param[in][out] merged_metadata
45   ///     Metadata that metadata_to_merge will be merged into.
46   ///
47   /// \param[in] metadata_to_merge
48   ///     Metadata to merge into merged_metadata.
49   static void MergeMetadata(HTRBlockMetadata &merged_metadata,
50                             HTRBlockMetadata const &metadata_to_merge);
51   /// Get the number of instructions in the block.
52   ///
53   /// \return
54   ///     The number of instructions in the block.
55   size_t GetNumInstructions() const;
56 
57   /// Get the name of the most frequently called function from the block.
58   ///
59   /// \return
60   ///     The name of the function that is called the most from this block or
61   ///     std::nullopt if no function is called from this block.
62   std::optional<llvm::StringRef> GetMostFrequentlyCalledFunction() const;
63 
64   /// Get the load address of the first instruction in the block.
65   ///
66   /// \return
67   ///     The load address of the first instruction in the block.
68   lldb::addr_t GetFirstInstructionLoadAddress() const;
69 
70   /// Get the function calls map for the block.
71   /// Function calls are identified in the instruction layer by finding 'call'
72   /// instructions and determining the function they are calling. As these
73   /// instructions are merged into blocks, we merge these different function
74   /// calls into a single map containing the function names to the number of
75   /// times it is called from this block.
76   ///
77   /// \return
78   ///     The mapping of function name to the number of times it is called from
79   ///     this block.
80   llvm::DenseMap<ConstString, size_t> const &GetFunctionCalls() const;
81 
82 private:
83   lldb::addr_t m_first_instruction_load_address;
84   size_t m_num_instructions;
85   llvm::DenseMap<ConstString, size_t> m_func_calls;
86 };
87 
88 /// Block structure representing a sequence of trace "units" (ie instructions).
89 /// Sequences of blocks are merged to create a new, single block
90 /// See lldb/docs/htr.rst for comprehensive HTR documentation
91 class HTRBlock {
92 public:
93   /// Constructor for a block of an HTR layer.
94   ///
95   /// \param[in] offset
96   ///     The offset of the start of this block in the previous layer.
97   ///
98   /// \param[in] size
99   ///     Number of blocks/instructions that make up this block in the previous
100   ///     layer.
101   ///
102   /// \param[in] metadata
103   ///     General metadata for this block.
104   HTRBlock(size_t offset, size_t size, HTRBlockMetadata metadata)
105       : m_offset(offset), m_size(size), m_metadata(metadata) {}
106 
107   /// Get the offset of the start of this block in the previous layer.
108   ///
109   /// \return
110   ///     The offset of the block.
111   size_t GetOffset() const;
112 
113   /// Get the number of blocks/instructions that make up this block in the
114   /// previous layer.
115   ///
116   /// \return
117   ///     The size of the block.
118   size_t GetSize() const;
119 
120   /// Get the metadata for this block.
121   ///
122   /// \return
123   ///     The metadata of the block.
124   HTRBlockMetadata const &GetMetadata() const;
125 
126 private:
127   /// Offset in the previous layer
128   size_t m_offset;
129   /// Number of blocks/instructions that make up this block in the previous
130   /// layer
131   size_t m_size;
132   /// General metadata for this block
133   HTRBlockMetadata m_metadata;
134 };
135 
136 /// HTR layer interface
137 /// See lldb/docs/htr.rst for comprehensive HTR documentation
138 class IHTRLayer {
139 public:
140   /// Construct new HTR layer.
141   //
142   /// \param[in] id
143   ///     The layer's id.
144   IHTRLayer(size_t id) : m_layer_id(id) {}
145 
146   /// Get the ID of the layer.
147   ///
148   /// \return
149   ///     The layer ID of this layer.
150   size_t GetLayerId() const;
151 
152   /// Get the metadata of a unit (instruction or block) in the layer.
153   ///
154   /// \param[in] index
155   ///     The position of the unit in the layer.
156   ///
157   /// \return
158   ///     The metadata of the unit in the layer.
159   virtual HTRBlockMetadata GetMetadataByIndex(size_t index) const = 0;
160 
161   /// Get the total number of units (instruction or block) in this layer.
162   ///
163   /// \return
164   ///     The total number of units in the layer.
165   virtual size_t GetNumUnits() const = 0;
166 
167   /// Creates a new block from the result of merging a contiguous sequence of
168   /// "units" (instructions or blocks depending on layer type) in this layer
169   /// This allows the implementation class to decide how to store/generate this
170   /// metadata. For example, in the case of the instruction layer we want to
171   /// lazily generate this metadata instead of storing it for each instruction.
172   ///
173   /// \param[in] start_unit_index
174   ///     The index of the first unit to be merged.
175   ///
176   /// \param[in] num_units
177   ///     The number of units to be merged. Must be >= 1, since merging 0 blocks
178   ///     does not make sense.
179   ///
180   /// \return
181   ///     A new block instance representing the merge of the specified units.
182   HTRBlock MergeUnits(size_t start_unit_index, size_t num_units);
183 
184   virtual ~IHTRLayer() = default;
185 
186 protected:
187   /// ID of the layer.
188   size_t m_layer_id;
189 };
190 
191 /// "Base" layer of HTR representing the dynamic instructions of the trace.
192 /// See lldb/docs/htr.rst for comprehensive HTR documentation
193 class HTRInstructionLayer : public IHTRLayer {
194 public:
195   /// Construct new instruction layer.
196   //
197   /// \param[in] id
198   ///     The layer's id.
199   HTRInstructionLayer(size_t id) : IHTRLayer(id) {}
200 
201   size_t GetNumUnits() const override;
202 
203   HTRBlockMetadata GetMetadataByIndex(size_t index) const override;
204 
205   /// Get the dynamic instruction trace.
206   ///
207   /// \return
208   ///     The dynamic instruction trace.
209   llvm::ArrayRef<lldb::addr_t> GetInstructionTrace() const;
210 
211   /// Add metadata for a 'call' instruction of the trace.
212   ///
213   /// \param[in] load_addr
214   ///     The load address of the 'call' instruction.
215   ///
216   /// \param[in] func_name
217   ///     The name of the function the 'call' instruction is calling if it can
218   ///     be determined, std::nullopt otherwise.
219   void AddCallInstructionMetadata(lldb::addr_t load_addr,
220                                   std::optional<ConstString> func_name);
221 
222   /// Append the load address of an instruction to the dynamic instruction
223   /// trace.
224   ///
225   /// \param[in] load_addr
226   ///     The load address of the instruction.
227   void AppendInstruction(lldb::addr_t load_addr);
228 
229 private:
230   // Dynamic instructions of trace are stored in chronological order.
231   std::vector<lldb::addr_t> m_instruction_trace;
232   // Only store metadata for instructions of interest (call instructions)
233   // If we stored metadata for each instruction this would be wasteful since
234   // most instructions don't contain useful metadata
235 
236   // This map contains the load address of all the call instructions.
237   // load address maps to the name of the function it calls (std::nullopt if
238   // function name can't be determined)
239   std::unordered_map<lldb::addr_t, std::optional<ConstString>> m_call_isns;
240 };
241 
242 /// HTR layer composed of blocks of the trace.
243 /// See lldb/docs/htr.rst for comprehensive HTR documentation
244 class HTRBlockLayer : public IHTRLayer {
245 public:
246   /// Construct new block layer.
247   //
248   /// \param[in] id
249   ///     The layer's id.
250   HTRBlockLayer(size_t id) : IHTRLayer(id) {}
251 
252   size_t GetNumUnits() const override;
253 
254   HTRBlockMetadata GetMetadataByIndex(size_t index) const override;
255 
256   /// Get an \a HTRBlock from its block id.
257   ///
258   /// \param[in] block_id
259   ///     The id of the block to retrieve.
260   ///
261   /// \return
262   ///     The \a HTRBlock with the specified id, nullptr if no there is no block
263   ///     in the layer with the specified block id.
264   HTRBlock const *GetBlockById(size_t block_id) const;
265 
266   /// Get the block ID trace for this layer.
267   /// This block ID trace stores the block ID of each block that occured in the
268   /// trace and the block defs map maps block ID to the corresponding \a
269   /// HTRBlock.
270   ///
271   /// \return
272   ///     The block ID trace for this layer.
273   llvm::ArrayRef<size_t> GetBlockIdTrace() const;
274 
275   /// Appends a new block to the layer.
276   ///
277   /// \param[in] block_id
278   ///     The block id of the new block.
279   ///
280   /// \param[in] block
281   ///     The new \a HTRBlock to be appended to the layer. This block is moved
282   ///     into the layer.
283   void AppendNewBlock(size_t block_id, HTRBlock &&block);
284 
285   /// Appends a repeated block to the layer.
286   ///
287   /// \param[in] block_id
288   ///     The block id of the repeated block.
289   void AppendRepeatedBlock(size_t block_id);
290 
291 private:
292   /// Maps a unique Block ID to the corresponding HTRBlock
293   std::unordered_map<size_t, HTRBlock> m_block_defs;
294   /// Reduce memory footprint by just storing a trace of block IDs and use
295   /// m_block_defs to map a block_id to its corresponding HTRBlock
296   std::vector<size_t> m_block_id_trace;
297 };
298 
299 typedef std::unique_ptr<lldb_private::HTRBlockLayer> HTRBlockLayerUP;
300 typedef std::unique_ptr<lldb_private::HTRInstructionLayer>
301     HTRInstructionLayerUP;
302 
303 /// Top-level HTR class
304 /// See lldb/docs/htr.rst for comprehensive HTR documentation
305 class TraceHTR {
306 
307 public:
308   /// Constructor for a trace's HTR.
309   ///
310   /// \param[in] thread
311   ///     The thread the trace belongs to.
312   ///
313   /// \param[in] cursor
314   ///     The trace cursor that gives access to the trace's contents.
315   TraceHTR(Thread &thread, TraceCursor &cursor);
316 
317   /// Executes passes on the HTR layers until no further
318   /// summarization/compression is achieved
319   void ExecutePasses();
320 
321   /// Export HTR layers to the specified format and outfile.
322   ///
323   /// \param[in] outfile
324   ///     The file that the exported HTR data will be written to.
325   ///
326   /// \return
327   ///     Success if the export is successful, Error otherwise.
328   llvm::Error Export(std::string outfile);
329 
330   /// Get the block layers of this HTR.
331   ///
332   /// \return
333   ///     The block layers of this HTR.
334   llvm::ArrayRef<HTRBlockLayerUP> GetBlockLayers() const;
335 
336   /// Get the instruction layer of this HTR.
337   ///
338   /// \return
339   ///     The instruction layer of this HTR.
340   HTRInstructionLayer const &GetInstructionLayer() const;
341 
342   /// Add a new block layer to this HTR.
343   ///
344   /// \param[in]
345   ///     The new block layer to be added.
346   void AddNewBlockLayer(HTRBlockLayerUP &&block_layer);
347 
348 private:
349   // There is a single instruction layer per HTR
350   HTRInstructionLayerUP m_instruction_layer_up;
351   // There are one or more block layers per HTR
352   std::vector<HTRBlockLayerUP> m_block_layer_ups;
353 };
354 
355 // Serialization functions for exporting HTR to Chrome Trace Format
356 llvm::json::Value toJSON(const TraceHTR &htr);
357 llvm::json::Value toJSON(const HTRBlock &block);
358 llvm::json::Value toJSON(const HTRBlockMetadata &metadata);
359 
360 /// The HTR passes are defined below:
361 
362 /// Creates a new layer by merging the "basic super blocks" in the current layer
363 ///
364 /// A "basic super block" is the longest sequence of blocks that always occur in
365 /// the same order. (The concept is akin to “Basic Block" in compiler theory,
366 /// but refers to dynamic occurrences rather than CFG nodes)
367 ///
368 /// Procedure to find all basic super blocks:
369 //
370 ///   - For each block, compute the number of distinct predecessor and
371 ///   successor blocks.
372 ///       Predecessor - the block that occurs directly before (to the left of)
373 ///       the current block Successor  - the block that occurs directly after
374 ///       (to the right of) the current block
375 ///   - A block with more than one distinct successor is always the start of a
376 ///   super block, the super block will continue until the next block with
377 ///   more than one distinct predecessor or successor.
378 ///
379 /// The implementation makes use of two terms - 'heads' and 'tails' known as
380 /// the 'endpoints' of a basic super block:
381 ///   A 'head' is defined to be a block in the trace that doesn't have a
382 ///   unique predecessor
383 ///   A 'tail' is defined to be a block in the trace that doesn't have a
384 ///   unique successor
385 ///
386 /// A basic super block is defined to be a sequence of blocks between two
387 /// endpoints
388 ///
389 /// A head represents the start of the next group, so the current group
390 /// ends at the block preceding the head and the next group begins with
391 /// this head block
392 ///
393 /// A tail represents the end of the current group, so the current group
394 /// ends with the tail block and the next group begins with the
395 /// following block.
396 ///
397 /// See lldb/docs/htr.rst for comprehensive HTR documentation
398 ///
399 /// \param[in] layer
400 ///     The layer to execute the pass on.
401 ///
402 /// \return
403 ///     A new layer instance representing the merge of blocks in the
404 ///     previous layer
405 HTRBlockLayerUP BasicSuperBlockMerge(IHTRLayer &layer);
406 
407 } // namespace lldb_private
408 
409 #endif // LLDB_TARGET_TRACE_HTR_H
410