LLDB mainline
Statistics.cpp
Go to the documentation of this file.
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
10
11#include "lldb/Core/Debugger.h"
12#include "lldb/Core/Module.h"
16#include "lldb/Target/Process.h"
17#include "lldb/Target/Target.h"
20
21using namespace lldb;
22using namespace lldb_private;
23using namespace llvm;
24
25static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
26 const std::string &str) {
27 if (str.empty())
28 return;
29 if (LLVM_LIKELY(llvm::json::isUTF8(str)))
30 obj.try_emplace(key, str);
31 else
32 obj.try_emplace(key, llvm::json::fixUTF8(str));
33}
34
35json::Value StatsSuccessFail::ToJSON() const {
36 return json::Object{{"successes", successes}, {"failures", failures}};
37}
38
39static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) {
41 end.time_since_epoch() - start.time_since_epoch();
42 return elapsed.count();
43}
44
47 for (ModuleSP module_sp : target.GetImages().Modules())
48 m_module_identifiers.emplace_back((intptr_t)module_sp.get());
49}
50
51json::Value ModuleStats::ToJSON() const {
52 json::Object module;
53 EmplaceSafeString(module, "path", path);
54 EmplaceSafeString(module, "uuid", uuid);
55 EmplaceSafeString(module, "triple", triple);
56 module.try_emplace("identifier", identifier);
57 module.try_emplace("symbolTableParseTime", symtab_parse_time);
58 module.try_emplace("symbolTableIndexTime", symtab_index_time);
59 module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache);
60 module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache);
61 module.try_emplace("debugInfoParseTime", debug_parse_time);
62 module.try_emplace("debugInfoIndexTime", debug_index_time);
63 module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size);
64 module.try_emplace("debugInfoIndexLoadedFromCache",
66 module.try_emplace("debugInfoIndexSavedToCache",
68 module.try_emplace("debugInfoEnabled", debug_info_enabled);
69 module.try_emplace("debugInfoHadVariableErrors",
71 module.try_emplace("debugInfoHadIncompleteTypes",
73 module.try_emplace("symbolTableStripped", symtab_stripped);
74 if (!symfile_path.empty())
75 module.try_emplace("symbolFilePath", symfile_path);
76
77 if (!symfile_modules.empty()) {
78 json::Array symfile_ids;
79 for (const auto symfile_id: symfile_modules)
80 symfile_ids.emplace_back(symfile_id);
81 module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids));
82 }
83
84 if (!type_system_stats.empty()) {
85 json::Array type_systems;
86 for (const auto &entry : type_system_stats) {
87 json::Object obj;
88 obj.try_emplace(entry.first().str(), entry.second);
89 type_systems.emplace_back(std::move(obj));
90 }
91 module.try_emplace("typeSystemInfo", std::move(type_systems));
92 }
93
94 return module;
95}
96
97llvm::json::Value ConstStringStats::ToJSON() const {
98 json::Object obj;
99 obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal());
100 obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed());
101 obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused());
102 return obj;
103}
104
105json::Value
107 const lldb_private::StatisticsOptions &options) {
108 json::Object target_metrics_json;
109 ProcessSP process_sp = target.GetProcessSP();
110 const bool summary_only = options.GetSummaryOnly();
111 const bool include_modules = options.GetIncludeModules();
112 if (!summary_only) {
113 CollectStats(target);
114
115 json::Array json_module_uuid_array;
116 for (auto module_identifier : m_module_identifiers)
117 json_module_uuid_array.emplace_back(module_identifier);
118
119 target_metrics_json.try_emplace(m_expr_eval.name, m_expr_eval.ToJSON());
120 target_metrics_json.try_emplace(m_frame_var.name, m_frame_var.ToJSON());
121 if (include_modules)
122 target_metrics_json.try_emplace("moduleIdentifiers",
123 std::move(json_module_uuid_array));
124
126 double elapsed_time =
128 target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);
129 }
131 double elapsed_time =
133 target_metrics_json.try_emplace("firstStopTime", elapsed_time);
134 }
135 target_metrics_json.try_emplace("targetCreateTime",
136 m_create_time.get().count());
137
138 json::Array breakpoints_array;
139 double totalBreakpointResolveTime = 0.0;
140 // Report both the normal breakpoint list and the internal breakpoint list.
141 for (int i = 0; i < 2; ++i) {
142 BreakpointList &breakpoints = target.GetBreakpointList(i == 1);
143 std::unique_lock<std::recursive_mutex> lock;
144 breakpoints.GetListMutex(lock);
145 size_t num_breakpoints = breakpoints.GetSize();
146 for (size_t i = 0; i < num_breakpoints; i++) {
147 Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
148 breakpoints_array.push_back(bp->GetStatistics());
149 totalBreakpointResolveTime += bp->GetResolveTime().count();
150 }
151 }
152 target_metrics_json.try_emplace("breakpoints",
153 std::move(breakpoints_array));
154 target_metrics_json.try_emplace("totalBreakpointResolveTime",
155 totalBreakpointResolveTime);
156
157 if (process_sp) {
158 UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();
159 if (unix_signals_sp)
160 target_metrics_json.try_emplace(
161 "signals", unix_signals_sp->GetHitCountStatistics());
162 }
163 }
164
165 // Counting "totalSharedLibraryEventHitCount" from breakpoints of kind
166 // "shared-library-event".
167 {
168 uint32_t shared_library_event_breakpoint_hit_count = 0;
169 // The "shared-library-event" is only found in the internal breakpoint list.
170 BreakpointList &breakpoints = target.GetBreakpointList(/* internal */ true);
171 std::unique_lock<std::recursive_mutex> lock;
172 breakpoints.GetListMutex(lock);
173 size_t num_breakpoints = breakpoints.GetSize();
174 for (size_t i = 0; i < num_breakpoints; i++) {
175 Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
176 if (strcmp(bp->GetBreakpointKind(), "shared-library-event") == 0)
177 shared_library_event_breakpoint_hit_count += bp->GetHitCount();
178 }
179
180 target_metrics_json.try_emplace("totalSharedLibraryEventHitCount",
181 shared_library_event_breakpoint_hit_count);
182 }
183
184 if (process_sp) {
185 uint32_t stop_id = process_sp->GetStopID();
186 target_metrics_json.try_emplace("stopCount", stop_id);
187
188 llvm::StringRef dyld_plugin_name;
189 if (process_sp->GetDynamicLoader())
190 dyld_plugin_name = process_sp->GetDynamicLoader()->GetPluginName();
191 target_metrics_json.try_emplace("dyldPluginName", dyld_plugin_name);
192 }
193 target_metrics_json.try_emplace("sourceMapDeduceCount",
195 return target_metrics_json;
196}
197
199 m_launch_or_attach_time = StatsClock::now();
200 m_first_private_stop_time = std::nullopt;
201}
202
204 // Launching and attaching has many paths depending on if synchronous mode
205 // was used or if we are stopping at the entry point or not. Only set the
206 // first stop time if it hasn't already been set.
208 m_first_private_stop_time = StatsClock::now();
209}
210
212 // Launching and attaching has many paths depending on if synchronous mode
213 // was used or if we are stopping at the entry point or not. Only set the
214 // first stop time if it hasn't already been set.
216 m_first_public_stop_time = StatsClock::now();
217}
218
221}
222
224
226 Debugger &debugger, Target *target,
227 const lldb_private::StatisticsOptions &options) {
228
229 const bool summary_only = options.GetSummaryOnly();
230 const bool load_all_debug_info = options.GetLoadAllDebugInfo();
231 const bool include_targets = options.GetIncludeTargets();
232 const bool include_modules = options.GetIncludeModules();
233 const bool include_transcript = options.GetIncludeTranscript();
234
235 json::Array json_targets;
236 json::Array json_modules;
237 double symtab_parse_time = 0.0;
238 double symtab_index_time = 0.0;
239 double debug_parse_time = 0.0;
240 double debug_index_time = 0.0;
241 uint32_t symtabs_loaded = 0;
242 uint32_t symtabs_saved = 0;
243 uint32_t debug_index_loaded = 0;
244 uint32_t debug_index_saved = 0;
245 uint64_t debug_info_size = 0;
246
247 std::vector<ModuleStats> modules;
248 std::lock_guard<std::recursive_mutex> guard(
250 const uint64_t num_modules = Module::GetNumberAllocatedModules();
251 uint32_t num_debug_info_enabled_modules = 0;
252 uint32_t num_modules_has_debug_info = 0;
253 uint32_t num_modules_with_variable_errors = 0;
254 uint32_t num_modules_with_incomplete_types = 0;
255 uint32_t num_stripped_modules = 0;
256 for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
257 Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
258 ModuleStats module_stat;
259 module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
260 module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
261 Symtab *symtab = module->GetSymtab();
262 if (symtab) {
263 module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();
264 if (module_stat.symtab_loaded_from_cache)
265 ++symtabs_loaded;
266 module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache();
267 if (module_stat.symtab_saved_to_cache)
268 ++symtabs_saved;
269 }
270 SymbolFile *sym_file = module->GetSymbolFile();
271 if (sym_file) {
272 if (!summary_only) {
273 if (sym_file->GetObjectFile() != module->GetObjectFile())
274 module_stat.symfile_path =
275 sym_file->GetObjectFile()->GetFileSpec().GetPath();
276 ModuleList symbol_modules = sym_file->GetDebugInfoModules();
277 for (const auto &symbol_module : symbol_modules.Modules())
278 module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());
279 }
283 ++debug_index_loaded;
286 if (module_stat.debug_info_index_saved_to_cache)
287 ++debug_index_saved;
288 module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
289 module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
290 module_stat.debug_info_size =
291 sym_file->GetDebugInfoSize(load_all_debug_info);
292 module_stat.symtab_stripped = module->GetObjectFile()->IsStripped();
293 if (module_stat.symtab_stripped)
294 ++num_stripped_modules;
295 module_stat.debug_info_enabled = sym_file->GetLoadDebugInfoEnabled() &&
296 module_stat.debug_info_size > 0;
299 if (module_stat.debug_info_enabled)
300 ++num_debug_info_enabled_modules;
301 if (module_stat.debug_info_size > 0)
302 ++num_modules_has_debug_info;
303 if (module_stat.debug_info_had_variable_errors)
304 ++num_modules_with_variable_errors;
305 }
306 symtab_parse_time += module_stat.symtab_parse_time;
307 symtab_index_time += module_stat.symtab_index_time;
308 debug_parse_time += module_stat.debug_parse_time;
309 debug_index_time += module_stat.debug_index_time;
310 debug_info_size += module_stat.debug_info_size;
311 module->ForEachTypeSystem([&](lldb::TypeSystemSP ts) {
312 if (auto stats = ts->ReportStatistics())
313 module_stat.type_system_stats.insert({ts->GetPluginName(), *stats});
314 if (ts->GetHasForcefullyCompletedTypes())
315 module_stat.debug_info_had_incomplete_types = true;
316 return true;
317 });
318 if (module_stat.debug_info_had_incomplete_types)
319 ++num_modules_with_incomplete_types;
320
321 if (include_modules) {
322 module_stat.identifier = (intptr_t)module;
323 module_stat.path = module->GetFileSpec().GetPath();
324 if (ConstString object_name = module->GetObjectName()) {
325 module_stat.path.append(1, '(');
326 module_stat.path.append(object_name.GetStringRef().str());
327 module_stat.path.append(1, ')');
328 }
329 module_stat.uuid = module->GetUUID().GetAsString();
330 module_stat.triple = module->GetArchitecture().GetTriple().str();
331 json_modules.emplace_back(module_stat.ToJSON());
332 }
333 }
334
335 json::Object global_stats{
336 {"totalSymbolTableParseTime", symtab_parse_time},
337 {"totalSymbolTableIndexTime", symtab_index_time},
338 {"totalSymbolTablesLoadedFromCache", symtabs_loaded},
339 {"totalSymbolTablesSavedToCache", symtabs_saved},
340 {"totalDebugInfoParseTime", debug_parse_time},
341 {"totalDebugInfoIndexTime", debug_index_time},
342 {"totalDebugInfoIndexLoadedFromCache", debug_index_loaded},
343 {"totalDebugInfoIndexSavedToCache", debug_index_saved},
344 {"totalDebugInfoByteSize", debug_info_size},
345 {"totalModuleCount", num_modules},
346 {"totalModuleCountHasDebugInfo", num_modules_has_debug_info},
347 {"totalModuleCountWithVariableErrors", num_modules_with_variable_errors},
348 {"totalModuleCountWithIncompleteTypes",
349 num_modules_with_incomplete_types},
350 {"totalDebugInfoEnabled", num_debug_info_enabled_modules},
351 {"totalSymbolTableStripped", num_stripped_modules},
352 };
353
354 if (include_targets) {
355 if (target) {
356 json_targets.emplace_back(target->ReportStatistics(options));
357 } else {
358 for (const auto &target : debugger.GetTargetList().Targets())
359 json_targets.emplace_back(target->ReportStatistics(options));
360 }
361 global_stats.try_emplace("targets", std::move(json_targets));
362 }
363
364 ConstStringStats const_string_stats;
365 json::Object json_memory{
366 {"strings", const_string_stats.ToJSON()},
367 };
368 global_stats.try_emplace("memory", std::move(json_memory));
369 if (!summary_only) {
370 json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();
371 global_stats.try_emplace("commands", std::move(cmd_stats));
372 }
373
374 if (include_modules) {
375 global_stats.try_emplace("modules", std::move(json_modules));
376 }
377
378 if (include_transcript) {
379 // When transcript is available, add it to the to-be-returned statistics.
380 //
381 // NOTE:
382 // When the statistics is polled by an LLDB command:
383 // - The transcript in the returned statistics *will NOT* contain the
384 // returned statistics itself (otherwise infinite recursion).
385 // - The returned statistics *will* be written to the internal transcript
386 // buffer. It *will* appear in the next statistcs or transcript poll.
387 //
388 // For example, let's say the following commands are run in order:
389 // - "version"
390 // - "statistics dump" <- call it "A"
391 // - "statistics dump" <- call it "B"
392 // The output of "A" will contain the transcript of "version" and
393 // "statistics dump" (A), with the latter having empty output. The output
394 // of B will contain the trascnript of "version", "statistics dump" (A),
395 // "statistics dump" (B), with A's output populated and B's output empty.
396 const StructuredData::Array &transcript =
398 if (transcript.GetSize() != 0) {
399 std::string buffer;
400 llvm::raw_string_ostream ss(buffer);
401 json::OStream json_os(ss);
402 transcript.Serialize(json_os);
403 if (auto json_transcript = llvm::json::parse(ss.str()))
404 global_stats.try_emplace("transcript",
405 std::move(json_transcript.get()));
406 }
407 }
408
409 return std::move(global_stats);
410}
static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end)
Definition: Statistics.cpp:39
static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, const std::string &str)
Definition: Statistics.cpp:25
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:450
General Outline: Allows adding and removing breakpoints and find by ID and index.
void GetListMutex(std::unique_lock< std::recursive_mutex > &lock)
Sets the passed in Locker to hold the Breakpoint List mutex.
size_t GetSize() const
Returns the number of elements in this breakpoint list.
lldb::BreakpointSP GetBreakpointAtIndex(size_t i) const
Returns a shared pointer to the breakpoint with index i.
General Outline: A breakpoint has four main parts, a filter, a resolver, the list of breakpoint locat...
Definition: Breakpoint.h:81
llvm::json::Value GetStatistics()
Get statistics associated with this breakpoint in JSON format.
const char * GetBreakpointKind() const
Return the "kind" description for a breakpoint.
Definition: Breakpoint.h:458
uint32_t GetHitCount() const
Return the current hit count for all locations.
Definition: Breakpoint.cpp:319
StatsDuration::Duration GetResolveTime() const
Get the time it took to resolve all locations in this breakpoint.
Definition: Breakpoint.h:592
const StructuredData::Array & GetTranscript() const
A uniqued constant string class.
Definition: ConstString.h:40
static bool g_collecting_stats
Definition: Statistics.h:234
static llvm::json::Value ReportStatistics(Debugger &debugger, Target *target, const lldb_private::StatisticsOptions &options)
Get metrics associated with one or all targets in a debugger in JSON format.
Definition: Statistics.cpp:225
A class to manage flag bits.
Definition: Debugger.h:80
CommandInterpreter & GetCommandInterpreter()
Definition: Debugger.h:168
TargetList & GetTargetList()
Get accessor for the target list.
Definition: Debugger.h:198
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:367
A collection class for Module objects.
Definition: ModuleList.h:103
ModuleIterable Modules() const
Definition: ModuleList.h:527
A class that describes an executable image and its associated object and symbol files.
Definition: Module.h:88
const lldb_private::UUID & GetUUID()
Get a reference to the UUID value contained in this object.
Definition: Module.cpp:340
virtual ObjectFile * GetObjectFile()
Get the object file representation for the current architecture.
Definition: Module.cpp:1184
virtual SymbolFile * GetSymbolFile(bool can_create=true, Stream *feedback_strm=nullptr)
Get the module's symbol file.
Definition: Module.cpp:992
ConstString GetObjectName() const
Definition: Module.cpp:1182
static Module * GetAllocatedModuleAtIndex(size_t idx)
Definition: Module.cpp:124
static std::recursive_mutex & GetAllocationModuleCollectionMutex()
Definition: Module.cpp:106
Symtab * GetSymtab()
Definition: Module.cpp:1020
static size_t GetNumberAllocatedModules()
Definition: Module.cpp:118
void ForEachTypeSystem(llvm::function_ref< bool(lldb::TypeSystemSP)> callback)
Call callback for each TypeSystem in this Module.
Definition: Module.cpp:370
const ArchSpec & GetArchitecture() const
Get const accessor for the module architecture.
Definition: Module.cpp:1035
StatsDuration & GetSymtabIndexTime()
Accessor for the symbol table index time metric.
Definition: Module.h:881
const FileSpec & GetFileSpec() const
Get const accessor for the module file specification.
Definition: Module.h:452
StatsDuration & GetSymtabParseTime()
Accessor for the symbol table parse time metric.
Definition: Module.h:875
virtual bool IsStripped()=0
Detect if this object file has been stripped of local symbols.
virtual FileSpec & GetFileSpec()
Get accessor to the object file specification.
Definition: ObjectFile.h:275
Duration get() const
Definition: Statistics.h:33
std::chrono::duration< double > Duration
Definition: Statistics.h:31
void Serialize(llvm::json::OStream &s) const override
Provides public interface for all SymbolFiles.
Definition: SymbolFile.h:50
virtual uint64_t GetDebugInfoSize(bool load_all_debug_info=false)=0
Metrics gathering functions.
virtual bool GetDebugInfoIndexWasLoadedFromCache() const =0
Accessors for the bool that indicates if the debug info index was loaded from, or saved to the module...
virtual bool GetDebugInfoIndexWasSavedToCache() const =0
virtual StatsDuration::Duration GetDebugInfoParseTime()
Return the time taken to parse the debug information.
Definition: SymbolFile.h:408
virtual bool GetLoadDebugInfoEnabled()
Whether debug info will be loaded or not.
Definition: SymbolFile.h:135
virtual bool GetDebugInfoHadFrameVariableErrors() const =0
Accessors for the bool that indicates if there was debug info, but errors stopped variables from bein...
virtual ModuleList GetDebugInfoModules()
Get the additional modules that this symbol file uses to parse debug info.
Definition: SymbolFile.h:424
virtual StatsDuration::Duration GetDebugInfoIndexTime()
Return the time it took to index the debug information in the object file.
Definition: SymbolFile.h:415
virtual ObjectFile * GetObjectFile()=0
bool GetWasLoadedFromCache() const
Accessors for the bool that indicates if the debug info index was loaded from, or saved to the module...
Definition: Symtab.h:228
bool GetWasSavedToCache() const
Definition: Symtab.h:234
TargetIterable Targets()
Definition: TargetList.h:194
StatsSuccessFail m_frame_var
Definition: Statistics.h:198
std::optional< StatsTimepoint > m_launch_or_attach_time
Definition: Statistics.h:194
uint32_t m_source_map_deduce_count
Definition: Statistics.h:200
void CollectStats(Target &target)
Definition: Statistics.cpp:45
llvm::json::Value ToJSON(Target &target, const lldb_private::StatisticsOptions &options)
Definition: Statistics.cpp:106
StatsDuration m_create_time
Definition: Statistics.h:193
std::optional< StatsTimepoint > m_first_public_stop_time
Definition: Statistics.h:196
StatsSuccessFail m_expr_eval
Definition: Statistics.h:197
std::vector< intptr_t > m_module_identifiers
Definition: Statistics.h:199
std::optional< StatsTimepoint > m_first_private_stop_time
Definition: Statistics.h:195
BreakpointList & GetBreakpointList(bool internal=false)
Definition: Target.cpp:314
const lldb::ProcessSP & GetProcessSP() const
Definition: Target.cpp:221
llvm::json::Value ReportStatistics(const lldb_private::StatisticsOptions &options)
Get metrics associated with this target in JSON format.
Definition: Target.cpp:4947
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition: Target.h:981
std::string GetAsString(llvm::StringRef separator="-") const
Definition: UUID.cpp:49
A class that represents a running process on the host machine.
std::chrono::time_point< StatsClock > StatsTimepoint
Definition: Statistics.h:27
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::TypeSystem > TypeSystemSP
Definition: lldb-forward.h:464
std::shared_ptr< lldb_private::UnixSignals > UnixSignalsSP
Definition: lldb-forward.h:475
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:386
std::shared_ptr< lldb_private::Module > ModuleSP
Definition: lldb-forward.h:370
Definition: Debugger.h:54
ConstString::MemoryStats stats
Definition: Statistics.h:130
llvm::json::Value ToJSON() const
Definition: Statistics.cpp:97
A class that represents statistics for a since lldb_private::Module.
Definition: Statistics.h:99
llvm::json::Value ToJSON() const
Definition: Statistics.cpp:51
llvm::StringMap< llvm::json::Value > type_system_stats
Definition: Statistics.h:112
std::vector< intptr_t > symfile_modules
Definition: Statistics.h:111
llvm::json::Value ToJSON() const
Definition: Statistics.cpp:35