Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Target/Statistics.cpp
39587 views
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/Interpreter/CommandInterpreter.h"
14
#include "lldb/Symbol/SymbolFile.h"
15
#include "lldb/Target/DynamicLoader.h"
16
#include "lldb/Target/Process.h"
17
#include "lldb/Target/Target.h"
18
#include "lldb/Target/UnixSignals.h"
19
#include "lldb/Utility/StructuredData.h"
20
21
using namespace lldb;
22
using namespace lldb_private;
23
using namespace llvm;
24
25
static 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
35
json::Value StatsSuccessFail::ToJSON() const {
36
return json::Object{{"successes", successes}, {"failures", failures}};
37
}
38
39
static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) {
40
StatsDuration::Duration elapsed =
41
end.time_since_epoch() - start.time_since_epoch();
42
return elapsed.count();
43
}
44
45
void TargetStats::CollectStats(Target &target) {
46
m_module_identifiers.clear();
47
for (ModuleSP module_sp : target.GetImages().Modules())
48
m_module_identifiers.emplace_back((intptr_t)module_sp.get());
49
}
50
51
json::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",
65
debug_info_index_loaded_from_cache);
66
module.try_emplace("debugInfoIndexSavedToCache",
67
debug_info_index_saved_to_cache);
68
module.try_emplace("debugInfoEnabled", debug_info_enabled);
69
module.try_emplace("debugInfoHadVariableErrors",
70
debug_info_had_variable_errors);
71
module.try_emplace("debugInfoHadIncompleteTypes",
72
debug_info_had_incomplete_types);
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
97
llvm::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
105
json::Value
106
TargetStats::ToJSON(Target &target,
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
125
if (m_launch_or_attach_time && m_first_private_stop_time) {
126
double elapsed_time =
127
elapsed(*m_launch_or_attach_time, *m_first_private_stop_time);
128
target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);
129
}
130
if (m_launch_or_attach_time && m_first_public_stop_time) {
131
double elapsed_time =
132
elapsed(*m_launch_or_attach_time, *m_first_public_stop_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",
194
m_source_map_deduce_count);
195
return target_metrics_json;
196
}
197
198
void TargetStats::SetLaunchOrAttachTime() {
199
m_launch_or_attach_time = StatsClock::now();
200
m_first_private_stop_time = std::nullopt;
201
}
202
203
void TargetStats::SetFirstPrivateStopTime() {
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.
207
if (!m_first_private_stop_time)
208
m_first_private_stop_time = StatsClock::now();
209
}
210
211
void TargetStats::SetFirstPublicStopTime() {
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.
215
if (!m_first_public_stop_time)
216
m_first_public_stop_time = StatsClock::now();
217
}
218
219
void TargetStats::IncreaseSourceMapDeduceCount() {
220
++m_source_map_deduce_count;
221
}
222
223
bool DebuggerStats::g_collecting_stats = false;
224
225
llvm::json::Value DebuggerStats::ReportStatistics(
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(
249
Module::GetAllocationModuleCollectionMutex());
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
}
280
module_stat.debug_info_index_loaded_from_cache =
281
sym_file->GetDebugInfoIndexWasLoadedFromCache();
282
if (module_stat.debug_info_index_loaded_from_cache)
283
++debug_index_loaded;
284
module_stat.debug_info_index_saved_to_cache =
285
sym_file->GetDebugInfoIndexWasSavedToCache();
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;
297
module_stat.debug_info_had_variable_errors =
298
sym_file->GetDebugInfoHadFrameVariableErrors();
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 =
397
debugger.GetCommandInterpreter().GetTranscript();
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
}
411
412