| //===-- 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 <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 |
| /// None if no function is called from this block. |
| llvm::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, None otherwise. |
| void AddCallInstructionMetadata(lldb::addr_t load_addr, |
| llvm::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 (None if function |
| // name can't be determined) |
| std::unordered_map<lldb::addr_t, llvm::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 |