1d7b33853SGreg Clayton //===-- Statistics.cpp ----------------------------------------------------===//
2d7b33853SGreg Clayton //
3d7b33853SGreg Clayton // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d7b33853SGreg Clayton // See https://llvm.org/LICENSE.txt for license information.
5d7b33853SGreg Clayton // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d7b33853SGreg Clayton //
7d7b33853SGreg Clayton //===----------------------------------------------------------------------===//
8d7b33853SGreg Clayton 
9d7b33853SGreg Clayton #include "lldb/Target/Statistics.h"
10d7b33853SGreg Clayton 
11d7b33853SGreg Clayton #include "lldb/Core/Debugger.h"
12d7b33853SGreg Clayton #include "lldb/Core/Module.h"
13d7b33853SGreg Clayton #include "lldb/Symbol/SymbolFile.h"
1413005564SGreg Clayton #include "lldb/Target/Process.h"
15d7b33853SGreg Clayton #include "lldb/Target/Target.h"
1613005564SGreg Clayton #include "lldb/Target/UnixSignals.h"
17d7b33853SGreg Clayton 
18d7b33853SGreg Clayton using namespace lldb;
19d7b33853SGreg Clayton using namespace lldb_private;
20d7b33853SGreg Clayton using namespace llvm;
21d7b33853SGreg Clayton 
EmplaceSafeString(llvm::json::Object & obj,llvm::StringRef key,const std::string & str)22c571988eSGreg Clayton static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
23c571988eSGreg Clayton                               const std::string &str) {
24c571988eSGreg Clayton   if (str.empty())
25c571988eSGreg Clayton     return;
26c571988eSGreg Clayton   if (LLVM_LIKELY(llvm::json::isUTF8(str)))
27c571988eSGreg Clayton     obj.try_emplace(key, str);
28c571988eSGreg Clayton   else
29c571988eSGreg Clayton     obj.try_emplace(key, llvm::json::fixUTF8(str));
30c571988eSGreg Clayton }
31c571988eSGreg Clayton 
ToJSON() const32d7b33853SGreg Clayton json::Value StatsSuccessFail::ToJSON() const {
33d7b33853SGreg Clayton   return json::Object{{"successes", successes}, {"failures", failures}};
34d7b33853SGreg Clayton }
35d7b33853SGreg Clayton 
elapsed(const StatsTimepoint & start,const StatsTimepoint & end)36d7b33853SGreg Clayton static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) {
374f89157bSPavel Labath   StatsDuration::Duration elapsed =
384f89157bSPavel Labath       end.time_since_epoch() - start.time_since_epoch();
39d7b33853SGreg Clayton   return elapsed.count();
40d7b33853SGreg Clayton }
41d7b33853SGreg Clayton 
CollectStats(Target & target)42c571988eSGreg Clayton void TargetStats::CollectStats(Target &target) {
43c571988eSGreg Clayton   m_module_identifiers.clear();
44c571988eSGreg Clayton   for (ModuleSP module_sp : target.GetImages().Modules())
45c571988eSGreg Clayton     m_module_identifiers.emplace_back((intptr_t)module_sp.get());
46c571988eSGreg Clayton }
47c571988eSGreg Clayton 
ToJSON() const48c571988eSGreg Clayton json::Value ModuleStats::ToJSON() const {
49c571988eSGreg Clayton   json::Object module;
50c571988eSGreg Clayton   EmplaceSafeString(module, "path", path);
51c571988eSGreg Clayton   EmplaceSafeString(module, "uuid", uuid);
52c571988eSGreg Clayton   EmplaceSafeString(module, "triple", triple);
53c571988eSGreg Clayton   module.try_emplace("identifier", identifier);
54c571988eSGreg Clayton   module.try_emplace("symbolTableParseTime", symtab_parse_time);
55c571988eSGreg Clayton   module.try_emplace("symbolTableIndexTime", symtab_index_time);
56a2154b19SGreg Clayton   module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache);
57a2154b19SGreg Clayton   module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache);
582887d9fdSGreg Clayton   module.try_emplace("debugInfoParseTime", debug_parse_time);
592887d9fdSGreg Clayton   module.try_emplace("debugInfoIndexTime", debug_index_time);
602887d9fdSGreg Clayton   module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size);
61a2154b19SGreg Clayton   module.try_emplace("debugInfoIndexLoadedFromCache",
62a2154b19SGreg Clayton                      debug_info_index_loaded_from_cache);
63a2154b19SGreg Clayton   module.try_emplace("debugInfoIndexSavedToCache",
64a2154b19SGreg Clayton                      debug_info_index_saved_to_cache);
65*7b81192dSJeffrey Tan   module.try_emplace("debugInfoEnabled", debug_info_enabled);
66*7b81192dSJeffrey Tan   module.try_emplace("symbolTableStripped", symtab_stripped);
673db7cc1bSGreg Clayton   if (!symfile_path.empty())
683db7cc1bSGreg Clayton     module.try_emplace("symbolFilePath", symfile_path);
693db7cc1bSGreg Clayton 
703db7cc1bSGreg Clayton   if (!symfile_modules.empty()) {
713db7cc1bSGreg Clayton     json::Array symfile_ids;
723db7cc1bSGreg Clayton     for (const auto symfile_id: symfile_modules)
733db7cc1bSGreg Clayton       symfile_ids.emplace_back(symfile_id);
743db7cc1bSGreg Clayton     module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids));
753db7cc1bSGreg Clayton   }
76c571988eSGreg Clayton   return module;
77c571988eSGreg Clayton }
78c571988eSGreg Clayton 
ToJSON() const79cd8122b2SJonas Devlieghere llvm::json::Value ConstStringStats::ToJSON() const {
80cd8122b2SJonas Devlieghere   json::Object obj;
81cd8122b2SJonas Devlieghere   obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal());
82cd8122b2SJonas Devlieghere   obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed());
83cd8122b2SJonas Devlieghere   obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused());
84cd8122b2SJonas Devlieghere   return obj;
85cd8122b2SJonas Devlieghere }
86cd8122b2SJonas Devlieghere 
ToJSON(Target & target)87c571988eSGreg Clayton json::Value TargetStats::ToJSON(Target &target) {
88c571988eSGreg Clayton   CollectStats(target);
89c571988eSGreg Clayton 
90c571988eSGreg Clayton   json::Array json_module_uuid_array;
91c571988eSGreg Clayton   for (auto module_identifier : m_module_identifiers)
92c571988eSGreg Clayton     json_module_uuid_array.emplace_back(module_identifier);
93c571988eSGreg Clayton 
94c571988eSGreg Clayton   json::Object target_metrics_json{
95c571988eSGreg Clayton       {m_expr_eval.name, m_expr_eval.ToJSON()},
96c571988eSGreg Clayton       {m_frame_var.name, m_frame_var.ToJSON()},
97c571988eSGreg Clayton       {"moduleIdentifiers", std::move(json_module_uuid_array)}};
98c571988eSGreg Clayton 
99d7b33853SGreg Clayton   if (m_launch_or_attach_time && m_first_private_stop_time) {
100d7b33853SGreg Clayton     double elapsed_time =
101d7b33853SGreg Clayton         elapsed(*m_launch_or_attach_time, *m_first_private_stop_time);
102d7b33853SGreg Clayton     target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);
103d7b33853SGreg Clayton   }
104d7b33853SGreg Clayton   if (m_launch_or_attach_time && m_first_public_stop_time) {
105d7b33853SGreg Clayton     double elapsed_time =
106d7b33853SGreg Clayton         elapsed(*m_launch_or_attach_time, *m_first_public_stop_time);
107d7b33853SGreg Clayton     target_metrics_json.try_emplace("firstStopTime", elapsed_time);
108d7b33853SGreg Clayton   }
1094f89157bSPavel Labath   target_metrics_json.try_emplace("targetCreateTime",
1104f89157bSPavel Labath                                   m_create_time.get().count());
111d7b33853SGreg Clayton 
112fb254968SGreg Clayton   json::Array breakpoints_array;
113fb254968SGreg Clayton   double totalBreakpointResolveTime = 0.0;
114fb254968SGreg Clayton   // Rport both the normal breakpoint list and the internal breakpoint list.
115fb254968SGreg Clayton   for (int i = 0; i < 2; ++i) {
116fb254968SGreg Clayton     BreakpointList &breakpoints = target.GetBreakpointList(i == 1);
117fb254968SGreg Clayton     std::unique_lock<std::recursive_mutex> lock;
118fb254968SGreg Clayton     breakpoints.GetListMutex(lock);
119fb254968SGreg Clayton     size_t num_breakpoints = breakpoints.GetSize();
120fb254968SGreg Clayton     for (size_t i = 0; i < num_breakpoints; i++) {
121fb254968SGreg Clayton       Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
122fb254968SGreg Clayton       breakpoints_array.push_back(bp->GetStatistics());
123fb254968SGreg Clayton       totalBreakpointResolveTime += bp->GetResolveTime().count();
124fb254968SGreg Clayton     }
125fb254968SGreg Clayton   }
126fb254968SGreg Clayton 
12713005564SGreg Clayton   ProcessSP process_sp = target.GetProcessSP();
12813005564SGreg Clayton   if (process_sp) {
12913005564SGreg Clayton     UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();
13013005564SGreg Clayton     if (unix_signals_sp)
13113005564SGreg Clayton       target_metrics_json.try_emplace("signals",
13213005564SGreg Clayton                                       unix_signals_sp->GetHitCountStatistics());
133dbd36e1eSGreg Clayton     uint32_t stop_id = process_sp->GetStopID();
134dbd36e1eSGreg Clayton     target_metrics_json.try_emplace("stopCount", stop_id);
13513005564SGreg Clayton   }
136fb254968SGreg Clayton   target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array));
137fb254968SGreg Clayton   target_metrics_json.try_emplace("totalBreakpointResolveTime",
138fb254968SGreg Clayton                                   totalBreakpointResolveTime);
139fb254968SGreg Clayton 
140d7b33853SGreg Clayton   return target_metrics_json;
141d7b33853SGreg Clayton }
142d7b33853SGreg Clayton 
SetLaunchOrAttachTime()143d7b33853SGreg Clayton void TargetStats::SetLaunchOrAttachTime() {
144d7b33853SGreg Clayton   m_launch_or_attach_time = StatsClock::now();
145d7b33853SGreg Clayton   m_first_private_stop_time = llvm::None;
146d7b33853SGreg Clayton }
147d7b33853SGreg Clayton 
SetFirstPrivateStopTime()148d7b33853SGreg Clayton void TargetStats::SetFirstPrivateStopTime() {
149d7b33853SGreg Clayton   // Launching and attaching has many paths depending on if synchronous mode
150d7b33853SGreg Clayton   // was used or if we are stopping at the entry point or not. Only set the
151d7b33853SGreg Clayton   // first stop time if it hasn't already been set.
152d7b33853SGreg Clayton   if (!m_first_private_stop_time)
153d7b33853SGreg Clayton     m_first_private_stop_time = StatsClock::now();
154d7b33853SGreg Clayton }
155d7b33853SGreg Clayton 
SetFirstPublicStopTime()156d7b33853SGreg Clayton void TargetStats::SetFirstPublicStopTime() {
157d7b33853SGreg Clayton   // Launching and attaching has many paths depending on if synchronous mode
158d7b33853SGreg Clayton   // was used or if we are stopping at the entry point or not. Only set the
159d7b33853SGreg Clayton   // first stop time if it hasn't already been set.
160d7b33853SGreg Clayton   if (!m_first_public_stop_time)
161d7b33853SGreg Clayton     m_first_public_stop_time = StatsClock::now();
162d7b33853SGreg Clayton }
163d7b33853SGreg Clayton 
164d7b33853SGreg Clayton bool DebuggerStats::g_collecting_stats = false;
165d7b33853SGreg Clayton 
ReportStatistics(Debugger & debugger,Target * target)166c571988eSGreg Clayton llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger,
167c571988eSGreg Clayton                                                   Target *target) {
168c571988eSGreg Clayton   json::Array json_targets;
169c571988eSGreg Clayton   json::Array json_modules;
170c571988eSGreg Clayton   double symtab_parse_time = 0.0;
171c571988eSGreg Clayton   double symtab_index_time = 0.0;
1722887d9fdSGreg Clayton   double debug_parse_time = 0.0;
1732887d9fdSGreg Clayton   double debug_index_time = 0.0;
174a2154b19SGreg Clayton   uint32_t symtabs_loaded = 0;
175a2154b19SGreg Clayton   uint32_t symtabs_saved = 0;
176a2154b19SGreg Clayton   uint32_t debug_index_loaded = 0;
177a2154b19SGreg Clayton   uint32_t debug_index_saved = 0;
1782887d9fdSGreg Clayton   uint64_t debug_info_size = 0;
179c571988eSGreg Clayton   if (target) {
180c571988eSGreg Clayton     json_targets.emplace_back(target->ReportStatistics());
181c571988eSGreg Clayton   } else {
182c571988eSGreg Clayton     for (const auto &target : debugger.GetTargetList().Targets())
183c571988eSGreg Clayton       json_targets.emplace_back(target->ReportStatistics());
184d7b33853SGreg Clayton   }
185c571988eSGreg Clayton   std::vector<ModuleStats> modules;
186c571988eSGreg Clayton   std::lock_guard<std::recursive_mutex> guard(
187c571988eSGreg Clayton       Module::GetAllocationModuleCollectionMutex());
188*7b81192dSJeffrey Tan   const uint64_t num_modules = Module::GetNumberAllocatedModules();
189*7b81192dSJeffrey Tan   uint32_t num_debug_info_enabled_modules = 0;
190*7b81192dSJeffrey Tan   uint32_t num_modules_has_debug_info = 0;
191*7b81192dSJeffrey Tan   uint32_t num_stripped_modules = 0;
192c571988eSGreg Clayton   for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
193c571988eSGreg Clayton     Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
194c571988eSGreg Clayton     ModuleStats module_stat;
195c571988eSGreg Clayton     module_stat.identifier = (intptr_t)module;
196c571988eSGreg Clayton     module_stat.path = module->GetFileSpec().GetPath();
1972887d9fdSGreg Clayton     if (ConstString object_name = module->GetObjectName()) {
1982887d9fdSGreg Clayton       module_stat.path.append(1, '(');
1992887d9fdSGreg Clayton       module_stat.path.append(object_name.GetStringRef().str());
2002887d9fdSGreg Clayton       module_stat.path.append(1, ')');
2012887d9fdSGreg Clayton     }
202c571988eSGreg Clayton     module_stat.uuid = module->GetUUID().GetAsString();
203c571988eSGreg Clayton     module_stat.triple = module->GetArchitecture().GetTriple().str();
2044f89157bSPavel Labath     module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
2054f89157bSPavel Labath     module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
206a2154b19SGreg Clayton     Symtab *symtab = module->GetSymtab();
207a2154b19SGreg Clayton     if (symtab) {
208a2154b19SGreg Clayton       module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();
209a2154b19SGreg Clayton       if (module_stat.symtab_loaded_from_cache)
210a2154b19SGreg Clayton         ++symtabs_loaded;
211a2154b19SGreg Clayton       module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache();
212a2154b19SGreg Clayton       if (module_stat.symtab_saved_to_cache)
213a2154b19SGreg Clayton         ++symtabs_saved;
214a2154b19SGreg Clayton     }
2152887d9fdSGreg Clayton     SymbolFile *sym_file = module->GetSymbolFile();
2162887d9fdSGreg Clayton     if (sym_file) {
2173db7cc1bSGreg Clayton 
2183db7cc1bSGreg Clayton       if (sym_file->GetObjectFile() != module->GetObjectFile())
2193db7cc1bSGreg Clayton         module_stat.symfile_path =
2203db7cc1bSGreg Clayton             sym_file->GetObjectFile()->GetFileSpec().GetPath();
2212887d9fdSGreg Clayton       module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
2222887d9fdSGreg Clayton       module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
2232887d9fdSGreg Clayton       module_stat.debug_info_size = sym_file->GetDebugInfoSize();
224a2154b19SGreg Clayton       module_stat.debug_info_index_loaded_from_cache =
225a2154b19SGreg Clayton           sym_file->GetDebugInfoIndexWasLoadedFromCache();
226a2154b19SGreg Clayton       if (module_stat.debug_info_index_loaded_from_cache)
227a2154b19SGreg Clayton         ++debug_index_loaded;
228a2154b19SGreg Clayton       module_stat.debug_info_index_saved_to_cache =
229a2154b19SGreg Clayton           sym_file->GetDebugInfoIndexWasSavedToCache();
230a2154b19SGreg Clayton       if (module_stat.debug_info_index_saved_to_cache)
231a2154b19SGreg Clayton         ++debug_index_saved;
2323db7cc1bSGreg Clayton       ModuleList symbol_modules = sym_file->GetDebugInfoModules();
2333db7cc1bSGreg Clayton       for (const auto &symbol_module: symbol_modules.Modules())
2343db7cc1bSGreg Clayton         module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());
235*7b81192dSJeffrey Tan       module_stat.symtab_stripped = module->GetObjectFile()->IsStripped();
236*7b81192dSJeffrey Tan       if (module_stat.symtab_stripped)
237*7b81192dSJeffrey Tan         ++num_stripped_modules;
238*7b81192dSJeffrey Tan       module_stat.debug_info_enabled = sym_file->GetLoadDebugInfoEnabled() &&
239*7b81192dSJeffrey Tan                                        module_stat.debug_info_size > 0;
240*7b81192dSJeffrey Tan       if (module_stat.debug_info_enabled)
241*7b81192dSJeffrey Tan         ++num_debug_info_enabled_modules;
242*7b81192dSJeffrey Tan       if (module_stat.debug_info_size > 0)
243*7b81192dSJeffrey Tan         ++num_modules_has_debug_info;
2442887d9fdSGreg Clayton     }
245c571988eSGreg Clayton     symtab_parse_time += module_stat.symtab_parse_time;
246c571988eSGreg Clayton     symtab_index_time += module_stat.symtab_index_time;
2472887d9fdSGreg Clayton     debug_parse_time += module_stat.debug_parse_time;
2482887d9fdSGreg Clayton     debug_index_time += module_stat.debug_index_time;
2492887d9fdSGreg Clayton     debug_info_size += module_stat.debug_info_size;
250c571988eSGreg Clayton     json_modules.emplace_back(module_stat.ToJSON());
251c571988eSGreg Clayton   }
252c571988eSGreg Clayton 
253cd8122b2SJonas Devlieghere   ConstStringStats const_string_stats;
254cd8122b2SJonas Devlieghere   json::Object json_memory{
255cd8122b2SJonas Devlieghere       {"strings", const_string_stats.ToJSON()},
256cd8122b2SJonas Devlieghere   };
257cd8122b2SJonas Devlieghere 
258d7b33853SGreg Clayton   json::Object global_stats{
259c571988eSGreg Clayton       {"targets", std::move(json_targets)},
260c571988eSGreg Clayton       {"modules", std::move(json_modules)},
261cd8122b2SJonas Devlieghere       {"memory", std::move(json_memory)},
262c571988eSGreg Clayton       {"totalSymbolTableParseTime", symtab_parse_time},
263c571988eSGreg Clayton       {"totalSymbolTableIndexTime", symtab_index_time},
264a2154b19SGreg Clayton       {"totalSymbolTablesLoadedFromCache", symtabs_loaded},
265a2154b19SGreg Clayton       {"totalSymbolTablesSavedToCache", symtabs_saved},
2662887d9fdSGreg Clayton       {"totalDebugInfoParseTime", debug_parse_time},
2672887d9fdSGreg Clayton       {"totalDebugInfoIndexTime", debug_index_time},
268a2154b19SGreg Clayton       {"totalDebugInfoIndexLoadedFromCache", debug_index_loaded},
269a2154b19SGreg Clayton       {"totalDebugInfoIndexSavedToCache", debug_index_saved},
2702887d9fdSGreg Clayton       {"totalDebugInfoByteSize", debug_info_size},
271*7b81192dSJeffrey Tan       {"totalModuleCount", num_modules},
272*7b81192dSJeffrey Tan       {"totalModuleCountHasDebugInfo", num_modules_has_debug_info},
273*7b81192dSJeffrey Tan       {"totalDebugInfoEnabled", num_debug_info_enabled_modules},
274*7b81192dSJeffrey Tan       {"totalSymbolTableStripped", num_stripped_modules},
275d7b33853SGreg Clayton   };
276d7b33853SGreg Clayton   return std::move(global_stats);
277d7b33853SGreg Clayton }
278