xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/Statistics.cpp (revision c9ccf3a32da427475985b85d7df023ccfb138c27)
1 //===-- Statistics.cpp ----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Target/Statistics.h"
10 
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Symbol/SymbolFile.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/Target.h"
16 #include "lldb/Target/UnixSignals.h"
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 using namespace llvm;
21 
22 static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
23                               const std::string &str) {
24   if (str.empty())
25     return;
26   if (LLVM_LIKELY(llvm::json::isUTF8(str)))
27     obj.try_emplace(key, str);
28   else
29     obj.try_emplace(key, llvm::json::fixUTF8(str));
30 }
31 
32 json::Value StatsSuccessFail::ToJSON() const {
33   return json::Object{{"successes", successes}, {"failures", failures}};
34 }
35 
36 static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) {
37   StatsDuration::Duration elapsed =
38       end.time_since_epoch() - start.time_since_epoch();
39   return elapsed.count();
40 }
41 
42 void TargetStats::CollectStats(Target &target) {
43   m_module_identifiers.clear();
44   for (ModuleSP module_sp : target.GetImages().Modules())
45     m_module_identifiers.emplace_back((intptr_t)module_sp.get());
46 }
47 
48 json::Value ModuleStats::ToJSON() const {
49   json::Object module;
50   EmplaceSafeString(module, "path", path);
51   EmplaceSafeString(module, "uuid", uuid);
52   EmplaceSafeString(module, "triple", triple);
53   module.try_emplace("identifier", identifier);
54   module.try_emplace("symbolTableParseTime", symtab_parse_time);
55   module.try_emplace("symbolTableIndexTime", symtab_index_time);
56   module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache);
57   module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache);
58   module.try_emplace("debugInfoParseTime", debug_parse_time);
59   module.try_emplace("debugInfoIndexTime", debug_index_time);
60   module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size);
61   module.try_emplace("debugInfoIndexLoadedFromCache",
62                      debug_info_index_loaded_from_cache);
63   module.try_emplace("debugInfoIndexSavedToCache",
64                      debug_info_index_saved_to_cache);
65   return module;
66 }
67 
68 llvm::json::Value ConstStringStats::ToJSON() const {
69   json::Object obj;
70   obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal());
71   obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed());
72   obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused());
73   return obj;
74 }
75 
76 json::Value TargetStats::ToJSON(Target &target) {
77   CollectStats(target);
78 
79   json::Array json_module_uuid_array;
80   for (auto module_identifier : m_module_identifiers)
81     json_module_uuid_array.emplace_back(module_identifier);
82 
83   json::Object target_metrics_json{
84       {m_expr_eval.name, m_expr_eval.ToJSON()},
85       {m_frame_var.name, m_frame_var.ToJSON()},
86       {"moduleIdentifiers", std::move(json_module_uuid_array)}};
87 
88   if (m_launch_or_attach_time && m_first_private_stop_time) {
89     double elapsed_time =
90         elapsed(*m_launch_or_attach_time, *m_first_private_stop_time);
91     target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);
92   }
93   if (m_launch_or_attach_time && m_first_public_stop_time) {
94     double elapsed_time =
95         elapsed(*m_launch_or_attach_time, *m_first_public_stop_time);
96     target_metrics_json.try_emplace("firstStopTime", elapsed_time);
97   }
98   target_metrics_json.try_emplace("targetCreateTime",
99                                   m_create_time.get().count());
100 
101   json::Array breakpoints_array;
102   double totalBreakpointResolveTime = 0.0;
103   // Rport both the normal breakpoint list and the internal breakpoint list.
104   for (int i = 0; i < 2; ++i) {
105     BreakpointList &breakpoints = target.GetBreakpointList(i == 1);
106     std::unique_lock<std::recursive_mutex> lock;
107     breakpoints.GetListMutex(lock);
108     size_t num_breakpoints = breakpoints.GetSize();
109     for (size_t i = 0; i < num_breakpoints; i++) {
110       Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
111       breakpoints_array.push_back(bp->GetStatistics());
112       totalBreakpointResolveTime += bp->GetResolveTime().count();
113     }
114   }
115 
116   ProcessSP process_sp = target.GetProcessSP();
117   if (process_sp) {
118     UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();
119     if (unix_signals_sp)
120       target_metrics_json.try_emplace("signals",
121                                       unix_signals_sp->GetHitCountStatistics());
122     uint32_t stop_id = process_sp->GetStopID();
123     target_metrics_json.try_emplace("stopCount", stop_id);
124   }
125   target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array));
126   target_metrics_json.try_emplace("totalBreakpointResolveTime",
127                                   totalBreakpointResolveTime);
128 
129   return target_metrics_json;
130 }
131 
132 void TargetStats::SetLaunchOrAttachTime() {
133   m_launch_or_attach_time = StatsClock::now();
134   m_first_private_stop_time = llvm::None;
135 }
136 
137 void TargetStats::SetFirstPrivateStopTime() {
138   // Launching and attaching has many paths depending on if synchronous mode
139   // was used or if we are stopping at the entry point or not. Only set the
140   // first stop time if it hasn't already been set.
141   if (!m_first_private_stop_time)
142     m_first_private_stop_time = StatsClock::now();
143 }
144 
145 void TargetStats::SetFirstPublicStopTime() {
146   // Launching and attaching has many paths depending on if synchronous mode
147   // was used or if we are stopping at the entry point or not. Only set the
148   // first stop time if it hasn't already been set.
149   if (!m_first_public_stop_time)
150     m_first_public_stop_time = StatsClock::now();
151 }
152 
153 bool DebuggerStats::g_collecting_stats = false;
154 
155 llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger,
156                                                   Target *target) {
157   json::Array json_targets;
158   json::Array json_modules;
159   double symtab_parse_time = 0.0;
160   double symtab_index_time = 0.0;
161   double debug_parse_time = 0.0;
162   double debug_index_time = 0.0;
163   uint32_t symtabs_loaded = 0;
164   uint32_t symtabs_saved = 0;
165   uint32_t debug_index_loaded = 0;
166   uint32_t debug_index_saved = 0;
167   uint64_t debug_info_size = 0;
168   if (target) {
169     json_targets.emplace_back(target->ReportStatistics());
170   } else {
171     for (const auto &target : debugger.GetTargetList().Targets())
172       json_targets.emplace_back(target->ReportStatistics());
173   }
174   std::vector<ModuleStats> modules;
175   std::lock_guard<std::recursive_mutex> guard(
176       Module::GetAllocationModuleCollectionMutex());
177   const size_t num_modules = Module::GetNumberAllocatedModules();
178   for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
179     Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
180     ModuleStats module_stat;
181     module_stat.identifier = (intptr_t)module;
182     module_stat.path = module->GetFileSpec().GetPath();
183     if (ConstString object_name = module->GetObjectName()) {
184       module_stat.path.append(1, '(');
185       module_stat.path.append(object_name.GetStringRef().str());
186       module_stat.path.append(1, ')');
187     }
188     module_stat.uuid = module->GetUUID().GetAsString();
189     module_stat.triple = module->GetArchitecture().GetTriple().str();
190     module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
191     module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
192     Symtab *symtab = module->GetSymtab();
193     if (symtab) {
194       module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();
195       if (module_stat.symtab_loaded_from_cache)
196         ++symtabs_loaded;
197       module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache();
198       if (module_stat.symtab_saved_to_cache)
199         ++symtabs_saved;
200     }
201     SymbolFile *sym_file = module->GetSymbolFile();
202     if (sym_file) {
203       module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
204       module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
205       module_stat.debug_info_size = sym_file->GetDebugInfoSize();
206       module_stat.debug_info_index_loaded_from_cache =
207           sym_file->GetDebugInfoIndexWasLoadedFromCache();
208       if (module_stat.debug_info_index_loaded_from_cache)
209         ++debug_index_loaded;
210       module_stat.debug_info_index_saved_to_cache =
211           sym_file->GetDebugInfoIndexWasSavedToCache();
212       if (module_stat.debug_info_index_saved_to_cache)
213         ++debug_index_saved;
214     }
215     symtab_parse_time += module_stat.symtab_parse_time;
216     symtab_index_time += module_stat.symtab_index_time;
217     debug_parse_time += module_stat.debug_parse_time;
218     debug_index_time += module_stat.debug_index_time;
219     debug_info_size += module_stat.debug_info_size;
220     json_modules.emplace_back(module_stat.ToJSON());
221   }
222 
223   ConstStringStats const_string_stats;
224   json::Object json_memory{
225       {"strings", const_string_stats.ToJSON()},
226   };
227 
228   json::Object global_stats{
229       {"targets", std::move(json_targets)},
230       {"modules", std::move(json_modules)},
231       {"memory", std::move(json_memory)},
232       {"totalSymbolTableParseTime", symtab_parse_time},
233       {"totalSymbolTableIndexTime", symtab_index_time},
234       {"totalSymbolTablesLoadedFromCache", symtabs_loaded},
235       {"totalSymbolTablesSavedToCache", symtabs_saved},
236       {"totalDebugInfoParseTime", debug_parse_time},
237       {"totalDebugInfoIndexTime", debug_index_time},
238       {"totalDebugInfoIndexLoadedFromCache", debug_index_loaded},
239       {"totalDebugInfoIndexSavedToCache", debug_index_saved},
240       {"totalDebugInfoByteSize", debug_info_size},
241   };
242   return std::move(global_stats);
243 }
244