xref: /src/contrib/llvm-project/lldb/source/Target/Statistics.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1c0981da4SDimitry Andric //===-- Statistics.cpp ----------------------------------------------------===//
2c0981da4SDimitry Andric //
3c0981da4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c0981da4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5c0981da4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c0981da4SDimitry Andric //
7c0981da4SDimitry Andric //===----------------------------------------------------------------------===//
8c0981da4SDimitry Andric 
9c0981da4SDimitry Andric #include "lldb/Target/Statistics.h"
10c0981da4SDimitry Andric 
11c0981da4SDimitry Andric #include "lldb/Core/Debugger.h"
12c0981da4SDimitry Andric #include "lldb/Core/Module.h"
13ac9a064cSDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
14c0981da4SDimitry Andric #include "lldb/Symbol/SymbolFile.h"
15ac9a064cSDimitry Andric #include "lldb/Target/DynamicLoader.h"
16c0981da4SDimitry Andric #include "lldb/Target/Process.h"
17c0981da4SDimitry Andric #include "lldb/Target/Target.h"
18c0981da4SDimitry Andric #include "lldb/Target/UnixSignals.h"
19ac9a064cSDimitry Andric #include "lldb/Utility/StructuredData.h"
20c0981da4SDimitry Andric 
21c0981da4SDimitry Andric using namespace lldb;
22c0981da4SDimitry Andric using namespace lldb_private;
23c0981da4SDimitry Andric using namespace llvm;
24c0981da4SDimitry Andric 
EmplaceSafeString(llvm::json::Object & obj,llvm::StringRef key,const std::string & str)25c0981da4SDimitry Andric static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
26c0981da4SDimitry Andric                               const std::string &str) {
27c0981da4SDimitry Andric   if (str.empty())
28c0981da4SDimitry Andric     return;
29c0981da4SDimitry Andric   if (LLVM_LIKELY(llvm::json::isUTF8(str)))
30c0981da4SDimitry Andric     obj.try_emplace(key, str);
31c0981da4SDimitry Andric   else
32c0981da4SDimitry Andric     obj.try_emplace(key, llvm::json::fixUTF8(str));
33c0981da4SDimitry Andric }
34c0981da4SDimitry Andric 
ToJSON() const35c0981da4SDimitry Andric json::Value StatsSuccessFail::ToJSON() const {
36c0981da4SDimitry Andric   return json::Object{{"successes", successes}, {"failures", failures}};
37c0981da4SDimitry Andric }
38c0981da4SDimitry Andric 
elapsed(const StatsTimepoint & start,const StatsTimepoint & end)39c0981da4SDimitry Andric static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) {
406f8fc217SDimitry Andric   StatsDuration::Duration elapsed =
416f8fc217SDimitry Andric       end.time_since_epoch() - start.time_since_epoch();
42c0981da4SDimitry Andric   return elapsed.count();
43c0981da4SDimitry Andric }
44c0981da4SDimitry Andric 
CollectStats(Target & target)45c0981da4SDimitry Andric void TargetStats::CollectStats(Target &target) {
46c0981da4SDimitry Andric   m_module_identifiers.clear();
47c0981da4SDimitry Andric   for (ModuleSP module_sp : target.GetImages().Modules())
48c0981da4SDimitry Andric     m_module_identifiers.emplace_back((intptr_t)module_sp.get());
49c0981da4SDimitry Andric }
50c0981da4SDimitry Andric 
ToJSON() const51c0981da4SDimitry Andric json::Value ModuleStats::ToJSON() const {
52c0981da4SDimitry Andric   json::Object module;
53c0981da4SDimitry Andric   EmplaceSafeString(module, "path", path);
54c0981da4SDimitry Andric   EmplaceSafeString(module, "uuid", uuid);
55c0981da4SDimitry Andric   EmplaceSafeString(module, "triple", triple);
56c0981da4SDimitry Andric   module.try_emplace("identifier", identifier);
57c0981da4SDimitry Andric   module.try_emplace("symbolTableParseTime", symtab_parse_time);
58c0981da4SDimitry Andric   module.try_emplace("symbolTableIndexTime", symtab_index_time);
596f8fc217SDimitry Andric   module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache);
606f8fc217SDimitry Andric   module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache);
61c0981da4SDimitry Andric   module.try_emplace("debugInfoParseTime", debug_parse_time);
62c0981da4SDimitry Andric   module.try_emplace("debugInfoIndexTime", debug_index_time);
63c0981da4SDimitry Andric   module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size);
646f8fc217SDimitry Andric   module.try_emplace("debugInfoIndexLoadedFromCache",
656f8fc217SDimitry Andric                      debug_info_index_loaded_from_cache);
666f8fc217SDimitry Andric   module.try_emplace("debugInfoIndexSavedToCache",
676f8fc217SDimitry Andric                      debug_info_index_saved_to_cache);
68145449b1SDimitry Andric   module.try_emplace("debugInfoEnabled", debug_info_enabled);
69e3b55780SDimitry Andric   module.try_emplace("debugInfoHadVariableErrors",
70e3b55780SDimitry Andric                      debug_info_had_variable_errors);
71e3b55780SDimitry Andric   module.try_emplace("debugInfoHadIncompleteTypes",
72e3b55780SDimitry Andric                      debug_info_had_incomplete_types);
73145449b1SDimitry Andric   module.try_emplace("symbolTableStripped", symtab_stripped);
74145449b1SDimitry Andric   if (!symfile_path.empty())
75145449b1SDimitry Andric     module.try_emplace("symbolFilePath", symfile_path);
76145449b1SDimitry Andric 
77145449b1SDimitry Andric   if (!symfile_modules.empty()) {
78145449b1SDimitry Andric     json::Array symfile_ids;
79145449b1SDimitry Andric     for (const auto symfile_id: symfile_modules)
80145449b1SDimitry Andric       symfile_ids.emplace_back(symfile_id);
81145449b1SDimitry Andric     module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids));
82145449b1SDimitry Andric   }
83e3b55780SDimitry Andric 
84e3b55780SDimitry Andric   if (!type_system_stats.empty()) {
85e3b55780SDimitry Andric     json::Array type_systems;
86e3b55780SDimitry Andric     for (const auto &entry : type_system_stats) {
87e3b55780SDimitry Andric       json::Object obj;
88e3b55780SDimitry Andric       obj.try_emplace(entry.first().str(), entry.second);
89e3b55780SDimitry Andric       type_systems.emplace_back(std::move(obj));
90e3b55780SDimitry Andric     }
91e3b55780SDimitry Andric     module.try_emplace("typeSystemInfo", std::move(type_systems));
92e3b55780SDimitry Andric   }
93e3b55780SDimitry Andric 
94c0981da4SDimitry Andric   return module;
95c0981da4SDimitry Andric }
96c0981da4SDimitry Andric 
ToJSON() const976f8fc217SDimitry Andric llvm::json::Value ConstStringStats::ToJSON() const {
986f8fc217SDimitry Andric   json::Object obj;
996f8fc217SDimitry Andric   obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal());
1006f8fc217SDimitry Andric   obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed());
1016f8fc217SDimitry Andric   obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused());
1026f8fc217SDimitry Andric   return obj;
1036f8fc217SDimitry Andric }
1046f8fc217SDimitry Andric 
105ac9a064cSDimitry Andric json::Value
ToJSON(Target & target,const lldb_private::StatisticsOptions & options)106ac9a064cSDimitry Andric TargetStats::ToJSON(Target &target,
107ac9a064cSDimitry Andric                     const lldb_private::StatisticsOptions &options) {
108ac9a064cSDimitry Andric   json::Object target_metrics_json;
109ac9a064cSDimitry Andric   ProcessSP process_sp = target.GetProcessSP();
110ac9a064cSDimitry Andric   const bool summary_only = options.GetSummaryOnly();
111ac9a064cSDimitry Andric   const bool include_modules = options.GetIncludeModules();
112ac9a064cSDimitry Andric   if (!summary_only) {
113c0981da4SDimitry Andric     CollectStats(target);
114c0981da4SDimitry Andric 
115c0981da4SDimitry Andric     json::Array json_module_uuid_array;
116c0981da4SDimitry Andric     for (auto module_identifier : m_module_identifiers)
117c0981da4SDimitry Andric       json_module_uuid_array.emplace_back(module_identifier);
118c0981da4SDimitry Andric 
119ac9a064cSDimitry Andric     target_metrics_json.try_emplace(m_expr_eval.name, m_expr_eval.ToJSON());
120ac9a064cSDimitry Andric     target_metrics_json.try_emplace(m_frame_var.name, m_frame_var.ToJSON());
121ac9a064cSDimitry Andric     if (include_modules)
122ac9a064cSDimitry Andric       target_metrics_json.try_emplace("moduleIdentifiers",
123ac9a064cSDimitry Andric                                       std::move(json_module_uuid_array));
124c0981da4SDimitry Andric 
125c0981da4SDimitry Andric     if (m_launch_or_attach_time && m_first_private_stop_time) {
126c0981da4SDimitry Andric       double elapsed_time =
127c0981da4SDimitry Andric           elapsed(*m_launch_or_attach_time, *m_first_private_stop_time);
128c0981da4SDimitry Andric       target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);
129c0981da4SDimitry Andric     }
130c0981da4SDimitry Andric     if (m_launch_or_attach_time && m_first_public_stop_time) {
131c0981da4SDimitry Andric       double elapsed_time =
132c0981da4SDimitry Andric           elapsed(*m_launch_or_attach_time, *m_first_public_stop_time);
133c0981da4SDimitry Andric       target_metrics_json.try_emplace("firstStopTime", elapsed_time);
134c0981da4SDimitry Andric     }
1356f8fc217SDimitry Andric     target_metrics_json.try_emplace("targetCreateTime",
1366f8fc217SDimitry Andric                                     m_create_time.get().count());
137c0981da4SDimitry Andric 
138c0981da4SDimitry Andric     json::Array breakpoints_array;
139c0981da4SDimitry Andric     double totalBreakpointResolveTime = 0.0;
140ac9a064cSDimitry Andric     // Report both the normal breakpoint list and the internal breakpoint list.
141c0981da4SDimitry Andric     for (int i = 0; i < 2; ++i) {
142c0981da4SDimitry Andric       BreakpointList &breakpoints = target.GetBreakpointList(i == 1);
143c0981da4SDimitry Andric       std::unique_lock<std::recursive_mutex> lock;
144c0981da4SDimitry Andric       breakpoints.GetListMutex(lock);
145c0981da4SDimitry Andric       size_t num_breakpoints = breakpoints.GetSize();
146c0981da4SDimitry Andric       for (size_t i = 0; i < num_breakpoints; i++) {
147c0981da4SDimitry Andric         Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
148c0981da4SDimitry Andric         breakpoints_array.push_back(bp->GetStatistics());
149c0981da4SDimitry Andric         totalBreakpointResolveTime += bp->GetResolveTime().count();
150c0981da4SDimitry Andric       }
151c0981da4SDimitry Andric     }
152ac9a064cSDimitry Andric     target_metrics_json.try_emplace("breakpoints",
153ac9a064cSDimitry Andric                                     std::move(breakpoints_array));
154ac9a064cSDimitry Andric     target_metrics_json.try_emplace("totalBreakpointResolveTime",
155ac9a064cSDimitry Andric                                     totalBreakpointResolveTime);
156c0981da4SDimitry Andric 
157c0981da4SDimitry Andric     if (process_sp) {
158c0981da4SDimitry Andric       UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();
159c0981da4SDimitry Andric       if (unix_signals_sp)
160ac9a064cSDimitry Andric         target_metrics_json.try_emplace(
161ac9a064cSDimitry Andric             "signals", unix_signals_sp->GetHitCountStatistics());
162ac9a064cSDimitry Andric     }
163ac9a064cSDimitry Andric   }
164ac9a064cSDimitry Andric 
165ac9a064cSDimitry Andric   // Counting "totalSharedLibraryEventHitCount" from breakpoints of kind
166ac9a064cSDimitry Andric   // "shared-library-event".
167ac9a064cSDimitry Andric   {
168ac9a064cSDimitry Andric     uint32_t shared_library_event_breakpoint_hit_count = 0;
169ac9a064cSDimitry Andric     // The "shared-library-event" is only found in the internal breakpoint list.
170ac9a064cSDimitry Andric     BreakpointList &breakpoints = target.GetBreakpointList(/* internal */ true);
171ac9a064cSDimitry Andric     std::unique_lock<std::recursive_mutex> lock;
172ac9a064cSDimitry Andric     breakpoints.GetListMutex(lock);
173ac9a064cSDimitry Andric     size_t num_breakpoints = breakpoints.GetSize();
174ac9a064cSDimitry Andric     for (size_t i = 0; i < num_breakpoints; i++) {
175ac9a064cSDimitry Andric       Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
176ac9a064cSDimitry Andric       if (strcmp(bp->GetBreakpointKind(), "shared-library-event") == 0)
177ac9a064cSDimitry Andric         shared_library_event_breakpoint_hit_count += bp->GetHitCount();
178ac9a064cSDimitry Andric     }
179ac9a064cSDimitry Andric 
180ac9a064cSDimitry Andric     target_metrics_json.try_emplace("totalSharedLibraryEventHitCount",
181ac9a064cSDimitry Andric                                     shared_library_event_breakpoint_hit_count);
182ac9a064cSDimitry Andric   }
183ac9a064cSDimitry Andric 
184ac9a064cSDimitry Andric   if (process_sp) {
185c0981da4SDimitry Andric     uint32_t stop_id = process_sp->GetStopID();
186c0981da4SDimitry Andric     target_metrics_json.try_emplace("stopCount", stop_id);
187c0981da4SDimitry Andric 
188ac9a064cSDimitry Andric     llvm::StringRef dyld_plugin_name;
189ac9a064cSDimitry Andric     if (process_sp->GetDynamicLoader())
190ac9a064cSDimitry Andric       dyld_plugin_name = process_sp->GetDynamicLoader()->GetPluginName();
191ac9a064cSDimitry Andric     target_metrics_json.try_emplace("dyldPluginName", dyld_plugin_name);
192ac9a064cSDimitry Andric   }
193ac9a064cSDimitry Andric   target_metrics_json.try_emplace("sourceMapDeduceCount",
194ac9a064cSDimitry Andric                                   m_source_map_deduce_count);
195c0981da4SDimitry Andric   return target_metrics_json;
196c0981da4SDimitry Andric }
197c0981da4SDimitry Andric 
SetLaunchOrAttachTime()198c0981da4SDimitry Andric void TargetStats::SetLaunchOrAttachTime() {
199c0981da4SDimitry Andric   m_launch_or_attach_time = StatsClock::now();
200e3b55780SDimitry Andric   m_first_private_stop_time = std::nullopt;
201c0981da4SDimitry Andric }
202c0981da4SDimitry Andric 
SetFirstPrivateStopTime()203c0981da4SDimitry Andric void TargetStats::SetFirstPrivateStopTime() {
204c0981da4SDimitry Andric   // Launching and attaching has many paths depending on if synchronous mode
205c0981da4SDimitry Andric   // was used or if we are stopping at the entry point or not. Only set the
206c0981da4SDimitry Andric   // first stop time if it hasn't already been set.
207c0981da4SDimitry Andric   if (!m_first_private_stop_time)
208c0981da4SDimitry Andric     m_first_private_stop_time = StatsClock::now();
209c0981da4SDimitry Andric }
210c0981da4SDimitry Andric 
SetFirstPublicStopTime()211c0981da4SDimitry Andric void TargetStats::SetFirstPublicStopTime() {
212c0981da4SDimitry Andric   // Launching and attaching has many paths depending on if synchronous mode
213c0981da4SDimitry Andric   // was used or if we are stopping at the entry point or not. Only set the
214c0981da4SDimitry Andric   // first stop time if it hasn't already been set.
215c0981da4SDimitry Andric   if (!m_first_public_stop_time)
216c0981da4SDimitry Andric     m_first_public_stop_time = StatsClock::now();
217c0981da4SDimitry Andric }
218c0981da4SDimitry Andric 
IncreaseSourceMapDeduceCount()219e3b55780SDimitry Andric void TargetStats::IncreaseSourceMapDeduceCount() {
220e3b55780SDimitry Andric   ++m_source_map_deduce_count;
221e3b55780SDimitry Andric }
222e3b55780SDimitry Andric 
223c0981da4SDimitry Andric bool DebuggerStats::g_collecting_stats = false;
224c0981da4SDimitry Andric 
ReportStatistics(Debugger & debugger,Target * target,const lldb_private::StatisticsOptions & options)225ac9a064cSDimitry Andric llvm::json::Value DebuggerStats::ReportStatistics(
226ac9a064cSDimitry Andric     Debugger &debugger, Target *target,
227ac9a064cSDimitry Andric     const lldb_private::StatisticsOptions &options) {
228ac9a064cSDimitry Andric 
229ac9a064cSDimitry Andric   const bool summary_only = options.GetSummaryOnly();
230ac9a064cSDimitry Andric   const bool load_all_debug_info = options.GetLoadAllDebugInfo();
231ac9a064cSDimitry Andric   const bool include_targets = options.GetIncludeTargets();
232ac9a064cSDimitry Andric   const bool include_modules = options.GetIncludeModules();
233ac9a064cSDimitry Andric   const bool include_transcript = options.GetIncludeTranscript();
234ac9a064cSDimitry Andric 
235c0981da4SDimitry Andric   json::Array json_targets;
236c0981da4SDimitry Andric   json::Array json_modules;
237c0981da4SDimitry Andric   double symtab_parse_time = 0.0;
238c0981da4SDimitry Andric   double symtab_index_time = 0.0;
239c0981da4SDimitry Andric   double debug_parse_time = 0.0;
240c0981da4SDimitry Andric   double debug_index_time = 0.0;
2416f8fc217SDimitry Andric   uint32_t symtabs_loaded = 0;
2426f8fc217SDimitry Andric   uint32_t symtabs_saved = 0;
2436f8fc217SDimitry Andric   uint32_t debug_index_loaded = 0;
2446f8fc217SDimitry Andric   uint32_t debug_index_saved = 0;
245c0981da4SDimitry Andric   uint64_t debug_info_size = 0;
246ac9a064cSDimitry Andric 
247c0981da4SDimitry Andric   std::vector<ModuleStats> modules;
248c0981da4SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(
249c0981da4SDimitry Andric       Module::GetAllocationModuleCollectionMutex());
250145449b1SDimitry Andric   const uint64_t num_modules = Module::GetNumberAllocatedModules();
251145449b1SDimitry Andric   uint32_t num_debug_info_enabled_modules = 0;
252145449b1SDimitry Andric   uint32_t num_modules_has_debug_info = 0;
253e3b55780SDimitry Andric   uint32_t num_modules_with_variable_errors = 0;
254e3b55780SDimitry Andric   uint32_t num_modules_with_incomplete_types = 0;
255145449b1SDimitry Andric   uint32_t num_stripped_modules = 0;
256c0981da4SDimitry Andric   for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
257c0981da4SDimitry Andric     Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
258c0981da4SDimitry Andric     ModuleStats module_stat;
2596f8fc217SDimitry Andric     module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
2606f8fc217SDimitry Andric     module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
2616f8fc217SDimitry Andric     Symtab *symtab = module->GetSymtab();
2626f8fc217SDimitry Andric     if (symtab) {
2636f8fc217SDimitry Andric       module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();
2646f8fc217SDimitry Andric       if (module_stat.symtab_loaded_from_cache)
2656f8fc217SDimitry Andric         ++symtabs_loaded;
2666f8fc217SDimitry Andric       module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache();
2676f8fc217SDimitry Andric       if (module_stat.symtab_saved_to_cache)
2686f8fc217SDimitry Andric         ++symtabs_saved;
2696f8fc217SDimitry Andric     }
270c0981da4SDimitry Andric     SymbolFile *sym_file = module->GetSymbolFile();
271c0981da4SDimitry Andric     if (sym_file) {
272ac9a064cSDimitry Andric       if (!summary_only) {
273145449b1SDimitry Andric         if (sym_file->GetObjectFile() != module->GetObjectFile())
274145449b1SDimitry Andric           module_stat.symfile_path =
275145449b1SDimitry Andric               sym_file->GetObjectFile()->GetFileSpec().GetPath();
276ac9a064cSDimitry Andric         ModuleList symbol_modules = sym_file->GetDebugInfoModules();
277ac9a064cSDimitry Andric         for (const auto &symbol_module : symbol_modules.Modules())
278ac9a064cSDimitry Andric           module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());
279ac9a064cSDimitry Andric       }
2806f8fc217SDimitry Andric       module_stat.debug_info_index_loaded_from_cache =
2816f8fc217SDimitry Andric           sym_file->GetDebugInfoIndexWasLoadedFromCache();
2826f8fc217SDimitry Andric       if (module_stat.debug_info_index_loaded_from_cache)
2836f8fc217SDimitry Andric         ++debug_index_loaded;
2846f8fc217SDimitry Andric       module_stat.debug_info_index_saved_to_cache =
2856f8fc217SDimitry Andric           sym_file->GetDebugInfoIndexWasSavedToCache();
2866f8fc217SDimitry Andric       if (module_stat.debug_info_index_saved_to_cache)
2876f8fc217SDimitry Andric         ++debug_index_saved;
288ac9a064cSDimitry Andric       module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
289ac9a064cSDimitry Andric       module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
290ac9a064cSDimitry Andric       module_stat.debug_info_size =
291ac9a064cSDimitry Andric           sym_file->GetDebugInfoSize(load_all_debug_info);
292145449b1SDimitry Andric       module_stat.symtab_stripped = module->GetObjectFile()->IsStripped();
293145449b1SDimitry Andric       if (module_stat.symtab_stripped)
294145449b1SDimitry Andric         ++num_stripped_modules;
295145449b1SDimitry Andric       module_stat.debug_info_enabled = sym_file->GetLoadDebugInfoEnabled() &&
296145449b1SDimitry Andric                                        module_stat.debug_info_size > 0;
297e3b55780SDimitry Andric       module_stat.debug_info_had_variable_errors =
298e3b55780SDimitry Andric           sym_file->GetDebugInfoHadFrameVariableErrors();
299145449b1SDimitry Andric       if (module_stat.debug_info_enabled)
300145449b1SDimitry Andric         ++num_debug_info_enabled_modules;
301145449b1SDimitry Andric       if (module_stat.debug_info_size > 0)
302145449b1SDimitry Andric         ++num_modules_has_debug_info;
303e3b55780SDimitry Andric       if (module_stat.debug_info_had_variable_errors)
304e3b55780SDimitry Andric         ++num_modules_with_variable_errors;
305c0981da4SDimitry Andric     }
306c0981da4SDimitry Andric     symtab_parse_time += module_stat.symtab_parse_time;
307c0981da4SDimitry Andric     symtab_index_time += module_stat.symtab_index_time;
308c0981da4SDimitry Andric     debug_parse_time += module_stat.debug_parse_time;
309c0981da4SDimitry Andric     debug_index_time += module_stat.debug_index_time;
310c0981da4SDimitry Andric     debug_info_size += module_stat.debug_info_size;
311e3b55780SDimitry Andric     module->ForEachTypeSystem([&](lldb::TypeSystemSP ts) {
312e3b55780SDimitry Andric       if (auto stats = ts->ReportStatistics())
313e3b55780SDimitry Andric         module_stat.type_system_stats.insert({ts->GetPluginName(), *stats});
314e3b55780SDimitry Andric       if (ts->GetHasForcefullyCompletedTypes())
315e3b55780SDimitry Andric         module_stat.debug_info_had_incomplete_types = true;
316e3b55780SDimitry Andric       return true;
317e3b55780SDimitry Andric     });
318e3b55780SDimitry Andric     if (module_stat.debug_info_had_incomplete_types)
319e3b55780SDimitry Andric       ++num_modules_with_incomplete_types;
320e3b55780SDimitry Andric 
321ac9a064cSDimitry Andric     if (include_modules) {
322ac9a064cSDimitry Andric       module_stat.identifier = (intptr_t)module;
323ac9a064cSDimitry Andric       module_stat.path = module->GetFileSpec().GetPath();
324ac9a064cSDimitry Andric       if (ConstString object_name = module->GetObjectName()) {
325ac9a064cSDimitry Andric         module_stat.path.append(1, '(');
326ac9a064cSDimitry Andric         module_stat.path.append(object_name.GetStringRef().str());
327ac9a064cSDimitry Andric         module_stat.path.append(1, ')');
328ac9a064cSDimitry Andric       }
329ac9a064cSDimitry Andric       module_stat.uuid = module->GetUUID().GetAsString();
330ac9a064cSDimitry Andric       module_stat.triple = module->GetArchitecture().GetTriple().str();
331c0981da4SDimitry Andric       json_modules.emplace_back(module_stat.ToJSON());
332c0981da4SDimitry Andric     }
333ac9a064cSDimitry Andric   }
3346f8fc217SDimitry Andric 
335c0981da4SDimitry Andric   json::Object global_stats{
336c0981da4SDimitry Andric       {"totalSymbolTableParseTime", symtab_parse_time},
337c0981da4SDimitry Andric       {"totalSymbolTableIndexTime", symtab_index_time},
3386f8fc217SDimitry Andric       {"totalSymbolTablesLoadedFromCache", symtabs_loaded},
3396f8fc217SDimitry Andric       {"totalSymbolTablesSavedToCache", symtabs_saved},
340c0981da4SDimitry Andric       {"totalDebugInfoParseTime", debug_parse_time},
341c0981da4SDimitry Andric       {"totalDebugInfoIndexTime", debug_index_time},
3426f8fc217SDimitry Andric       {"totalDebugInfoIndexLoadedFromCache", debug_index_loaded},
3436f8fc217SDimitry Andric       {"totalDebugInfoIndexSavedToCache", debug_index_saved},
344c0981da4SDimitry Andric       {"totalDebugInfoByteSize", debug_info_size},
345145449b1SDimitry Andric       {"totalModuleCount", num_modules},
346145449b1SDimitry Andric       {"totalModuleCountHasDebugInfo", num_modules_has_debug_info},
347e3b55780SDimitry Andric       {"totalModuleCountWithVariableErrors", num_modules_with_variable_errors},
348ac9a064cSDimitry Andric       {"totalModuleCountWithIncompleteTypes",
349ac9a064cSDimitry Andric        num_modules_with_incomplete_types},
350145449b1SDimitry Andric       {"totalDebugInfoEnabled", num_debug_info_enabled_modules},
351145449b1SDimitry Andric       {"totalSymbolTableStripped", num_stripped_modules},
352c0981da4SDimitry Andric   };
353ac9a064cSDimitry Andric 
354ac9a064cSDimitry Andric   if (include_targets) {
355ac9a064cSDimitry Andric     if (target) {
356ac9a064cSDimitry Andric       json_targets.emplace_back(target->ReportStatistics(options));
357ac9a064cSDimitry Andric     } else {
358ac9a064cSDimitry Andric       for (const auto &target : debugger.GetTargetList().Targets())
359ac9a064cSDimitry Andric         json_targets.emplace_back(target->ReportStatistics(options));
360ac9a064cSDimitry Andric     }
361ac9a064cSDimitry Andric     global_stats.try_emplace("targets", std::move(json_targets));
362ac9a064cSDimitry Andric   }
363ac9a064cSDimitry Andric 
364ac9a064cSDimitry Andric   ConstStringStats const_string_stats;
365ac9a064cSDimitry Andric   json::Object json_memory{
366ac9a064cSDimitry Andric       {"strings", const_string_stats.ToJSON()},
367ac9a064cSDimitry Andric   };
368ac9a064cSDimitry Andric   global_stats.try_emplace("memory", std::move(json_memory));
369ac9a064cSDimitry Andric   if (!summary_only) {
370ac9a064cSDimitry Andric     json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();
371ac9a064cSDimitry Andric     global_stats.try_emplace("commands", std::move(cmd_stats));
372ac9a064cSDimitry Andric   }
373ac9a064cSDimitry Andric 
374ac9a064cSDimitry Andric   if (include_modules) {
375ac9a064cSDimitry Andric     global_stats.try_emplace("modules", std::move(json_modules));
376ac9a064cSDimitry Andric   }
377ac9a064cSDimitry Andric 
378ac9a064cSDimitry Andric   if (include_transcript) {
379ac9a064cSDimitry Andric     // When transcript is available, add it to the to-be-returned statistics.
380ac9a064cSDimitry Andric     //
381ac9a064cSDimitry Andric     // NOTE:
382ac9a064cSDimitry Andric     // When the statistics is polled by an LLDB command:
383ac9a064cSDimitry Andric     // - The transcript in the returned statistics *will NOT* contain the
384ac9a064cSDimitry Andric     //   returned statistics itself (otherwise infinite recursion).
385ac9a064cSDimitry Andric     // - The returned statistics *will* be written to the internal transcript
386ac9a064cSDimitry Andric     //   buffer. It *will* appear in the next statistcs or transcript poll.
387ac9a064cSDimitry Andric     //
388ac9a064cSDimitry Andric     // For example, let's say the following commands are run in order:
389ac9a064cSDimitry Andric     // - "version"
390ac9a064cSDimitry Andric     // - "statistics dump"  <- call it "A"
391ac9a064cSDimitry Andric     // - "statistics dump"  <- call it "B"
392ac9a064cSDimitry Andric     // The output of "A" will contain the transcript of "version" and
393ac9a064cSDimitry Andric     // "statistics dump" (A), with the latter having empty output. The output
394ac9a064cSDimitry Andric     // of B will contain the trascnript of "version", "statistics dump" (A),
395ac9a064cSDimitry Andric     // "statistics dump" (B), with A's output populated and B's output empty.
396ac9a064cSDimitry Andric     const StructuredData::Array &transcript =
397ac9a064cSDimitry Andric         debugger.GetCommandInterpreter().GetTranscript();
398ac9a064cSDimitry Andric     if (transcript.GetSize() != 0) {
399ac9a064cSDimitry Andric       std::string buffer;
400ac9a064cSDimitry Andric       llvm::raw_string_ostream ss(buffer);
401ac9a064cSDimitry Andric       json::OStream json_os(ss);
402ac9a064cSDimitry Andric       transcript.Serialize(json_os);
403ac9a064cSDimitry Andric       if (auto json_transcript = llvm::json::parse(ss.str()))
404ac9a064cSDimitry Andric         global_stats.try_emplace("transcript",
405ac9a064cSDimitry Andric                                  std::move(json_transcript.get()));
406ac9a064cSDimitry Andric     }
407ac9a064cSDimitry Andric   }
408ac9a064cSDimitry Andric 
409c0981da4SDimitry Andric   return std::move(global_stats);
410c0981da4SDimitry Andric }
411