Skip to content

Commit

Permalink
Fix statistics dump to report per-target (llvm#113723)
Browse files Browse the repository at this point in the history
"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]>
(cherry picked from commit 24feaab)
  • Loading branch information
jeffreytan81 authored and adrian-prantl committed Dec 10, 2024
1 parent e5cc456 commit 45d373d
Show file tree
Hide file tree
Showing 20 changed files with 173 additions and 4 deletions.
5 changes: 5 additions & 0 deletions lldb/include/lldb/API/SBDebugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,11 @@ class LLDB_API SBDebugger {

SBTypeSynthetic GetSyntheticForType(SBTypeNameSpecifier);

/// Clear collected statistics for targets belonging to this debugger. This
/// includes clearing symbol table and debug info parsing/index time for all
/// modules, breakpoint resolve time and target statistics.
void ResetStatistics();

#ifndef SWIG
/// Run the command interpreter.
///
Expand Down
5 changes: 5 additions & 0 deletions lldb/include/lldb/API/SBTarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ class LLDB_API SBTarget {
/// A SBStructuredData with the statistics collected.
lldb::SBStructuredData GetStatistics(SBStatisticsOptions options);

/// Reset the statistics collected for this target.
/// This includes clearing symbol table and debug info parsing/index time for
/// all modules, breakpoint resolve time and target statistics.
void ResetStatistics();

/// Return the platform object associated with the target.
///
/// After return, the platform object should be checked for
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Breakpoint/Breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,8 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
/// Get statistics associated with this breakpoint in JSON format.
llvm::json::Value GetStatistics();

void ResetStatistics();

/// Get the time it took to resolve all locations in this breakpoint.
StatsDuration::Duration GetResolveTime() const { return m_resolve_time; }

Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Core/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,8 @@ class Module : public std::enable_shared_from_this<Module>,
/// ElapsedTime RAII object.
StatsDuration &GetSymtabIndexTime() { return m_symtab_index_time; }

void ResetStatistics();

/// \class LookupInfo Module.h "lldb/Core/Module.h"
/// A class that encapsulates name lookup information.
///
Expand Down
3 changes: 3 additions & 0 deletions lldb/include/lldb/Symbol/SymbolFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,9 @@ class SymbolFile : public PluginInterface {
/// hasn't been indexed yet, or a valid duration if it has.
virtual StatsDuration::Duration GetDebugInfoIndexTime() { return {}; }

/// Reset the statistics for the symbol file.
virtual void ResetStatistics() {}

/// Get the additional modules that this symbol file uses to parse debug info.
///
/// Some debug info is stored in stand alone object files that are represented
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Symbol/SymbolFileOnDemand.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ class SymbolFileOnDemand : public lldb_private::SymbolFile {
lldb_private::StatsDuration::Duration GetDebugInfoParseTime() override;
lldb_private::StatsDuration::Duration GetDebugInfoIndexTime() override;

void ResetStatistics() override;

uint32_t GetAbilities() override;

Symtab *GetSymtab() override { return m_sym_file_impl->GetSymtab(); }
Expand Down
17 changes: 17 additions & 0 deletions lldb/include/lldb/Target/Statistics.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class StatsDuration {
}
operator Duration() const { return get(); }

void reset() { value.store(0, std::memory_order_relaxed); }

StatsDuration &operator+=(Duration dur) {
value.fetch_add(std::chrono::duration_cast<InternalDuration>(dur).count(),
std::memory_order_relaxed);
Expand Down Expand Up @@ -201,6 +203,8 @@ class SummaryStatistics {

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

void Reset() { m_total_time.reset(); }

/// Basic RAII class to increment the summary count when the call is complete.
class SummaryInvocation {
public:
Expand Down Expand Up @@ -250,6 +254,8 @@ class SummaryStatisticsCache {

llvm::json::Value ToJSON();

void Reset();

private:
llvm::StringMap<SummaryStatisticsSP> m_summary_stats_map;
std::mutex m_map_mutex;
Expand All @@ -271,6 +277,7 @@ class TargetStats {
StatsDuration &GetCreateTime() { return m_create_time; }
StatsSuccessFail &GetExpressionStats() { return m_expr_eval; }
StatsSuccessFail &GetFrameVariableStats() { return m_frame_var; }
void Reset(Target &target);

protected:
StatsDuration m_create_time;
Expand Down Expand Up @@ -311,6 +318,16 @@ class DebuggerStats {
ReportStatistics(Debugger &debugger, Target *target,
const lldb_private::StatisticsOptions &options);

/// Reset metrics associated with one or all targets in a debugger.
///
/// \param debugger
/// The debugger to reset the target list from if \a target is NULL.
///
/// \param target
/// The target to reset statistics for, or if null, reset statistics
/// for all targets
static void ResetStatistics(Debugger &debugger, Target *target);

protected:
// Collecting stats can be set to true to collect stats that are expensive
// to collect. By default all stats that are cheap to collect are enabled.
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -1735,6 +1735,8 @@ class Target : public std::enable_shared_from_this<Target>,
llvm::json::Value
ReportStatistics(const lldb_private::StatisticsOptions &options);

void ResetStatistics();

TargetStats &GetStatistics() { return m_stats; }

protected:
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/API/SBDebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,12 @@ SBTypeSynthetic SBDebugger::GetSyntheticForType(SBTypeNameSpecifier type_name) {
DataVisualization::GetSyntheticForType(type_name.GetSP()));
}

void SBDebugger::ResetStatistics() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_sp)
DebuggerStats::ResetStatistics(*m_opaque_sp, nullptr);
}

static llvm::ArrayRef<const char *> GetCategoryArray(const char **categories) {
if (categories == nullptr)
return {};
Expand Down
7 changes: 7 additions & 0 deletions lldb/source/API/SBTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,13 @@ SBStructuredData SBTarget::GetStatistics(SBStatisticsOptions options) {
return data;
}

void SBTarget::ResetStatistics() {
LLDB_INSTRUMENT_VA(this);
TargetSP target_sp(GetSP());
if (target_sp)
DebuggerStats::ResetStatistics(target_sp->GetDebugger(), target_sp.get());
}

void SBTarget::SetCollectingStats(bool v) {
LLDB_INSTRUMENT_VA(this, v);

Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Breakpoint/Breakpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1138,3 +1138,5 @@ json::Value Breakpoint::GetStatistics() {
}
return json::Value(std::move(bp));
}

void Breakpoint::ResetStatistics() { m_resolve_time.reset(); }
8 changes: 8 additions & 0 deletions lldb/source/Core/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,14 @@ bool Module::MergeArchitecture(const ArchSpec &arch_spec) {
return SetArchitecture(merged_arch);
}

void Module::ResetStatistics() {
m_symtab_parse_time.reset();
m_symtab_index_time.reset();
SymbolFile *sym_file = GetSymbolFile();
if (sym_file)
sym_file->ResetStatistics();
}

llvm::VersionTuple Module::GetVersion() {
if (ObjectFile *obj_file = GetObjectFile())
return obj_file->GetVersion();
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class DWARFIndex {

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

void ResetStatistics() { m_index_time.reset(); }

protected:
Module &m_module;
StatsDuration m_index_time;
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4560,6 +4560,12 @@ StatsDuration::Duration SymbolFileDWARF::GetDebugInfoIndexTime() {
return {};
}

void SymbolFileDWARF::ResetStatistics() {
m_parse_time.reset();
if (m_index)
return m_index->ResetStatistics();
}

Status SymbolFileDWARF::CalculateFrameVariableError(StackFrame &frame) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
CompileUnit *cu = frame.GetSymbolContext(eSymbolContextCompUnit).comp_unit;
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ class SymbolFileDWARF : public SymbolFileCommon {

StatsDuration &GetDebugInfoParseTimeRef() { return m_parse_time; }

void ResetStatistics() override;

virtual lldb::offset_t
GetVendorDWARFOpcodeSize(const DataExtractor &data,
const lldb::offset_t data_offset,
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Symbol/SymbolFileOnDemand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,12 @@ StatsDuration::Duration SymbolFileOnDemand::GetDebugInfoIndexTime() {
return m_sym_file_impl->GetDebugInfoIndexTime();
}

void SymbolFileOnDemand::ResetStatistics() {
LLDB_LOG(GetLog(), "[{0}] {1} is not skipped", GetSymbolFileName(),
__FUNCTION__);
return m_sym_file_impl->ResetStatistics();
}

void SymbolFileOnDemand::SetLoadDebugInfoEnabled() {
if (m_debug_info_enabled)
return;
Expand Down
53 changes: 51 additions & 2 deletions lldb/source/Target/Statistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,24 @@ TargetStats::ToJSON(Target &target,
return target_metrics_json;
}

void TargetStats::Reset(Target &target) {
m_launch_or_attach_time.reset();
m_first_private_stop_time.reset();
m_first_public_stop_time.reset();
// Report both the normal breakpoint list and the internal breakpoint list.
for (int i = 0; i < 2; ++i) {
BreakpointList &breakpoints = target.GetBreakpointList(i == 1);
std::unique_lock<std::recursive_mutex> lock;
breakpoints.GetListMutex(lock);
size_t num_breakpoints = breakpoints.GetSize();
for (size_t i = 0; i < num_breakpoints; i++) {
Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
bp->ResetStatistics();
}
}
target.GetSummaryStatisticsCache().Reset();
}

void TargetStats::SetLaunchOrAttachTime() {
m_launch_or_attach_time = StatsClock::now();
m_first_private_stop_time = std::nullopt;
Expand Down Expand Up @@ -236,6 +254,28 @@ void TargetStats::IncreaseSourceRealpathCompatibleCount(uint32_t count) {

bool DebuggerStats::g_collecting_stats = false;

void DebuggerStats::ResetStatistics(Debugger &debugger, Target *target) {
std::lock_guard<std::recursive_mutex> guard(
Module::GetAllocationModuleCollectionMutex());
const uint64_t num_modules = target != nullptr
? target->GetImages().GetSize()
: Module::GetNumberAllocatedModules();
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = target != nullptr
? target->GetImages().GetModuleAtIndex(image_idx).get()
: Module::GetAllocatedModuleAtIndex(image_idx);
if (module == nullptr)
continue;
module->ResetStatistics();
}
if (target)
target->ResetStatistics();
else {
for (const auto &target : debugger.GetTargetList().Targets())
target->ResetStatistics();
}
}

llvm::json::Value DebuggerStats::ReportStatistics(
Debugger &debugger, Target *target,
const lldb_private::StatisticsOptions &options) {
Expand All @@ -261,14 +301,18 @@ llvm::json::Value DebuggerStats::ReportStatistics(
std::vector<ModuleStats> modules;
std::lock_guard<std::recursive_mutex> guard(
Module::GetAllocationModuleCollectionMutex());
const uint64_t num_modules = Module::GetNumberAllocatedModules();
const uint64_t num_modules = target != nullptr
? target->GetImages().GetSize()
: Module::GetNumberAllocatedModules();
uint32_t num_debug_info_enabled_modules = 0;
uint32_t num_modules_has_debug_info = 0;
uint32_t num_modules_with_variable_errors = 0;
uint32_t num_modules_with_incomplete_types = 0;
uint32_t num_stripped_modules = 0;
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
Module *module = target != nullptr
? target->GetImages().GetModuleAtIndex(image_idx).get()
: Module::GetAllocatedModuleAtIndex(image_idx);
ModuleStats module_stat;
module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
Expand Down Expand Up @@ -440,3 +484,8 @@ json::Value SummaryStatisticsCache::ToJSON() {

return json_summary_stats;
}

void SummaryStatisticsCache::Reset() {
for (const auto &summary_stat : m_summary_stats_map)
summary_stat.second->Reset();
}
2 changes: 2 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5389,3 +5389,5 @@ llvm::json::Value
Target::ReportStatistics(const lldb_private::StatisticsOptions &options) {
return m_stats.ToJSON(*this, options);
}

void Target::ResetStatistics() { m_stats.Reset(*this); }
40 changes: 38 additions & 2 deletions lldb/test/API/commands/statistics/basic/TestStats.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import lldb
import json
import os
import re

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
Expand Down Expand Up @@ -540,7 +541,7 @@ def test_no_dsym_binary_has_symfile_identifiers_in_stats(self):
# in the stats.
self.runCmd("b main.cpp:7")

debug_stats = self.get_stats()
debug_stats = self.get_stats("--all-targets")

exe_stats = self.find_module_in_metrics(exe, debug_stats)
# If we don't have a dSYM file, there should not be a key/value pair in
Expand Down Expand Up @@ -984,3 +985,38 @@ def test_summary_statistics_providers_vec(self):
# We may hit the std::vector C++ provider, or a summary provider string
if "c++" in summary_provider_str:
self.assertIn("std::vector", summary_provider_str)

@skipIfWindows
def test_multiple_targets(self):
"""
Test statistics dump only reports the stats from current target and
"statistics dump --all-targets" includes all target stats.
"""
da = {"CXX_SOURCES": "main.cpp", "EXE": self.getBuildArtifact("a.out")}
self.build(dictionary=da)
self.addTearDownCleanup(dictionary=da)

db = {"CXX_SOURCES": "second.cpp", "EXE": self.getBuildArtifact("second.out")}
self.build(dictionary=db)
self.addTearDownCleanup(dictionary=db)

main_exe = self.getBuildArtifact("a.out")
second_exe = self.getBuildArtifact("second.out")

(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "// break here", lldb.SBFileSpec("main.cpp"), None, "a.out"
)
debugger_stats1 = self.get_stats()
self.assertIsNotNone(self.find_module_in_metrics(main_exe, debugger_stats1))
self.assertIsNone(self.find_module_in_metrics(second_exe, debugger_stats1))

(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "// break here", lldb.SBFileSpec("second.cpp"), None, "second.out"
)
debugger_stats2 = self.get_stats()
self.assertIsNone(self.find_module_in_metrics(main_exe, debugger_stats2))
self.assertIsNotNone(self.find_module_in_metrics(second_exe, debugger_stats2))

all_targets_stats = self.get_stats("--all-targets")
self.assertIsNotNone(self.find_module_in_metrics(main_exe, all_targets_stats))
self.assertIsNotNone(self.find_module_in_metrics(second_exe, all_targets_stats))
5 changes: 5 additions & 0 deletions lldb/test/API/commands/statistics/basic/second.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Test that the lldb command `statistics` works.

int main(void) {
return 0; // break here
}

0 comments on commit 45d373d

Please sign in to comment.