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