Skip to content

Commit 24feaab

Browse files
jeffreytan81jeffreytan81
andauthored
Fix statistics dump to report per-target (#113723)
"statistics dump" currently report the statistics of all targets in debugger instead of current target. This is wrong because there is a "statistics dump --all-targets" option that supposed to include everything. This PR fixes the issue by only report statistics for current target instead of all. It also includes the change to reset statistics debug info/symbol table parsing/indexing time during debugger destroy. This is required so that we report current statistics if we plan to reuse lldb/lldb-dap across debug sessions --------- Co-authored-by: jeffreytan81 <[email protected]>
1 parent d9eda6b commit 24feaab

File tree

20 files changed

+173
-4
lines changed

20 files changed

+173
-4
lines changed

lldb/include/lldb/API/SBDebugger.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,11 @@ class LLDB_API SBDebugger {
426426

427427
SBTypeSynthetic GetSyntheticForType(SBTypeNameSpecifier);
428428

429+
/// Clear collected statistics for targets belonging to this debugger. This
430+
/// includes clearing symbol table and debug info parsing/index time for all
431+
/// modules, breakpoint resolve time and target statistics.
432+
void ResetStatistics();
433+
429434
#ifndef SWIG
430435
/// Run the command interpreter.
431436
///

lldb/include/lldb/API/SBTarget.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ class LLDB_API SBTarget {
101101
/// A SBStructuredData with the statistics collected.
102102
lldb::SBStructuredData GetStatistics(SBStatisticsOptions options);
103103

104+
/// Reset the statistics collected for this target.
105+
/// This includes clearing symbol table and debug info parsing/index time for
106+
/// all modules, breakpoint resolve time and target statistics.
107+
void ResetStatistics();
108+
104109
/// Return the platform object associated with the target.
105110
///
106111
/// After return, the platform object should be checked for

lldb/include/lldb/Breakpoint/Breakpoint.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
588588
/// Get statistics associated with this breakpoint in JSON format.
589589
llvm::json::Value GetStatistics();
590590

591+
void ResetStatistics();
592+
591593
/// Get the time it took to resolve all locations in this breakpoint.
592594
StatsDuration::Duration GetResolveTime() const { return m_resolve_time; }
593595

lldb/include/lldb/Core/Module.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,8 @@ class Module : public std::enable_shared_from_this<Module>,
881881
/// ElapsedTime RAII object.
882882
StatsDuration &GetSymtabIndexTime() { return m_symtab_index_time; }
883883

884+
void ResetStatistics();
885+
884886
/// \class LookupInfo Module.h "lldb/Core/Module.h"
885887
/// A class that encapsulates name lookup information.
886888
///

lldb/include/lldb/Symbol/SymbolFile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,9 @@ class SymbolFile : public PluginInterface {
422422
/// hasn't been indexed yet, or a valid duration if it has.
423423
virtual StatsDuration::Duration GetDebugInfoIndexTime() { return {}; }
424424

425+
/// Reset the statistics for the symbol file.
426+
virtual void ResetStatistics() {}
427+
425428
/// Get the additional modules that this symbol file uses to parse debug info.
426429
///
427430
/// Some debug info is stored in stand alone object files that are represented

lldb/include/lldb/Symbol/SymbolFileOnDemand.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ class SymbolFileOnDemand : public lldb_private::SymbolFile {
182182
lldb_private::StatsDuration::Duration GetDebugInfoParseTime() override;
183183
lldb_private::StatsDuration::Duration GetDebugInfoIndexTime() override;
184184

185+
void ResetStatistics() override;
186+
185187
uint32_t GetAbilities() override;
186188

187189
Symtab *GetSymtab() override { return m_sym_file_impl->GetSymtab(); }

lldb/include/lldb/Target/Statistics.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class StatsDuration {
4141
}
4242
operator Duration() const { return get(); }
4343

44+
void reset() { value.store(0, std::memory_order_relaxed); }
45+
4446
StatsDuration &operator+=(Duration dur) {
4547
value.fetch_add(std::chrono::duration_cast<InternalDuration>(dur).count(),
4648
std::memory_order_relaxed);
@@ -201,6 +203,8 @@ class SummaryStatistics {
201203

202204
llvm::json::Value ToJSON() const;
203205

206+
void Reset() { m_total_time.reset(); }
207+
204208
/// Basic RAII class to increment the summary count when the call is complete.
205209
class SummaryInvocation {
206210
public:
@@ -250,6 +254,8 @@ class SummaryStatisticsCache {
250254

251255
llvm::json::Value ToJSON();
252256

257+
void Reset();
258+
253259
private:
254260
llvm::StringMap<SummaryStatisticsSP> m_summary_stats_map;
255261
std::mutex m_map_mutex;
@@ -271,6 +277,7 @@ class TargetStats {
271277
StatsDuration &GetCreateTime() { return m_create_time; }
272278
StatsSuccessFail &GetExpressionStats() { return m_expr_eval; }
273279
StatsSuccessFail &GetFrameVariableStats() { return m_frame_var; }
280+
void Reset(Target &target);
274281

275282
protected:
276283
StatsDuration m_create_time;
@@ -311,6 +318,16 @@ class DebuggerStats {
311318
ReportStatistics(Debugger &debugger, Target *target,
312319
const lldb_private::StatisticsOptions &options);
313320

321+
/// Reset metrics associated with one or all targets in a debugger.
322+
///
323+
/// \param debugger
324+
/// The debugger to reset the target list from if \a target is NULL.
325+
///
326+
/// \param target
327+
/// The target to reset statistics for, or if null, reset statistics
328+
/// for all targets
329+
static void ResetStatistics(Debugger &debugger, Target *target);
330+
314331
protected:
315332
// Collecting stats can be set to true to collect stats that are expensive
316333
// to collect. By default all stats that are cheap to collect are enabled.

lldb/include/lldb/Target/Target.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,6 +1635,8 @@ class Target : public std::enable_shared_from_this<Target>,
16351635
llvm::json::Value
16361636
ReportStatistics(const lldb_private::StatisticsOptions &options);
16371637

1638+
void ResetStatistics();
1639+
16381640
TargetStats &GetStatistics() { return m_stats; }
16391641

16401642
protected:

lldb/source/API/SBDebugger.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,12 @@ SBTypeSynthetic SBDebugger::GetSyntheticForType(SBTypeNameSpecifier type_name) {
16671667
DataVisualization::GetSyntheticForType(type_name.GetSP()));
16681668
}
16691669

1670+
void SBDebugger::ResetStatistics() {
1671+
LLDB_INSTRUMENT_VA(this);
1672+
if (m_opaque_sp)
1673+
DebuggerStats::ResetStatistics(*m_opaque_sp, nullptr);
1674+
}
1675+
16701676
static llvm::ArrayRef<const char *> GetCategoryArray(const char **categories) {
16711677
if (categories == nullptr)
16721678
return {};

lldb/source/API/SBTarget.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ SBStructuredData SBTarget::GetStatistics(SBStatisticsOptions options) {
220220
return data;
221221
}
222222

223+
void SBTarget::ResetStatistics() {
224+
LLDB_INSTRUMENT_VA(this);
225+
TargetSP target_sp(GetSP());
226+
if (target_sp)
227+
DebuggerStats::ResetStatistics(target_sp->GetDebugger(), target_sp.get());
228+
}
229+
223230
void SBTarget::SetCollectingStats(bool v) {
224231
LLDB_INSTRUMENT_VA(this, v);
225232

lldb/source/Breakpoint/Breakpoint.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,3 +1138,5 @@ json::Value Breakpoint::GetStatistics() {
11381138
}
11391139
return json::Value(std::move(bp));
11401140
}
1141+
1142+
void Breakpoint::ResetStatistics() { m_resolve_time.reset(); }

lldb/source/Core/Module.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,6 +1609,14 @@ bool Module::MergeArchitecture(const ArchSpec &arch_spec) {
16091609
return SetArchitecture(merged_arch);
16101610
}
16111611

1612+
void Module::ResetStatistics() {
1613+
m_symtab_parse_time.reset();
1614+
m_symtab_index_time.reset();
1615+
SymbolFile *sym_file = GetSymbolFile();
1616+
if (sym_file)
1617+
sym_file->ResetStatistics();
1618+
}
1619+
16121620
llvm::VersionTuple Module::GetVersion() {
16131621
if (ObjectFile *obj_file = GetObjectFile())
16141622
return obj_file->GetVersion();

lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class DWARFIndex {
9191

9292
StatsDuration::Duration GetIndexTime() { return m_index_time; }
9393

94+
void ResetStatistics() { m_index_time.reset(); }
95+
9496
protected:
9597
Module &m_module;
9698
StatsDuration m_index_time;

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4467,6 +4467,12 @@ StatsDuration::Duration SymbolFileDWARF::GetDebugInfoIndexTime() {
44674467
return {};
44684468
}
44694469

4470+
void SymbolFileDWARF::ResetStatistics() {
4471+
m_parse_time.reset();
4472+
if (m_index)
4473+
return m_index->ResetStatistics();
4474+
}
4475+
44704476
Status SymbolFileDWARF::CalculateFrameVariableError(StackFrame &frame) {
44714477
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
44724478
CompileUnit *cu = frame.GetSymbolContext(eSymbolContextCompUnit).comp_unit;

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
318318

319319
StatsDuration &GetDebugInfoParseTimeRef() { return m_parse_time; }
320320

321+
void ResetStatistics() override;
322+
321323
virtual lldb::offset_t
322324
GetVendorDWARFOpcodeSize(const DataExtractor &data,
323325
const lldb::offset_t data_offset,

lldb/source/Symbol/SymbolFileOnDemand.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,12 @@ StatsDuration::Duration SymbolFileOnDemand::GetDebugInfoIndexTime() {
555555
return m_sym_file_impl->GetDebugInfoIndexTime();
556556
}
557557

558+
void SymbolFileOnDemand::ResetStatistics() {
559+
LLDB_LOG(GetLog(), "[{0}] {1} is not skipped", GetSymbolFileName(),
560+
__FUNCTION__);
561+
return m_sym_file_impl->ResetStatistics();
562+
}
563+
558564
void SymbolFileOnDemand::SetLoadDebugInfoEnabled() {
559565
if (m_debug_info_enabled)
560566
return;

lldb/source/Target/Statistics.cpp

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,24 @@ TargetStats::ToJSON(Target &target,
201201
return target_metrics_json;
202202
}
203203

204+
void TargetStats::Reset(Target &target) {
205+
m_launch_or_attach_time.reset();
206+
m_first_private_stop_time.reset();
207+
m_first_public_stop_time.reset();
208+
// Report both the normal breakpoint list and the internal breakpoint list.
209+
for (int i = 0; i < 2; ++i) {
210+
BreakpointList &breakpoints = target.GetBreakpointList(i == 1);
211+
std::unique_lock<std::recursive_mutex> lock;
212+
breakpoints.GetListMutex(lock);
213+
size_t num_breakpoints = breakpoints.GetSize();
214+
for (size_t i = 0; i < num_breakpoints; i++) {
215+
Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
216+
bp->ResetStatistics();
217+
}
218+
}
219+
target.GetSummaryStatisticsCache().Reset();
220+
}
221+
204222
void TargetStats::SetLaunchOrAttachTime() {
205223
m_launch_or_attach_time = StatsClock::now();
206224
m_first_private_stop_time = std::nullopt;
@@ -236,6 +254,28 @@ void TargetStats::IncreaseSourceRealpathCompatibleCount(uint32_t count) {
236254

237255
bool DebuggerStats::g_collecting_stats = false;
238256

257+
void DebuggerStats::ResetStatistics(Debugger &debugger, Target *target) {
258+
std::lock_guard<std::recursive_mutex> guard(
259+
Module::GetAllocationModuleCollectionMutex());
260+
const uint64_t num_modules = target != nullptr
261+
? target->GetImages().GetSize()
262+
: Module::GetNumberAllocatedModules();
263+
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
264+
Module *module = target != nullptr
265+
? target->GetImages().GetModuleAtIndex(image_idx).get()
266+
: Module::GetAllocatedModuleAtIndex(image_idx);
267+
if (module == nullptr)
268+
continue;
269+
module->ResetStatistics();
270+
}
271+
if (target)
272+
target->ResetStatistics();
273+
else {
274+
for (const auto &target : debugger.GetTargetList().Targets())
275+
target->ResetStatistics();
276+
}
277+
}
278+
239279
llvm::json::Value DebuggerStats::ReportStatistics(
240280
Debugger &debugger, Target *target,
241281
const lldb_private::StatisticsOptions &options) {
@@ -261,14 +301,18 @@ llvm::json::Value DebuggerStats::ReportStatistics(
261301
std::vector<ModuleStats> modules;
262302
std::lock_guard<std::recursive_mutex> guard(
263303
Module::GetAllocationModuleCollectionMutex());
264-
const uint64_t num_modules = Module::GetNumberAllocatedModules();
304+
const uint64_t num_modules = target != nullptr
305+
? target->GetImages().GetSize()
306+
: Module::GetNumberAllocatedModules();
265307
uint32_t num_debug_info_enabled_modules = 0;
266308
uint32_t num_modules_has_debug_info = 0;
267309
uint32_t num_modules_with_variable_errors = 0;
268310
uint32_t num_modules_with_incomplete_types = 0;
269311
uint32_t num_stripped_modules = 0;
270312
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
271-
Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
313+
Module *module = target != nullptr
314+
? target->GetImages().GetModuleAtIndex(image_idx).get()
315+
: Module::GetAllocatedModuleAtIndex(image_idx);
272316
ModuleStats module_stat;
273317
module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
274318
module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
@@ -440,3 +484,8 @@ json::Value SummaryStatisticsCache::ToJSON() {
440484

441485
return json_summary_stats;
442486
}
487+
488+
void SummaryStatisticsCache::Reset() {
489+
for (const auto &summary_stat : m_summary_stats_map)
490+
summary_stat.second->Reset();
491+
}

lldb/source/Target/Target.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5149,3 +5149,5 @@ llvm::json::Value
51495149
Target::ReportStatistics(const lldb_private::StatisticsOptions &options) {
51505150
return m_stats.ToJSON(*this, options);
51515151
}
5152+
5153+
void Target::ResetStatistics() { m_stats.Reset(*this); }

lldb/test/API/commands/statistics/basic/TestStats.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import lldb
21
import json
32
import os
43
import re
4+
5+
import lldb
56
from lldbsuite.test.decorators import *
67
from lldbsuite.test.lldbtest import *
78
from lldbsuite.test import lldbutil
@@ -540,7 +541,7 @@ def test_no_dsym_binary_has_symfile_identifiers_in_stats(self):
540541
# in the stats.
541542
self.runCmd("b main.cpp:7")
542543

543-
debug_stats = self.get_stats()
544+
debug_stats = self.get_stats("--all-targets")
544545

545546
exe_stats = self.find_module_in_metrics(exe, debug_stats)
546547
# If we don't have a dSYM file, there should not be a key/value pair in
@@ -986,3 +987,38 @@ def test_summary_statistics_providers_vec(self):
986987
# We may hit the std::vector C++ provider, or a summary provider string
987988
if "c++" in summary_provider_str:
988989
self.assertIn("std::vector", summary_provider_str)
990+
991+
@skipIfWindows
992+
def test_multiple_targets(self):
993+
"""
994+
Test statistics dump only reports the stats from current target and
995+
"statistics dump --all-targets" includes all target stats.
996+
"""
997+
da = {"CXX_SOURCES": "main.cpp", "EXE": self.getBuildArtifact("a.out")}
998+
self.build(dictionary=da)
999+
self.addTearDownCleanup(dictionary=da)
1000+
1001+
db = {"CXX_SOURCES": "second.cpp", "EXE": self.getBuildArtifact("second.out")}
1002+
self.build(dictionary=db)
1003+
self.addTearDownCleanup(dictionary=db)
1004+
1005+
main_exe = self.getBuildArtifact("a.out")
1006+
second_exe = self.getBuildArtifact("second.out")
1007+
1008+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
1009+
self, "// break here", lldb.SBFileSpec("main.cpp"), None, "a.out"
1010+
)
1011+
debugger_stats1 = self.get_stats()
1012+
self.assertIsNotNone(self.find_module_in_metrics(main_exe, debugger_stats1))
1013+
self.assertIsNone(self.find_module_in_metrics(second_exe, debugger_stats1))
1014+
1015+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
1016+
self, "// break here", lldb.SBFileSpec("second.cpp"), None, "second.out"
1017+
)
1018+
debugger_stats2 = self.get_stats()
1019+
self.assertIsNone(self.find_module_in_metrics(main_exe, debugger_stats2))
1020+
self.assertIsNotNone(self.find_module_in_metrics(second_exe, debugger_stats2))
1021+
1022+
all_targets_stats = self.get_stats("--all-targets")
1023+
self.assertIsNotNone(self.find_module_in_metrics(main_exe, all_targets_stats))
1024+
self.assertIsNotNone(self.find_module_in_metrics(second_exe, all_targets_stats))
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Test that the lldb command `statistics` works.
2+
3+
int main(void) {
4+
return 0; // break here
5+
}

0 commit comments

Comments
 (0)