1d52ba488SWalter Erquinigo //===-- TraceHTR.cpp ------------------------------------------------------===//
2d52ba488SWalter Erquinigo //
3d52ba488SWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d52ba488SWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
5d52ba488SWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d52ba488SWalter Erquinigo //
7d52ba488SWalter Erquinigo //===----------------------------------------------------------------------===//
8d52ba488SWalter Erquinigo
9d52ba488SWalter Erquinigo #include "TraceHTR.h"
10d52ba488SWalter Erquinigo
11d52ba488SWalter Erquinigo #include "lldb/Symbol/Function.h"
12d52ba488SWalter Erquinigo #include "lldb/Target/Process.h"
13d52ba488SWalter Erquinigo #include "lldb/Target/Target.h"
14d52ba488SWalter Erquinigo #include "llvm/Support/JSON.h"
15f190ce62SKazu Hirata #include <optional>
16d52ba488SWalter Erquinigo #include <sstream>
17d52ba488SWalter Erquinigo #include <string>
18d52ba488SWalter Erquinigo
19d52ba488SWalter Erquinigo using namespace lldb_private;
20d52ba488SWalter Erquinigo using namespace lldb;
21d52ba488SWalter Erquinigo
GetNumInstructions() const22d52ba488SWalter Erquinigo size_t HTRBlockMetadata::GetNumInstructions() const {
23d52ba488SWalter Erquinigo return m_num_instructions;
24d52ba488SWalter Erquinigo }
25d52ba488SWalter Erquinigo
262fe83274SKazu Hirata std::optional<llvm::StringRef>
GetMostFrequentlyCalledFunction() const27d52ba488SWalter Erquinigo HTRBlockMetadata::GetMostFrequentlyCalledFunction() const {
28d52ba488SWalter Erquinigo size_t max_ncalls = 0;
292fe83274SKazu Hirata std::optional<llvm::StringRef> max_name;
30d52ba488SWalter Erquinigo for (const auto &it : m_func_calls) {
31d52ba488SWalter Erquinigo ConstString name = it.first;
32d52ba488SWalter Erquinigo size_t ncalls = it.second;
33d52ba488SWalter Erquinigo if (ncalls > max_ncalls) {
34d52ba488SWalter Erquinigo max_ncalls = ncalls;
35d52ba488SWalter Erquinigo max_name = name.GetStringRef();
36d52ba488SWalter Erquinigo }
37d52ba488SWalter Erquinigo }
38d52ba488SWalter Erquinigo return max_name;
39d52ba488SWalter Erquinigo }
40d52ba488SWalter Erquinigo
41d52ba488SWalter Erquinigo llvm::DenseMap<ConstString, size_t> const &
GetFunctionCalls() const42d52ba488SWalter Erquinigo HTRBlockMetadata::GetFunctionCalls() const {
43d52ba488SWalter Erquinigo return m_func_calls;
44d52ba488SWalter Erquinigo }
45d52ba488SWalter Erquinigo
GetFirstInstructionLoadAddress() const46d52ba488SWalter Erquinigo lldb::addr_t HTRBlockMetadata::GetFirstInstructionLoadAddress() const {
47d52ba488SWalter Erquinigo return m_first_instruction_load_address;
48d52ba488SWalter Erquinigo }
49d52ba488SWalter Erquinigo
GetOffset() const50d52ba488SWalter Erquinigo size_t HTRBlock::GetOffset() const { return m_offset; }
51d52ba488SWalter Erquinigo
GetSize() const52d52ba488SWalter Erquinigo size_t HTRBlock::GetSize() const { return m_size; }
53d52ba488SWalter Erquinigo
GetMetadata() const54d52ba488SWalter Erquinigo HTRBlockMetadata const &HTRBlock::GetMetadata() const { return m_metadata; }
55d52ba488SWalter Erquinigo
GetBlockLayers() const56d52ba488SWalter Erquinigo llvm::ArrayRef<HTRBlockLayerUP> TraceHTR::GetBlockLayers() const {
57d52ba488SWalter Erquinigo return m_block_layer_ups;
58d52ba488SWalter Erquinigo }
59d52ba488SWalter Erquinigo
GetInstructionLayer() const60d52ba488SWalter Erquinigo HTRInstructionLayer const &TraceHTR::GetInstructionLayer() const {
61d52ba488SWalter Erquinigo return *m_instruction_layer_up;
62d52ba488SWalter Erquinigo }
63d52ba488SWalter Erquinigo
AddNewBlockLayer(HTRBlockLayerUP && block_layer)64d52ba488SWalter Erquinigo void TraceHTR::AddNewBlockLayer(HTRBlockLayerUP &&block_layer) {
65d52ba488SWalter Erquinigo m_block_layer_ups.emplace_back(std::move(block_layer));
66d52ba488SWalter Erquinigo }
67d52ba488SWalter Erquinigo
GetLayerId() const68d52ba488SWalter Erquinigo size_t IHTRLayer::GetLayerId() const { return m_layer_id; }
69d52ba488SWalter Erquinigo
AppendNewBlock(size_t block_id,HTRBlock && block)70d52ba488SWalter Erquinigo void HTRBlockLayer::AppendNewBlock(size_t block_id, HTRBlock &&block) {
71d52ba488SWalter Erquinigo m_block_id_trace.emplace_back(block_id);
72*6953dc95SChris Cotter m_block_defs.emplace(block_id, std::move(block));
73d52ba488SWalter Erquinigo }
74d52ba488SWalter Erquinigo
AppendRepeatedBlock(size_t block_id)75d52ba488SWalter Erquinigo void HTRBlockLayer::AppendRepeatedBlock(size_t block_id) {
76d52ba488SWalter Erquinigo m_block_id_trace.emplace_back(block_id);
77d52ba488SWalter Erquinigo }
78d52ba488SWalter Erquinigo
GetInstructionTrace() const79d52ba488SWalter Erquinigo llvm::ArrayRef<lldb::addr_t> HTRInstructionLayer::GetInstructionTrace() const {
80d52ba488SWalter Erquinigo return m_instruction_trace;
81d52ba488SWalter Erquinigo }
82d52ba488SWalter Erquinigo
AddCallInstructionMetadata(lldb::addr_t load_addr,std::optional<ConstString> func_name)83d52ba488SWalter Erquinigo void HTRInstructionLayer::AddCallInstructionMetadata(
842fe83274SKazu Hirata lldb::addr_t load_addr, std::optional<ConstString> func_name) {
85d52ba488SWalter Erquinigo m_call_isns.emplace(load_addr, func_name);
86d52ba488SWalter Erquinigo }
87d52ba488SWalter Erquinigo
AppendInstruction(lldb::addr_t load_addr)88d52ba488SWalter Erquinigo void HTRInstructionLayer::AppendInstruction(lldb::addr_t load_addr) {
89d52ba488SWalter Erquinigo m_instruction_trace.emplace_back(load_addr);
90d52ba488SWalter Erquinigo }
91d52ba488SWalter Erquinigo
GetBlockById(size_t block_id) const92d52ba488SWalter Erquinigo HTRBlock const *HTRBlockLayer::GetBlockById(size_t block_id) const {
93d52ba488SWalter Erquinigo auto block_it = m_block_defs.find(block_id);
94d52ba488SWalter Erquinigo if (block_it == m_block_defs.end())
95d52ba488SWalter Erquinigo return nullptr;
96d52ba488SWalter Erquinigo else
97d52ba488SWalter Erquinigo return &block_it->second;
98d52ba488SWalter Erquinigo }
99d52ba488SWalter Erquinigo
GetBlockIdTrace() const100d52ba488SWalter Erquinigo llvm::ArrayRef<size_t> HTRBlockLayer::GetBlockIdTrace() const {
101d52ba488SWalter Erquinigo return m_block_id_trace;
102d52ba488SWalter Erquinigo }
103d52ba488SWalter Erquinigo
GetNumUnits() const104d52ba488SWalter Erquinigo size_t HTRBlockLayer::GetNumUnits() const { return m_block_id_trace.size(); }
105d52ba488SWalter Erquinigo
GetMetadataByIndex(size_t index) const106d52ba488SWalter Erquinigo HTRBlockMetadata HTRInstructionLayer::GetMetadataByIndex(size_t index) const {
107d52ba488SWalter Erquinigo lldb::addr_t instruction_load_address = m_instruction_trace[index];
108d52ba488SWalter Erquinigo llvm::DenseMap<ConstString, size_t> func_calls;
109d52ba488SWalter Erquinigo
110d52ba488SWalter Erquinigo auto func_name_it = m_call_isns.find(instruction_load_address);
111d52ba488SWalter Erquinigo if (func_name_it != m_call_isns.end()) {
1122fe83274SKazu Hirata if (std::optional<ConstString> func_name = func_name_it->second) {
113d52ba488SWalter Erquinigo func_calls[*func_name] = 1;
114d52ba488SWalter Erquinigo }
115d52ba488SWalter Erquinigo }
116ef28c783SWalter Erquinigo return {instruction_load_address, 1, std::move(func_calls)};
117d52ba488SWalter Erquinigo }
118d52ba488SWalter Erquinigo
GetNumUnits() const119d52ba488SWalter Erquinigo size_t HTRInstructionLayer::GetNumUnits() const {
120d52ba488SWalter Erquinigo return m_instruction_trace.size();
121d52ba488SWalter Erquinigo }
122d52ba488SWalter Erquinigo
GetMetadataByIndex(size_t index) const123d52ba488SWalter Erquinigo HTRBlockMetadata HTRBlockLayer::GetMetadataByIndex(size_t index) const {
124d52ba488SWalter Erquinigo size_t block_id = m_block_id_trace[index];
125d52ba488SWalter Erquinigo HTRBlock block = m_block_defs.find(block_id)->second;
126d52ba488SWalter Erquinigo return block.GetMetadata();
127d52ba488SWalter Erquinigo }
128d52ba488SWalter Erquinigo
TraceHTR(Thread & thread,TraceCursor & cursor)129d52ba488SWalter Erquinigo TraceHTR::TraceHTR(Thread &thread, TraceCursor &cursor)
130d52ba488SWalter Erquinigo : m_instruction_layer_up(std::make_unique<HTRInstructionLayer>(0)) {
131d52ba488SWalter Erquinigo
132d52ba488SWalter Erquinigo // Move cursor to the first instruction in the trace
133d52ba488SWalter Erquinigo cursor.SetForwards(true);
134f9b4ea0cSJakob Johnson cursor.Seek(0, lldb::eTraceCursorSeekTypeBeginning);
135d52ba488SWalter Erquinigo
136a3ec54c6SKevin Cadieux // TODO: fix after persona0220's patch on a new way to access instruction
137a3ec54c6SKevin Cadieux // kinds
138a3ec54c6SKevin Cadieux /*
139d52ba488SWalter Erquinigo Target &target = thread.GetProcess()->GetTarget();
140d52ba488SWalter Erquinigo auto function_name_from_load_address =
1412fe83274SKazu Hirata [&](lldb::addr_t load_address) -> std::optional<ConstString> {
142d52ba488SWalter Erquinigo lldb_private::Address pc_addr;
143d52ba488SWalter Erquinigo SymbolContext sc;
144d52ba488SWalter Erquinigo if (target.ResolveLoadAddress(load_address, pc_addr) &&
145d52ba488SWalter Erquinigo pc_addr.CalculateSymbolContext(&sc))
146d52ba488SWalter Erquinigo return sc.GetFunctionName()
1472fe83274SKazu Hirata ? std::optional<ConstString>(sc.GetFunctionName())
148529ca5adSKazu Hirata : std::nullopt;
149d52ba488SWalter Erquinigo else
150529ca5adSKazu Hirata return std::nullopt;
151d52ba488SWalter Erquinigo };
152d52ba488SWalter Erquinigo
153a3ec54c6SKevin Cadieux while (cursor.HasValue()) { if (cursor.IsError()) {
154d52ba488SWalter Erquinigo // Append a load address of 0 for all instructions that an error occured
155d52ba488SWalter Erquinigo // while decoding.
156d52ba488SWalter Erquinigo // TODO: Make distinction between errors by storing the error messages.
157d52ba488SWalter Erquinigo // Currently, all errors are treated the same.
158d52ba488SWalter Erquinigo m_instruction_layer_up->AppendInstruction(0);
159f91d8281SWalter Erquinigo cursor.Next();
160a7d6c3efSWalter Erquinigo } else if (cursor.IsEvent()) {
161a7d6c3efSWalter Erquinigo cursor.Next();
162d52ba488SWalter Erquinigo } else {
163d52ba488SWalter Erquinigo lldb::addr_t current_instruction_load_address = cursor.GetLoadAddress();
164ad7bcda9SWalter Erquinigo lldb::InstructionControlFlowKind current_instruction_type =
165ad7bcda9SWalter Erquinigo cursor.GetInstructionControlFlowKind();
166d52ba488SWalter Erquinigo
167d52ba488SWalter Erquinigo m_instruction_layer_up->AppendInstruction(
168d52ba488SWalter Erquinigo current_instruction_load_address);
169f91d8281SWalter Erquinigo cursor.Next();
170a7d6c3efSWalter Erquinigo bool more_data_in_trace = cursor.HasValue();
171d52ba488SWalter Erquinigo if (current_instruction_type &
172ad7bcda9SWalter Erquinigo lldb::eInstructionControlFlowKindCall) {
173d52ba488SWalter Erquinigo if (more_data_in_trace && !cursor.IsError()) {
174d52ba488SWalter Erquinigo m_instruction_layer_up->AddCallInstructionMetadata(
175d52ba488SWalter Erquinigo current_instruction_load_address,
176d52ba488SWalter Erquinigo function_name_from_load_address(cursor.GetLoadAddress()));
177d52ba488SWalter Erquinigo } else {
178d52ba488SWalter Erquinigo // Next instruction is not known - pass None to indicate the name
179d52ba488SWalter Erquinigo // of the function being called is not known
180d52ba488SWalter Erquinigo m_instruction_layer_up->AddCallInstructionMetadata(
181529ca5adSKazu Hirata current_instruction_load_address, std::nullopt);
182d52ba488SWalter Erquinigo }
183d52ba488SWalter Erquinigo }
184d52ba488SWalter Erquinigo }
185d52ba488SWalter Erquinigo }
186a7d6c3efSWalter Erquinigo */
187d52ba488SWalter Erquinigo }
188d52ba488SWalter Erquinigo
MergeMetadata(HTRBlockMetadata & merged_metadata,HTRBlockMetadata const & metadata_to_merge)189d52ba488SWalter Erquinigo void HTRBlockMetadata::MergeMetadata(
190d52ba488SWalter Erquinigo HTRBlockMetadata &merged_metadata,
191d52ba488SWalter Erquinigo HTRBlockMetadata const &metadata_to_merge) {
192d52ba488SWalter Erquinigo merged_metadata.m_num_instructions += metadata_to_merge.m_num_instructions;
193d52ba488SWalter Erquinigo for (const auto &it : metadata_to_merge.m_func_calls) {
194d52ba488SWalter Erquinigo ConstString name = it.first;
195d52ba488SWalter Erquinigo size_t num_calls = it.second;
196d52ba488SWalter Erquinigo merged_metadata.m_func_calls[name] += num_calls;
197d52ba488SWalter Erquinigo }
198d52ba488SWalter Erquinigo }
199d52ba488SWalter Erquinigo
MergeUnits(size_t start_unit_index,size_t num_units)200d52ba488SWalter Erquinigo HTRBlock IHTRLayer::MergeUnits(size_t start_unit_index, size_t num_units) {
201d52ba488SWalter Erquinigo // TODO: make this function take `end_unit_index` as a parameter instead of
202d52ba488SWalter Erquinigo // unit and merge the range [start_unit_indx, end_unit_index] inclusive.
203d52ba488SWalter Erquinigo HTRBlockMetadata merged_metadata = GetMetadataByIndex(start_unit_index);
204d52ba488SWalter Erquinigo for (size_t i = start_unit_index + 1; i < start_unit_index + num_units; i++) {
205d52ba488SWalter Erquinigo // merge the new metadata into merged_metadata
206d52ba488SWalter Erquinigo HTRBlockMetadata::MergeMetadata(merged_metadata, GetMetadataByIndex(i));
207d52ba488SWalter Erquinigo }
208d52ba488SWalter Erquinigo return {start_unit_index, num_units, merged_metadata};
209d52ba488SWalter Erquinigo }
210d52ba488SWalter Erquinigo
ExecutePasses()211d52ba488SWalter Erquinigo void TraceHTR::ExecutePasses() {
212d52ba488SWalter Erquinigo auto are_passes_done = [](IHTRLayer &l1, IHTRLayer &l2) {
213d52ba488SWalter Erquinigo return l1.GetNumUnits() == l2.GetNumUnits();
214d52ba488SWalter Erquinigo };
215d52ba488SWalter Erquinigo HTRBlockLayerUP current_block_layer_up =
216d52ba488SWalter Erquinigo BasicSuperBlockMerge(*m_instruction_layer_up);
217d52ba488SWalter Erquinigo HTRBlockLayer ¤t_block_layer = *current_block_layer_up;
218d52ba488SWalter Erquinigo if (are_passes_done(*m_instruction_layer_up, *current_block_layer_up))
219d52ba488SWalter Erquinigo return;
220d52ba488SWalter Erquinigo
221d52ba488SWalter Erquinigo AddNewBlockLayer(std::move(current_block_layer_up));
222d52ba488SWalter Erquinigo while (true) {
223d52ba488SWalter Erquinigo HTRBlockLayerUP new_block_layer_up =
224d52ba488SWalter Erquinigo BasicSuperBlockMerge(current_block_layer);
225d52ba488SWalter Erquinigo if (are_passes_done(current_block_layer, *new_block_layer_up))
226d52ba488SWalter Erquinigo return;
227d52ba488SWalter Erquinigo
228d52ba488SWalter Erquinigo current_block_layer = *new_block_layer_up;
229d52ba488SWalter Erquinigo AddNewBlockLayer(std::move(new_block_layer_up));
230d52ba488SWalter Erquinigo }
231d52ba488SWalter Erquinigo }
232d52ba488SWalter Erquinigo
Export(std::string outfile)233d52ba488SWalter Erquinigo llvm::Error TraceHTR::Export(std::string outfile) {
234d52ba488SWalter Erquinigo std::error_code ec;
235d52ba488SWalter Erquinigo llvm::raw_fd_ostream os(outfile, ec, llvm::sys::fs::OF_Text);
236d52ba488SWalter Erquinigo if (ec) {
237d52ba488SWalter Erquinigo return llvm::make_error<llvm::StringError>(
238d52ba488SWalter Erquinigo "unable to open destination file: " + outfile, os.error());
239d52ba488SWalter Erquinigo } else {
240d52ba488SWalter Erquinigo os << toJSON(*this);
241d52ba488SWalter Erquinigo os.close();
242d52ba488SWalter Erquinigo if (os.has_error()) {
243d52ba488SWalter Erquinigo return llvm::make_error<llvm::StringError>(
244d52ba488SWalter Erquinigo "unable to write to destination file: " + outfile, os.error());
245d52ba488SWalter Erquinigo }
246d52ba488SWalter Erquinigo }
247d52ba488SWalter Erquinigo return llvm::Error::success();
248d52ba488SWalter Erquinigo }
249d52ba488SWalter Erquinigo
BasicSuperBlockMerge(IHTRLayer & layer)250d52ba488SWalter Erquinigo HTRBlockLayerUP lldb_private::BasicSuperBlockMerge(IHTRLayer &layer) {
251d52ba488SWalter Erquinigo std::unique_ptr<HTRBlockLayer> new_block_layer =
252d52ba488SWalter Erquinigo std::make_unique<HTRBlockLayer>(layer.GetLayerId() + 1);
253d52ba488SWalter Erquinigo
254d52ba488SWalter Erquinigo if (layer.GetNumUnits()) {
255d52ba488SWalter Erquinigo // Future Improvement: split this into two functions - one for finding heads
256d52ba488SWalter Erquinigo // and tails, one for merging/creating the next layer A 'head' is defined to
257d52ba488SWalter Erquinigo // be a block whose occurrences in the trace do not have a unique preceding
258d52ba488SWalter Erquinigo // block.
259d52ba488SWalter Erquinigo std::unordered_set<size_t> heads;
260d52ba488SWalter Erquinigo
261d52ba488SWalter Erquinigo // The load address of the first instruction of a block is the unique ID for
262d52ba488SWalter Erquinigo // that block (i.e. blocks with the same first instruction load address are
263d52ba488SWalter Erquinigo // the same block)
264d52ba488SWalter Erquinigo
265d52ba488SWalter Erquinigo // Future Improvement: no need to store all its preceding block ids, all we
266d52ba488SWalter Erquinigo // care about is that there is more than one preceding block id, so an enum
267d52ba488SWalter Erquinigo // could be used
268d52ba488SWalter Erquinigo std::unordered_map<lldb::addr_t, std::unordered_set<lldb::addr_t>> head_map;
269d52ba488SWalter Erquinigo lldb::addr_t prev_id =
270d52ba488SWalter Erquinigo layer.GetMetadataByIndex(0).GetFirstInstructionLoadAddress();
271d52ba488SWalter Erquinigo size_t num_units = layer.GetNumUnits();
272d52ba488SWalter Erquinigo // This excludes the first unit since it has no previous unit
273d52ba488SWalter Erquinigo for (size_t i = 1; i < num_units; i++) {
274d52ba488SWalter Erquinigo lldb::addr_t current_id =
275d52ba488SWalter Erquinigo layer.GetMetadataByIndex(i).GetFirstInstructionLoadAddress();
276d52ba488SWalter Erquinigo head_map[current_id].insert(prev_id);
277d52ba488SWalter Erquinigo prev_id = current_id;
278d52ba488SWalter Erquinigo }
279d52ba488SWalter Erquinigo for (const auto &it : head_map) {
280d52ba488SWalter Erquinigo // ID of 0 represents an error - errors can't be heads or tails
281d52ba488SWalter Erquinigo lldb::addr_t id = it.first;
282d52ba488SWalter Erquinigo const std::unordered_set<lldb::addr_t> predecessor_set = it.second;
283d52ba488SWalter Erquinigo if (id && predecessor_set.size() > 1)
284d52ba488SWalter Erquinigo heads.insert(id);
285d52ba488SWalter Erquinigo }
286d52ba488SWalter Erquinigo
287d52ba488SWalter Erquinigo // Future Improvement: identify heads and tails in the same loop
288d52ba488SWalter Erquinigo // A 'tail' is defined to be a block whose occurrences in the trace do
289d52ba488SWalter Erquinigo // not have a unique succeeding block.
290d52ba488SWalter Erquinigo std::unordered_set<lldb::addr_t> tails;
291d52ba488SWalter Erquinigo std::unordered_map<lldb::addr_t, std::unordered_set<lldb::addr_t>> tail_map;
292d52ba488SWalter Erquinigo
293d52ba488SWalter Erquinigo // This excludes the last unit since it has no next unit
294d52ba488SWalter Erquinigo for (size_t i = 0; i < num_units - 1; i++) {
295d52ba488SWalter Erquinigo lldb::addr_t current_id =
296d52ba488SWalter Erquinigo layer.GetMetadataByIndex(i).GetFirstInstructionLoadAddress();
297d52ba488SWalter Erquinigo lldb::addr_t next_id =
298d52ba488SWalter Erquinigo layer.GetMetadataByIndex(i + 1).GetFirstInstructionLoadAddress();
299d52ba488SWalter Erquinigo tail_map[current_id].insert(next_id);
300d52ba488SWalter Erquinigo }
301d52ba488SWalter Erquinigo
302d52ba488SWalter Erquinigo // Mark last block as tail so the algorithm stops gracefully
303d52ba488SWalter Erquinigo lldb::addr_t last_id = layer.GetMetadataByIndex(num_units - 1)
304d52ba488SWalter Erquinigo .GetFirstInstructionLoadAddress();
305d52ba488SWalter Erquinigo tails.insert(last_id);
306d52ba488SWalter Erquinigo for (const auto &it : tail_map) {
307d52ba488SWalter Erquinigo lldb::addr_t id = it.first;
308d52ba488SWalter Erquinigo const std::unordered_set<lldb::addr_t> successor_set = it.second;
309d52ba488SWalter Erquinigo // ID of 0 represents an error - errors can't be heads or tails
310d52ba488SWalter Erquinigo if (id && successor_set.size() > 1)
311d52ba488SWalter Erquinigo tails.insert(id);
312d52ba488SWalter Erquinigo }
313d52ba488SWalter Erquinigo
314d52ba488SWalter Erquinigo // Need to keep track of size of string since things we push are variable
315d52ba488SWalter Erquinigo // length
316d52ba488SWalter Erquinigo size_t superblock_size = 0;
317d52ba488SWalter Erquinigo // Each super block always has the same first unit (we call this the
318d52ba488SWalter Erquinigo // super block head) This gurantee allows us to use the super block head as
319d52ba488SWalter Erquinigo // the unique key mapping to the super block it begins
3202fe83274SKazu Hirata std::optional<size_t> superblock_head;
321d52ba488SWalter Erquinigo auto construct_next_layer = [&](size_t merge_start, size_t n) -> void {
322d52ba488SWalter Erquinigo if (!superblock_head)
323d52ba488SWalter Erquinigo return;
324d52ba488SWalter Erquinigo if (new_block_layer->GetBlockById(*superblock_head)) {
325d52ba488SWalter Erquinigo new_block_layer->AppendRepeatedBlock(*superblock_head);
326d52ba488SWalter Erquinigo } else {
327d52ba488SWalter Erquinigo HTRBlock new_block = layer.MergeUnits(merge_start, n);
328d52ba488SWalter Erquinigo new_block_layer->AppendNewBlock(*superblock_head, std::move(new_block));
329d52ba488SWalter Erquinigo }
330d52ba488SWalter Erquinigo };
331d52ba488SWalter Erquinigo
332d52ba488SWalter Erquinigo for (size_t i = 0; i < num_units; i++) {
333d52ba488SWalter Erquinigo lldb::addr_t unit_id =
334d52ba488SWalter Erquinigo layer.GetMetadataByIndex(i).GetFirstInstructionLoadAddress();
335d52ba488SWalter Erquinigo auto isHead = heads.count(unit_id) > 0;
336d52ba488SWalter Erquinigo auto isTail = tails.count(unit_id) > 0;
337d52ba488SWalter Erquinigo
338d52ba488SWalter Erquinigo if (isHead && isTail) {
339d52ba488SWalter Erquinigo // Head logic
340d52ba488SWalter Erquinigo if (superblock_size) { // this handles (tail, head) adjacency -
341d52ba488SWalter Erquinigo // otherwise an empty
342d52ba488SWalter Erquinigo // block is created
343d52ba488SWalter Erquinigo // End previous super block
344d52ba488SWalter Erquinigo construct_next_layer(i - superblock_size, superblock_size);
345d52ba488SWalter Erquinigo }
346d52ba488SWalter Erquinigo // Current id is first in next super block since it's a head
347d52ba488SWalter Erquinigo superblock_head = unit_id;
348d52ba488SWalter Erquinigo superblock_size = 1;
349d52ba488SWalter Erquinigo
350d52ba488SWalter Erquinigo // Tail logic
351d52ba488SWalter Erquinigo construct_next_layer(i - superblock_size + 1, superblock_size);
352d52ba488SWalter Erquinigo // Reset the block_head since the prev super block has come to and end
353343523d0SKazu Hirata superblock_head = std::nullopt;
354d52ba488SWalter Erquinigo superblock_size = 0;
355d52ba488SWalter Erquinigo } else if (isHead) {
356d52ba488SWalter Erquinigo if (superblock_size) { // this handles (tail, head) adjacency -
357d52ba488SWalter Erquinigo // otherwise an empty
358d52ba488SWalter Erquinigo // block is created
359d52ba488SWalter Erquinigo // End previous super block
360d52ba488SWalter Erquinigo construct_next_layer(i - superblock_size, superblock_size);
361d52ba488SWalter Erquinigo }
362d52ba488SWalter Erquinigo // Current id is first in next super block since it's a head
363d52ba488SWalter Erquinigo superblock_head = unit_id;
364d52ba488SWalter Erquinigo superblock_size = 1;
365d52ba488SWalter Erquinigo } else if (isTail) {
366d52ba488SWalter Erquinigo if (!superblock_head)
367d52ba488SWalter Erquinigo superblock_head = unit_id;
368d52ba488SWalter Erquinigo superblock_size++;
369d52ba488SWalter Erquinigo
370d52ba488SWalter Erquinigo // End previous super block
371d52ba488SWalter Erquinigo construct_next_layer(i - superblock_size + 1, superblock_size);
372d52ba488SWalter Erquinigo // Reset the block_head since the prev super block has come to and end
373343523d0SKazu Hirata superblock_head = std::nullopt;
374d52ba488SWalter Erquinigo superblock_size = 0;
375d52ba488SWalter Erquinigo } else {
376d52ba488SWalter Erquinigo if (!superblock_head)
377d52ba488SWalter Erquinigo superblock_head = unit_id;
378d52ba488SWalter Erquinigo superblock_size++;
379d52ba488SWalter Erquinigo }
380d52ba488SWalter Erquinigo }
381d52ba488SWalter Erquinigo }
382d52ba488SWalter Erquinigo return new_block_layer;
383d52ba488SWalter Erquinigo }
384d52ba488SWalter Erquinigo
toJSON(const TraceHTR & htr)385d52ba488SWalter Erquinigo llvm::json::Value lldb_private::toJSON(const TraceHTR &htr) {
386d52ba488SWalter Erquinigo std::vector<llvm::json::Value> layers_as_json;
387d52ba488SWalter Erquinigo for (size_t i = 0; i < htr.GetInstructionLayer().GetInstructionTrace().size();
388d52ba488SWalter Erquinigo i++) {
389d52ba488SWalter Erquinigo size_t layer_id = htr.GetInstructionLayer().GetLayerId();
390d52ba488SWalter Erquinigo HTRBlockMetadata metadata = htr.GetInstructionLayer().GetMetadataByIndex(i);
391d52ba488SWalter Erquinigo lldb::addr_t load_address = metadata.GetFirstInstructionLoadAddress();
392d52ba488SWalter Erquinigo
393d52ba488SWalter Erquinigo std::string display_name;
394d52ba488SWalter Erquinigo
395d52ba488SWalter Erquinigo std::stringstream stream;
396d52ba488SWalter Erquinigo stream << "0x" << std::hex << load_address;
397d52ba488SWalter Erquinigo std::string load_address_hex_string(stream.str());
398d52ba488SWalter Erquinigo display_name.assign(load_address_hex_string);
399d52ba488SWalter Erquinigo
400ef28c783SWalter Erquinigo // name: load address of the first instruction of the block and the name
401ef28c783SWalter Erquinigo // of the most frequently called function from the block (if applicable)
402ef28c783SWalter Erquinigo
403ef28c783SWalter Erquinigo // ph: the event type - 'X' for Complete events (see link to documentation
404ef28c783SWalter Erquinigo // below)
405ef28c783SWalter Erquinigo
406ef28c783SWalter Erquinigo // Since trace timestamps aren't yet supported in HTR, the ts (timestamp) is
407ef28c783SWalter Erquinigo // based on the instruction's offset in the trace and the dur (duration) is
408ef28c783SWalter Erquinigo // 1 since this layer contains single instructions. Using the instruction
409ef28c783SWalter Erquinigo // offset and a duration of 1 oversimplifies the true timing information of
410ef28c783SWalter Erquinigo // the trace, nonetheless, these approximate timestamps/durations provide an
411ef28c783SWalter Erquinigo // clear visualization of the trace.
412ef28c783SWalter Erquinigo
413ef28c783SWalter Erquinigo // ts: offset from the beginning of the trace for the first instruction in
414ef28c783SWalter Erquinigo // the block
415ef28c783SWalter Erquinigo
416ef28c783SWalter Erquinigo // dur: 1 since this layer contains single instructions.
417ef28c783SWalter Erquinigo
418ef28c783SWalter Erquinigo // pid: the ID of the HTR layer the blocks belong to
419ef28c783SWalter Erquinigo
420ef28c783SWalter Erquinigo // See
421ef28c783SWalter Erquinigo // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.j75x71ritcoy
422ef28c783SWalter Erquinigo // for documentation on the Trace Event Format
423d52ba488SWalter Erquinigo layers_as_json.emplace_back(llvm::json::Object{
424d52ba488SWalter Erquinigo {"name", display_name},
425ef28c783SWalter Erquinigo {"ph", "X"},
426d52ba488SWalter Erquinigo {"ts", (int64_t)i},
427ef28c783SWalter Erquinigo {"dur", 1},
428d52ba488SWalter Erquinigo {"pid", (int64_t)layer_id},
429d52ba488SWalter Erquinigo });
430d52ba488SWalter Erquinigo }
431d52ba488SWalter Erquinigo
432d52ba488SWalter Erquinigo for (const auto &layer : htr.GetBlockLayers()) {
433d52ba488SWalter Erquinigo size_t start_ts = 0;
434d52ba488SWalter Erquinigo std::vector<size_t> block_id_trace = layer->GetBlockIdTrace();
435d52ba488SWalter Erquinigo for (size_t i = 0; i < block_id_trace.size(); i++) {
436d52ba488SWalter Erquinigo size_t id = block_id_trace[i];
437d52ba488SWalter Erquinigo // Guranteed that this ID is valid, so safe to dereference here.
438d52ba488SWalter Erquinigo HTRBlock block = *layer->GetBlockById(id);
439d52ba488SWalter Erquinigo llvm::json::Value block_json = toJSON(block);
440d52ba488SWalter Erquinigo size_t layer_id = layer->GetLayerId();
441d52ba488SWalter Erquinigo
442d52ba488SWalter Erquinigo HTRBlockMetadata metadata = block.GetMetadata();
443d52ba488SWalter Erquinigo
4442fe83274SKazu Hirata std::optional<llvm::StringRef> most_freq_func =
445d52ba488SWalter Erquinigo metadata.GetMostFrequentlyCalledFunction();
446d52ba488SWalter Erquinigo std::stringstream stream;
447d52ba488SWalter Erquinigo stream << "0x" << std::hex << metadata.GetFirstInstructionLoadAddress();
448d52ba488SWalter Erquinigo std::string offset_hex_string(stream.str());
449d52ba488SWalter Erquinigo std::string display_name =
450d52ba488SWalter Erquinigo most_freq_func ? offset_hex_string + ": " + most_freq_func->str()
451d52ba488SWalter Erquinigo : offset_hex_string;
452d52ba488SWalter Erquinigo
453ef28c783SWalter Erquinigo // Since trace timestamps aren't yet supported in HTR, the ts (timestamp)
454ef28c783SWalter Erquinigo // and dur (duration) are based on the block's offset in the trace and
455ef28c783SWalter Erquinigo // number of instructions in the block, respectively. Using the block
456ef28c783SWalter Erquinigo // offset and the number of instructions oversimplifies the true timing
457ef28c783SWalter Erquinigo // information of the trace, nonetheless, these approximate
458ef28c783SWalter Erquinigo // timestamps/durations provide an understandable visualization of the
459ef28c783SWalter Erquinigo // trace.
460ef28c783SWalter Erquinigo auto duration = metadata.GetNumInstructions();
461d52ba488SWalter Erquinigo layers_as_json.emplace_back(llvm::json::Object{
462d52ba488SWalter Erquinigo {"name", display_name},
463ef28c783SWalter Erquinigo {"ph", "X"},
464d52ba488SWalter Erquinigo {"ts", (int64_t)start_ts},
465ef28c783SWalter Erquinigo {"dur", (int64_t)duration},
466d52ba488SWalter Erquinigo {"pid", (int64_t)layer_id},
467d52ba488SWalter Erquinigo {"args", block_json},
468d52ba488SWalter Erquinigo });
469ef28c783SWalter Erquinigo start_ts += duration;
470d52ba488SWalter Erquinigo }
471d52ba488SWalter Erquinigo }
472d52ba488SWalter Erquinigo return layers_as_json;
473d52ba488SWalter Erquinigo }
474d52ba488SWalter Erquinigo
toJSON(const HTRBlock & block)475d52ba488SWalter Erquinigo llvm::json::Value lldb_private::toJSON(const HTRBlock &block) {
476d52ba488SWalter Erquinigo return llvm::json::Value(
477d52ba488SWalter Erquinigo llvm::json::Object{{"Metadata", block.GetMetadata()}});
478d52ba488SWalter Erquinigo }
479d52ba488SWalter Erquinigo
toJSON(const HTRBlockMetadata & metadata)480d52ba488SWalter Erquinigo llvm::json::Value lldb_private::toJSON(const HTRBlockMetadata &metadata) {
481d52ba488SWalter Erquinigo std::vector<llvm::json::Value> function_calls;
482d52ba488SWalter Erquinigo for (const auto &it : metadata.GetFunctionCalls()) {
483d52ba488SWalter Erquinigo ConstString name = it.first;
484d52ba488SWalter Erquinigo size_t n_calls = it.second;
485d52ba488SWalter Erquinigo function_calls.emplace_back(llvm::formatv("({0}: {1})", name, n_calls));
486d52ba488SWalter Erquinigo }
487d52ba488SWalter Erquinigo
488d52ba488SWalter Erquinigo return llvm::json::Value(llvm::json::Object{
489d52ba488SWalter Erquinigo {"Number of Instructions", (ssize_t)metadata.GetNumInstructions()},
490d52ba488SWalter Erquinigo {"Functions", function_calls}});
491d52ba488SWalter Erquinigo }
492