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
|