xref: /llvm-project/lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp (revision 6953dc95a9761768cad3c329ebac35927df126ab)
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 &current_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