Path: blob/main/contrib/llvm-project/lldb/source/Plugins/TraceExporter/common/TraceHTR.h
39653 views
//===-- TraceHTR.h --------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLDB_TARGET_TRACE_HTR_H9#define LLDB_TARGET_TRACE_HTR_H1011#include "lldb/Target/Thread.h"12#include "lldb/Target/Trace.h"1314#include <optional>15#include <unordered_map>16#include <unordered_set>1718namespace lldb_private {1920/// Metadata associated with an HTR block21/// See lldb/docs/htr.rst for comprehensive HTR documentation22class HTRBlockMetadata {23public:24/// Constructor for a block's metadata.25///26/// \param[in] first_instruction_load_address27/// The load address of the block's first instruction.28///29/// \param[in] num_instructions30/// The total number of instructions in the block.31///32/// \param[in] func_calls33/// The map of a function name to the number of times it is called from34/// the block.35HTRBlockMetadata(lldb::addr_t first_instruction_load_address,36size_t num_instructions,37llvm::DenseMap<ConstString, size_t> &&func_calls)38: m_first_instruction_load_address(first_instruction_load_address),39m_num_instructions(num_instructions), m_func_calls(func_calls) {}4041/// Merge two \a HTRBlockMetadata in place.42///43/// \param[in][out] merged_metadata44/// Metadata that metadata_to_merge will be merged into.45///46/// \param[in] metadata_to_merge47/// Metadata to merge into merged_metadata.48static void MergeMetadata(HTRBlockMetadata &merged_metadata,49HTRBlockMetadata const &metadata_to_merge);50/// Get the number of instructions in the block.51///52/// \return53/// The number of instructions in the block.54size_t GetNumInstructions() const;5556/// Get the name of the most frequently called function from the block.57///58/// \return59/// The name of the function that is called the most from this block or60/// std::nullopt if no function is called from this block.61std::optional<llvm::StringRef> GetMostFrequentlyCalledFunction() const;6263/// Get the load address of the first instruction in the block.64///65/// \return66/// The load address of the first instruction in the block.67lldb::addr_t GetFirstInstructionLoadAddress() const;6869/// Get the function calls map for the block.70/// Function calls are identified in the instruction layer by finding 'call'71/// instructions and determining the function they are calling. As these72/// instructions are merged into blocks, we merge these different function73/// calls into a single map containing the function names to the number of74/// times it is called from this block.75///76/// \return77/// The mapping of function name to the number of times it is called from78/// this block.79llvm::DenseMap<ConstString, size_t> const &GetFunctionCalls() const;8081private:82lldb::addr_t m_first_instruction_load_address;83size_t m_num_instructions;84llvm::DenseMap<ConstString, size_t> m_func_calls;85};8687/// Block structure representing a sequence of trace "units" (ie instructions).88/// Sequences of blocks are merged to create a new, single block89/// See lldb/docs/htr.rst for comprehensive HTR documentation90class HTRBlock {91public:92/// Constructor for a block of an HTR layer.93///94/// \param[in] offset95/// The offset of the start of this block in the previous layer.96///97/// \param[in] size98/// Number of blocks/instructions that make up this block in the previous99/// layer.100///101/// \param[in] metadata102/// General metadata for this block.103HTRBlock(size_t offset, size_t size, HTRBlockMetadata metadata)104: m_offset(offset), m_size(size), m_metadata(metadata) {}105106/// Get the offset of the start of this block in the previous layer.107///108/// \return109/// The offset of the block.110size_t GetOffset() const;111112/// Get the number of blocks/instructions that make up this block in the113/// previous layer.114///115/// \return116/// The size of the block.117size_t GetSize() const;118119/// Get the metadata for this block.120///121/// \return122/// The metadata of the block.123HTRBlockMetadata const &GetMetadata() const;124125private:126/// Offset in the previous layer127size_t m_offset;128/// Number of blocks/instructions that make up this block in the previous129/// layer130size_t m_size;131/// General metadata for this block132HTRBlockMetadata m_metadata;133};134135/// HTR layer interface136/// See lldb/docs/htr.rst for comprehensive HTR documentation137class IHTRLayer {138public:139/// Construct new HTR layer.140//141/// \param[in] id142/// The layer's id.143IHTRLayer(size_t id) : m_layer_id(id) {}144145/// Get the ID of the layer.146///147/// \return148/// The layer ID of this layer.149size_t GetLayerId() const;150151/// Get the metadata of a unit (instruction or block) in the layer.152///153/// \param[in] index154/// The position of the unit in the layer.155///156/// \return157/// The metadata of the unit in the layer.158virtual HTRBlockMetadata GetMetadataByIndex(size_t index) const = 0;159160/// Get the total number of units (instruction or block) in this layer.161///162/// \return163/// The total number of units in the layer.164virtual size_t GetNumUnits() const = 0;165166/// Creates a new block from the result of merging a contiguous sequence of167/// "units" (instructions or blocks depending on layer type) in this layer168/// This allows the implementation class to decide how to store/generate this169/// metadata. For example, in the case of the instruction layer we want to170/// lazily generate this metadata instead of storing it for each instruction.171///172/// \param[in] start_unit_index173/// The index of the first unit to be merged.174///175/// \param[in] num_units176/// The number of units to be merged. Must be >= 1, since merging 0 blocks177/// does not make sense.178///179/// \return180/// A new block instance representing the merge of the specified units.181HTRBlock MergeUnits(size_t start_unit_index, size_t num_units);182183virtual ~IHTRLayer() = default;184185protected:186/// ID of the layer.187size_t m_layer_id;188};189190/// "Base" layer of HTR representing the dynamic instructions of the trace.191/// See lldb/docs/htr.rst for comprehensive HTR documentation192class HTRInstructionLayer : public IHTRLayer {193public:194/// Construct new instruction layer.195//196/// \param[in] id197/// The layer's id.198HTRInstructionLayer(size_t id) : IHTRLayer(id) {}199200size_t GetNumUnits() const override;201202HTRBlockMetadata GetMetadataByIndex(size_t index) const override;203204/// Get the dynamic instruction trace.205///206/// \return207/// The dynamic instruction trace.208llvm::ArrayRef<lldb::addr_t> GetInstructionTrace() const;209210/// Add metadata for a 'call' instruction of the trace.211///212/// \param[in] load_addr213/// The load address of the 'call' instruction.214///215/// \param[in] func_name216/// The name of the function the 'call' instruction is calling if it can217/// be determined, std::nullopt otherwise.218void AddCallInstructionMetadata(lldb::addr_t load_addr,219std::optional<ConstString> func_name);220221/// Append the load address of an instruction to the dynamic instruction222/// trace.223///224/// \param[in] load_addr225/// The load address of the instruction.226void AppendInstruction(lldb::addr_t load_addr);227228private:229// Dynamic instructions of trace are stored in chronological order.230std::vector<lldb::addr_t> m_instruction_trace;231// Only store metadata for instructions of interest (call instructions)232// If we stored metadata for each instruction this would be wasteful since233// most instructions don't contain useful metadata234235// This map contains the load address of all the call instructions.236// load address maps to the name of the function it calls (std::nullopt if237// function name can't be determined)238std::unordered_map<lldb::addr_t, std::optional<ConstString>> m_call_isns;239};240241/// HTR layer composed of blocks of the trace.242/// See lldb/docs/htr.rst for comprehensive HTR documentation243class HTRBlockLayer : public IHTRLayer {244public:245/// Construct new block layer.246//247/// \param[in] id248/// The layer's id.249HTRBlockLayer(size_t id) : IHTRLayer(id) {}250251size_t GetNumUnits() const override;252253HTRBlockMetadata GetMetadataByIndex(size_t index) const override;254255/// Get an \a HTRBlock from its block id.256///257/// \param[in] block_id258/// The id of the block to retrieve.259///260/// \return261/// The \a HTRBlock with the specified id, nullptr if no there is no block262/// in the layer with the specified block id.263HTRBlock const *GetBlockById(size_t block_id) const;264265/// Get the block ID trace for this layer.266/// This block ID trace stores the block ID of each block that occured in the267/// trace and the block defs map maps block ID to the corresponding \a268/// HTRBlock.269///270/// \return271/// The block ID trace for this layer.272llvm::ArrayRef<size_t> GetBlockIdTrace() const;273274/// Appends a new block to the layer.275///276/// \param[in] block_id277/// The block id of the new block.278///279/// \param[in] block280/// The new \a HTRBlock to be appended to the layer. This block is moved281/// into the layer.282void AppendNewBlock(size_t block_id, HTRBlock &&block);283284/// Appends a repeated block to the layer.285///286/// \param[in] block_id287/// The block id of the repeated block.288void AppendRepeatedBlock(size_t block_id);289290private:291/// Maps a unique Block ID to the corresponding HTRBlock292std::unordered_map<size_t, HTRBlock> m_block_defs;293/// Reduce memory footprint by just storing a trace of block IDs and use294/// m_block_defs to map a block_id to its corresponding HTRBlock295std::vector<size_t> m_block_id_trace;296};297298typedef std::unique_ptr<lldb_private::HTRBlockLayer> HTRBlockLayerUP;299typedef std::unique_ptr<lldb_private::HTRInstructionLayer>300HTRInstructionLayerUP;301302/// Top-level HTR class303/// See lldb/docs/htr.rst for comprehensive HTR documentation304class TraceHTR {305306public:307/// Constructor for a trace's HTR.308///309/// \param[in] thread310/// The thread the trace belongs to.311///312/// \param[in] cursor313/// The trace cursor that gives access to the trace's contents.314TraceHTR(Thread &thread, TraceCursor &cursor);315316/// Executes passes on the HTR layers until no further317/// summarization/compression is achieved318void ExecutePasses();319320/// Export HTR layers to the specified format and outfile.321///322/// \param[in] outfile323/// The file that the exported HTR data will be written to.324///325/// \return326/// Success if the export is successful, Error otherwise.327llvm::Error Export(std::string outfile);328329/// Get the block layers of this HTR.330///331/// \return332/// The block layers of this HTR.333llvm::ArrayRef<HTRBlockLayerUP> GetBlockLayers() const;334335/// Get the instruction layer of this HTR.336///337/// \return338/// The instruction layer of this HTR.339HTRInstructionLayer const &GetInstructionLayer() const;340341/// Add a new block layer to this HTR.342///343/// \param[in]344/// The new block layer to be added.345void AddNewBlockLayer(HTRBlockLayerUP &&block_layer);346347private:348// There is a single instruction layer per HTR349HTRInstructionLayerUP m_instruction_layer_up;350// There are one or more block layers per HTR351std::vector<HTRBlockLayerUP> m_block_layer_ups;352};353354// Serialization functions for exporting HTR to Chrome Trace Format355llvm::json::Value toJSON(const TraceHTR &htr);356llvm::json::Value toJSON(const HTRBlock &block);357llvm::json::Value toJSON(const HTRBlockMetadata &metadata);358359/// The HTR passes are defined below:360361/// Creates a new layer by merging the "basic super blocks" in the current layer362///363/// A "basic super block" is the longest sequence of blocks that always occur in364/// the same order. (The concept is akin to “Basic Block" in compiler theory,365/// but refers to dynamic occurrences rather than CFG nodes)366///367/// Procedure to find all basic super blocks:368//369/// - For each block, compute the number of distinct predecessor and370/// successor blocks.371/// Predecessor - the block that occurs directly before (to the left of)372/// the current block Successor - the block that occurs directly after373/// (to the right of) the current block374/// - A block with more than one distinct successor is always the start of a375/// super block, the super block will continue until the next block with376/// more than one distinct predecessor or successor.377///378/// The implementation makes use of two terms - 'heads' and 'tails' known as379/// the 'endpoints' of a basic super block:380/// A 'head' is defined to be a block in the trace that doesn't have a381/// unique predecessor382/// A 'tail' is defined to be a block in the trace that doesn't have a383/// unique successor384///385/// A basic super block is defined to be a sequence of blocks between two386/// endpoints387///388/// A head represents the start of the next group, so the current group389/// ends at the block preceding the head and the next group begins with390/// this head block391///392/// A tail represents the end of the current group, so the current group393/// ends with the tail block and the next group begins with the394/// following block.395///396/// See lldb/docs/htr.rst for comprehensive HTR documentation397///398/// \param[in] layer399/// The layer to execute the pass on.400///401/// \return402/// A new layer instance representing the merge of blocks in the403/// previous layer404HTRBlockLayerUP BasicSuperBlockMerge(IHTRLayer &layer);405406} // namespace lldb_private407408#endif // LLDB_TARGET_TRACE_HTR_H409410411