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/Core/PluginManager.h"
14#include "lldb/Interpreter/CommandInterpreter.h"
15#include "lldb/Symbol/SymbolFile.h"
16#include "lldb/Target/DynamicLoader.h"
17#include "lldb/Target/Process.h"
18#include "lldb/Target/Target.h"
19#include "lldb/Target/UnixSignals.h"
20#include "lldb/Utility/StructuredData.h"
21
22using namespace lldb;
23using namespace lldb_private;
24using namespace llvm;
25
26static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
27 const std::string &str) {
28 if (str.empty())
29 return;
30 if (LLVM_LIKELY(llvm::json::isUTF8(str)))
31 obj.try_emplace(K: key, Args: str);
32 else
33 obj.try_emplace(K: key, Args: llvm::json::fixUTF8(S: str));
34}
35
36json::Value StatsSuccessFail::ToJSON() const {
37 return json::Object{{.K: "successes", .V: successes}, {.K: "failures", .V: failures}};
38}
39
40static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) {
41 StatsDuration::Duration elapsed =
42 end.time_since_epoch() - start.time_since_epoch();
43 return elapsed.count();
44}
45
46void TargetStats::CollectStats(Target &target) {
47 m_module_identifiers.clear();
48 for (ModuleSP module_sp : target.GetImages().Modules())
49 m_module_identifiers.emplace_back(args: (intptr_t)module_sp.get());
50}
51
52json::Value ModuleStats::ToJSON() const {
53 json::Object module;
54 EmplaceSafeString(obj&: module, key: "path", str: path);
55 EmplaceSafeString(obj&: module, key: "uuid", str: uuid);
56 EmplaceSafeString(obj&: module, key: "triple", str: triple);
57 module.try_emplace(K: "identifier", Args: identifier);
58 module.try_emplace(K: "symbolTableParseTime", Args: symtab_parse_time);
59 module.try_emplace(K: "symbolTableIndexTime", Args: symtab_index_time);
60 module.try_emplace(K: "symbolTableLoadedFromCache", Args: symtab_loaded_from_cache);
61 module.try_emplace(K: "symbolTableSavedToCache", Args: symtab_saved_to_cache);
62 module.try_emplace(K: "debugInfoParseTime", Args: debug_parse_time);
63 module.try_emplace(K: "debugInfoIndexTime", Args: debug_index_time);
64 module.try_emplace(K: "debugInfoByteSize", Args: (int64_t)debug_info_size);
65 module.try_emplace(K: "debugInfoIndexLoadedFromCache",
66 Args: debug_info_index_loaded_from_cache);
67 module.try_emplace(K: "debugInfoIndexSavedToCache",
68 Args: debug_info_index_saved_to_cache);
69 module.try_emplace(K: "debugInfoEnabled", Args: debug_info_enabled);
70 module.try_emplace(K: "debugInfoHadVariableErrors",
71 Args: debug_info_had_variable_errors);
72 module.try_emplace(K: "debugInfoHadIncompleteTypes",
73 Args: debug_info_had_incomplete_types);
74 module.try_emplace(K: "symbolTableStripped", Args: symtab_stripped);
75 module.try_emplace(K: "symbolTableSymbolCount", Args: symtab_symbol_count);
76 module.try_emplace(K: "dwoFileCount", Args: dwo_file_count);
77 module.try_emplace(K: "loadedDwoFileCount", Args: loaded_dwo_file_count);
78
79 if (!symbol_locator_time.map.empty()) {
80 json::Object obj;
81 for (const auto &entry : symbol_locator_time.map)
82 obj.try_emplace(K: entry.first().str(), Args: entry.second);
83 module.try_emplace(K: "symbolLocatorTime", Args: std::move(obj));
84 }
85
86 if (!symfile_path.empty())
87 module.try_emplace(K: "symbolFilePath", Args: symfile_path);
88
89 if (!symfile_modules.empty()) {
90 json::Array symfile_ids;
91 for (const auto symfile_id : symfile_modules)
92 symfile_ids.emplace_back(A: symfile_id);
93 module.try_emplace(K: "symbolFileModuleIdentifiers", Args: std::move(symfile_ids));
94 }
95
96 if (!type_system_stats.empty()) {
97 json::Array type_systems;
98 for (const auto &entry : type_system_stats) {
99 json::Object obj;
100 obj.try_emplace(K: entry.first().str(), Args: entry.second);
101 type_systems.emplace_back(A: std::move(obj));
102 }
103 module.try_emplace(K: "typeSystemInfo", Args: std::move(type_systems));
104 }
105
106 return module;
107}
108
109llvm::json::Value ConstStringStats::ToJSON() const {
110 json::Object obj;
111 obj.try_emplace<int64_t>(K: "bytesTotal", Args: stats.GetBytesTotal());
112 obj.try_emplace<int64_t>(K: "bytesUsed", Args: stats.GetBytesUsed());
113 obj.try_emplace<int64_t>(K: "bytesUnused", Args: stats.GetBytesUnused());
114 return obj;
115}
116
117json::Value
118TargetStats::ToJSON(Target &target,
119 const lldb_private::StatisticsOptions &options) {
120 json::Object target_metrics_json;
121 ProcessSP process_sp = target.GetProcessSP();
122 const bool summary_only = options.GetSummaryOnly();
123 const bool include_modules = options.GetIncludeModules();
124 if (!summary_only) {
125 CollectStats(target);
126
127 json::Array json_module_uuid_array;
128 for (auto module_identifier : m_module_identifiers)
129 json_module_uuid_array.emplace_back(A&: module_identifier);
130
131 target_metrics_json.try_emplace(K: m_expr_eval.name, Args: m_expr_eval.ToJSON());
132 target_metrics_json.try_emplace(K: m_frame_var.name, Args: m_frame_var.ToJSON());
133 if (include_modules)
134 target_metrics_json.try_emplace(K: "moduleIdentifiers",
135 Args: std::move(json_module_uuid_array));
136
137 if (m_launch_or_attach_time && m_first_private_stop_time) {
138 double elapsed_time =
139 elapsed(start: *m_launch_or_attach_time, end: *m_first_private_stop_time);
140 target_metrics_json.try_emplace(K: "launchOrAttachTime", Args&: elapsed_time);
141 }
142 if (m_launch_or_attach_time && m_first_public_stop_time) {
143 double elapsed_time =
144 elapsed(start: *m_launch_or_attach_time, end: *m_first_public_stop_time);
145 target_metrics_json.try_emplace(K: "firstStopTime", Args&: elapsed_time);
146 }
147 target_metrics_json.try_emplace(K: "targetCreateTime",
148 Args: m_create_time.get().count());
149
150 json::Array breakpoints_array;
151 double totalBreakpointResolveTime = 0.0;
152 // Report both the normal breakpoint list and the internal breakpoint list.
153 for (int i = 0; i < 2; ++i) {
154 BreakpointList &breakpoints = target.GetBreakpointList(internal: i == 1);
155 std::unique_lock<std::recursive_mutex> lock;
156 breakpoints.GetListMutex(lock);
157 size_t num_breakpoints = breakpoints.GetSize();
158 for (size_t i = 0; i < num_breakpoints; i++) {
159 Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
160 breakpoints_array.push_back(E: bp->GetStatistics());
161 totalBreakpointResolveTime += bp->GetResolveTime().count();
162 }
163 }
164 target_metrics_json.try_emplace(K: "breakpoints",
165 Args: std::move(breakpoints_array));
166 target_metrics_json.try_emplace(K: "totalBreakpointResolveTime",
167 Args&: totalBreakpointResolveTime);
168
169 if (process_sp) {
170 UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();
171 if (unix_signals_sp)
172 target_metrics_json.try_emplace(
173 K: "signals", Args: unix_signals_sp->GetHitCountStatistics());
174 }
175 }
176
177 // Counting "totalSharedLibraryEventHitCount" from breakpoints of kind
178 // "shared-library-event".
179 {
180 uint32_t shared_library_event_breakpoint_hit_count = 0;
181 // The "shared-library-event" is only found in the internal breakpoint list.
182 BreakpointList &breakpoints = target.GetBreakpointList(/* internal */ true);
183 std::unique_lock<std::recursive_mutex> lock;
184 breakpoints.GetListMutex(lock);
185 size_t num_breakpoints = breakpoints.GetSize();
186 for (size_t i = 0; i < num_breakpoints; i++) {
187 Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
188 if (strcmp(s1: bp->GetBreakpointKind(), s2: "shared-library-event") == 0)
189 shared_library_event_breakpoint_hit_count += bp->GetHitCount();
190 }
191
192 target_metrics_json.try_emplace(K: "totalSharedLibraryEventHitCount",
193 Args&: shared_library_event_breakpoint_hit_count);
194 }
195
196 if (process_sp) {
197 uint32_t stop_id = process_sp->GetStopID();
198 target_metrics_json.try_emplace(K: "stopCount", Args&: stop_id);
199
200 llvm::StringRef dyld_plugin_name;
201 if (process_sp->GetDynamicLoader())
202 dyld_plugin_name = process_sp->GetDynamicLoader()->GetPluginName();
203 target_metrics_json.try_emplace(K: "dyldPluginName", Args&: dyld_plugin_name);
204 }
205 target_metrics_json.try_emplace(K: "sourceMapDeduceCount",
206 Args&: m_source_map_deduce_count);
207 target_metrics_json.try_emplace(K: "sourceRealpathAttemptCount",
208 Args&: m_source_realpath_attempt_count);
209 target_metrics_json.try_emplace(K: "sourceRealpathCompatibleCount",
210 Args&: m_source_realpath_compatible_count);
211 target_metrics_json.try_emplace(K: "summaryProviderStatistics",
212 Args: target.GetSummaryStatisticsCache().ToJSON());
213 return target_metrics_json;
214}
215
216void TargetStats::Reset(Target &target) {
217 m_launch_or_attach_time.reset();
218 m_first_private_stop_time.reset();
219 m_first_public_stop_time.reset();
220 // Report both the normal breakpoint list and the internal breakpoint list.
221 for (int i = 0; i < 2; ++i) {
222 BreakpointList &breakpoints = target.GetBreakpointList(internal: i == 1);
223 std::unique_lock<std::recursive_mutex> lock;
224 breakpoints.GetListMutex(lock);
225 size_t num_breakpoints = breakpoints.GetSize();
226 for (size_t i = 0; i < num_breakpoints; i++) {
227 Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
228 bp->ResetStatistics();
229 }
230 }
231 target.GetSummaryStatisticsCache().Reset();
232}
233
234void TargetStats::SetLaunchOrAttachTime() {
235 m_launch_or_attach_time = StatsClock::now();
236 m_first_private_stop_time = std::nullopt;
237}
238
239void TargetStats::SetFirstPrivateStopTime() {
240 // Launching and attaching has many paths depending on if synchronous mode
241 // was used or if we are stopping at the entry point or not. Only set the
242 // first stop time if it hasn't already been set.
243 if (!m_first_private_stop_time)
244 m_first_private_stop_time = StatsClock::now();
245}
246
247void TargetStats::SetFirstPublicStopTime() {
248 // Launching and attaching has many paths depending on if synchronous mode
249 // was used or if we are stopping at the entry point or not. Only set the
250 // first stop time if it hasn't already been set.
251 if (!m_first_public_stop_time)
252 m_first_public_stop_time = StatsClock::now();
253}
254
255void TargetStats::IncreaseSourceMapDeduceCount() {
256 ++m_source_map_deduce_count;
257}
258
259void TargetStats::IncreaseSourceRealpathAttemptCount(uint32_t count) {
260 m_source_realpath_attempt_count += count;
261}
262
263void TargetStats::IncreaseSourceRealpathCompatibleCount(uint32_t count) {
264 m_source_realpath_compatible_count += count;
265}
266
267bool DebuggerStats::g_collecting_stats = false;
268
269void DebuggerStats::ResetStatistics(Debugger &debugger, Target *target) {
270 std::lock_guard<std::recursive_mutex> guard(
271 Module::GetAllocationModuleCollectionMutex());
272 const uint64_t num_modules = target != nullptr
273 ? target->GetImages().GetSize()
274 : Module::GetNumberAllocatedModules();
275 for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
276 Module *module = target != nullptr
277 ? target->GetImages().GetModuleAtIndex(idx: image_idx).get()
278 : Module::GetAllocatedModuleAtIndex(idx: image_idx);
279 if (module == nullptr)
280 continue;
281 module->ResetStatistics();
282 }
283 if (target)
284 target->ResetStatistics();
285 else {
286 for (const auto &target : debugger.GetTargetList().Targets())
287 target->ResetStatistics();
288 }
289}
290
291llvm::json::Value DebuggerStats::ReportStatistics(
292 Debugger &debugger, Target *target,
293 const lldb_private::StatisticsOptions &options) {
294
295 const bool summary_only = options.GetSummaryOnly();
296 const bool load_all_debug_info = options.GetLoadAllDebugInfo();
297 const bool include_targets = options.GetIncludeTargets();
298 const bool include_modules = options.GetIncludeModules();
299 const bool include_transcript = options.GetIncludeTranscript();
300 const bool include_plugins = options.GetIncludePlugins();
301
302 json::Array json_targets;
303 json::Array json_modules;
304 StatisticsMap symbol_locator_total_time;
305 double symtab_parse_time = 0.0;
306 double symtab_index_time = 0.0;
307 double debug_parse_time = 0.0;
308 double debug_index_time = 0.0;
309 uint32_t symtabs_loaded = 0;
310 uint32_t symtabs_loaded_from_cache = 0;
311 uint32_t symtabs_saved_to_cache = 0;
312 uint32_t debug_index_loaded = 0;
313 uint32_t debug_index_saved = 0;
314 uint64_t debug_info_size = 0;
315
316 std::lock_guard<std::recursive_mutex> guard(
317 Module::GetAllocationModuleCollectionMutex());
318 const uint64_t num_modules = target != nullptr
319 ? target->GetImages().GetSize()
320 : Module::GetNumberAllocatedModules();
321 uint32_t num_debug_info_enabled_modules = 0;
322 uint32_t num_modules_has_debug_info = 0;
323 uint32_t num_modules_with_variable_errors = 0;
324 uint32_t num_modules_with_incomplete_types = 0;
325 uint32_t num_stripped_modules = 0;
326 uint32_t symtab_symbol_count = 0;
327 uint32_t total_loaded_dwo_file_count = 0;
328 uint32_t total_dwo_file_count = 0;
329 for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
330 Module *module = target != nullptr
331 ? target->GetImages().GetModuleAtIndex(idx: image_idx).get()
332 : Module::GetAllocatedModuleAtIndex(idx: image_idx);
333 ModuleStats module_stat;
334 module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
335 module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
336 module_stat.symbol_locator_time = module->GetSymbolLocatorStatistics();
337 symbol_locator_total_time.merge(map_to_merge: module_stat.symbol_locator_time);
338 Symtab *symtab = module->GetSymtab(/*can_create=*/false);
339 if (symtab) {
340 module_stat.symtab_symbol_count = symtab->GetNumSymbols();
341 symtab_symbol_count += module_stat.symtab_symbol_count;
342 ++symtabs_loaded;
343 module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();
344 if (module_stat.symtab_loaded_from_cache)
345 ++symtabs_loaded_from_cache;
346 module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache();
347 if (module_stat.symtab_saved_to_cache)
348 ++symtabs_saved_to_cache;
349 }
350 SymbolFile *sym_file = module->GetSymbolFile(/*can_create=*/false);
351 if (sym_file) {
352 if (!summary_only) {
353 if (sym_file->GetObjectFile() != module->GetObjectFile())
354 module_stat.symfile_path =
355 sym_file->GetObjectFile()->GetFileSpec().GetPath();
356 ModuleList symbol_modules = sym_file->GetDebugInfoModules();
357 for (const auto &symbol_module : symbol_modules.Modules())
358 module_stat.symfile_modules.push_back(x: (intptr_t)symbol_module.get());
359 }
360 std::tie(args&: module_stat.loaded_dwo_file_count, args&: module_stat.dwo_file_count) =
361 sym_file->GetDwoFileCounts();
362 total_dwo_file_count += module_stat.dwo_file_count;
363 total_loaded_dwo_file_count += module_stat.loaded_dwo_file_count;
364 module_stat.debug_info_index_loaded_from_cache =
365 sym_file->GetDebugInfoIndexWasLoadedFromCache();
366 if (module_stat.debug_info_index_loaded_from_cache)
367 ++debug_index_loaded;
368 module_stat.debug_info_index_saved_to_cache =
369 sym_file->GetDebugInfoIndexWasSavedToCache();
370 if (module_stat.debug_info_index_saved_to_cache)
371 ++debug_index_saved;
372 module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
373 module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
374 module_stat.debug_info_size =
375 sym_file->GetDebugInfoSize(load_all_debug_info);
376 module_stat.symtab_stripped = module->GetObjectFile()->IsStripped();
377 if (module_stat.symtab_stripped)
378 ++num_stripped_modules;
379 module_stat.debug_info_enabled = sym_file->GetLoadDebugInfoEnabled() &&
380 module_stat.debug_info_size > 0;
381 module_stat.debug_info_had_variable_errors =
382 sym_file->GetDebugInfoHadFrameVariableErrors();
383 if (module_stat.debug_info_enabled)
384 ++num_debug_info_enabled_modules;
385 if (module_stat.debug_info_size > 0)
386 ++num_modules_has_debug_info;
387 if (module_stat.debug_info_had_variable_errors)
388 ++num_modules_with_variable_errors;
389 }
390 symtab_parse_time += module_stat.symtab_parse_time;
391 symtab_index_time += module_stat.symtab_index_time;
392 debug_parse_time += module_stat.debug_parse_time;
393 debug_index_time += module_stat.debug_index_time;
394 debug_info_size += module_stat.debug_info_size;
395 module->ForEachTypeSystem(callback: [&](lldb::TypeSystemSP ts) {
396 if (auto stats = ts->ReportStatistics())
397 module_stat.type_system_stats.insert(KV: {ts->GetPluginName(), *stats});
398 if (ts->GetHasForcefullyCompletedTypes())
399 module_stat.debug_info_had_incomplete_types = true;
400 return true;
401 });
402 if (module_stat.debug_info_had_incomplete_types)
403 ++num_modules_with_incomplete_types;
404
405 if (include_modules) {
406 module_stat.identifier = (intptr_t)module;
407 module_stat.path = module->GetFileSpec().GetPath();
408 if (ConstString object_name = module->GetObjectName()) {
409 module_stat.path.append(n: 1, c: '(');
410 module_stat.path.append(str: object_name.GetStringRef().str());
411 module_stat.path.append(n: 1, c: ')');
412 }
413 module_stat.uuid = module->GetUUID().GetAsString();
414 module_stat.triple = module->GetArchitecture().GetTriple().str();
415 json_modules.emplace_back(A: module_stat.ToJSON());
416 }
417 }
418
419 json::Object global_stats{
420 {.K: "totalSymbolTableParseTime", .V: symtab_parse_time},
421 {.K: "totalSymbolTableIndexTime", .V: symtab_index_time},
422 {.K: "totalSymbolTablesLoaded", .V: symtabs_loaded},
423 {.K: "totalSymbolTablesLoadedFromCache", .V: symtabs_loaded_from_cache},
424 {.K: "totalSymbolTablesSavedToCache", .V: symtabs_saved_to_cache},
425 {.K: "totalDebugInfoParseTime", .V: debug_parse_time},
426 {.K: "totalDebugInfoIndexTime", .V: debug_index_time},
427 {.K: "totalDebugInfoIndexLoadedFromCache", .V: debug_index_loaded},
428 {.K: "totalDebugInfoIndexSavedToCache", .V: debug_index_saved},
429 {.K: "totalDebugInfoByteSize", .V: debug_info_size},
430 {.K: "totalModuleCount", .V: num_modules},
431 {.K: "totalModuleCountHasDebugInfo", .V: num_modules_has_debug_info},
432 {.K: "totalModuleCountWithVariableErrors", .V: num_modules_with_variable_errors},
433 {.K: "totalModuleCountWithIncompleteTypes",
434 .V: num_modules_with_incomplete_types},
435 {.K: "totalDebugInfoEnabled", .V: num_debug_info_enabled_modules},
436 {.K: "totalSymbolTableStripped", .V: num_stripped_modules},
437 {.K: "totalSymbolTableSymbolCount", .V: symtab_symbol_count},
438 {.K: "totalLoadedDwoFileCount", .V: total_loaded_dwo_file_count},
439 {.K: "totalDwoFileCount", .V: total_dwo_file_count},
440 };
441
442 if (include_targets) {
443 if (target) {
444 json_targets.emplace_back(A: target->ReportStatistics(options));
445 } else {
446 for (const auto &target : debugger.GetTargetList().Targets())
447 json_targets.emplace_back(A: target->ReportStatistics(options));
448 }
449 global_stats.try_emplace(K: "targets", Args: std::move(json_targets));
450 }
451
452 if (!symbol_locator_total_time.map.empty()) {
453 json::Object obj;
454 for (const auto &entry : symbol_locator_total_time.map)
455 obj.try_emplace(K: entry.first().str(), Args: entry.second);
456 global_stats.try_emplace(K: "totalSymbolLocatorTime", Args: std::move(obj));
457 }
458
459 ConstStringStats const_string_stats;
460 json::Object json_memory{
461 {.K: "strings", .V: const_string_stats.ToJSON()},
462 };
463 global_stats.try_emplace(K: "memory", Args: std::move(json_memory));
464 if (!summary_only) {
465 json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();
466 global_stats.try_emplace(K: "commands", Args: std::move(cmd_stats));
467 }
468
469 if (include_modules) {
470 global_stats.try_emplace(K: "modules", Args: std::move(json_modules));
471 }
472
473 if (include_transcript) {
474 // When transcript is available, add it to the to-be-returned statistics.
475 //
476 // NOTE:
477 // When the statistics is polled by an LLDB command:
478 // - The transcript in the returned statistics *will NOT* contain the
479 // returned statistics itself (otherwise infinite recursion).
480 // - The returned statistics *will* be written to the internal transcript
481 // buffer. It *will* appear in the next statistcs or transcript poll.
482 //
483 // For example, let's say the following commands are run in order:
484 // - "version"
485 // - "statistics dump" <- call it "A"
486 // - "statistics dump" <- call it "B"
487 // The output of "A" will contain the transcript of "version" and
488 // "statistics dump" (A), with the latter having empty output. The output
489 // of B will contain the trascnript of "version", "statistics dump" (A),
490 // "statistics dump" (B), with A's output populated and B's output empty.
491 const StructuredData::Array &transcript =
492 debugger.GetCommandInterpreter().GetTranscript();
493 if (transcript.GetSize() != 0) {
494 std::string buffer;
495 llvm::raw_string_ostream ss(buffer);
496 json::OStream json_os(ss);
497 transcript.Serialize(s&: json_os);
498 if (auto json_transcript = llvm::json::parse(JSON: buffer))
499 global_stats.try_emplace(K: "transcript",
500 Args: std::move(json_transcript.get()));
501 }
502 }
503
504 if (include_plugins) {
505 global_stats.try_emplace(K: "plugins", Args: PluginManager::GetJSON());
506 }
507
508 return std::move(global_stats);
509}
510
511llvm::json::Value SummaryStatistics::ToJSON() const {
512 return json::Object{{
513 {.K: "name", .V: GetName()},
514 {.K: "type", .V: GetSummaryKindName()},
515 {.K: "count", .V: GetSummaryCount()},
516 {.K: "totalTime", .V: GetTotalTime()},
517 }};
518}
519
520json::Value SummaryStatisticsCache::ToJSON() {
521 std::lock_guard<std::mutex> guard(m_map_mutex);
522 json::Array json_summary_stats;
523 for (const auto &summary_stat : m_summary_stats_map)
524 json_summary_stats.emplace_back(A: summary_stat.second->ToJSON());
525
526 return json_summary_stats;
527}
528
529void SummaryStatisticsCache::Reset() {
530 for (const auto &summary_stat : m_summary_stats_map)
531 summary_stat.second->Reset();
532}
533

source code of lldb/source/Target/Statistics.cpp