https://github.com/kusmour updated https://github.com/llvm/llvm-project/pull/80745
>From c79b3daa3e2a5ed2a571d93871bc527b651c0403 Mon Sep 17 00:00:00 2001 From: Wanyi Ye <wa...@fb.com> Date: Fri, 2 Feb 2024 15:42:01 -0800 Subject: [PATCH 1/4] Support statistics dump summary only mode Summary: Added a new --summary option to statistics dump command so that it is much light weight than the full version. With this change, statistics dump --summary can now be included in lldb command line telemetry without slowing down lldb exiting. --- lldb/include/lldb/API/SBTarget.h | 6 +- lldb/include/lldb/Target/Statistics.h | 9 +- lldb/include/lldb/Target/Target.h | 2 +- lldb/source/API/SBTarget.cpp | 9 +- lldb/source/Commands/CommandObjectStats.cpp | 8 +- lldb/source/Commands/Options.td | 3 + lldb/source/Target/Statistics.cpp | 194 +++++++++++------- lldb/source/Target/Target.cpp | 4 +- .../stats_api/TestStatisticsAPI.py | 15 ++ 9 files changed, 163 insertions(+), 87 deletions(-) diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 83087623088c5b..72b8997afd2704 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -86,9 +86,13 @@ class LLDB_API SBTarget { /// Returns a dump of the collected statistics. /// + /// \param[in] summary_only + /// If true, only report high level summary statistics without + /// targets/modules/breakpoints etc.. details. + /// /// \return /// A SBStructuredData with the statistics collected. - lldb::SBStructuredData GetStatistics(); + lldb::SBStructuredData GetStatistics(bool summary_only = false); /// Return the platform object associated with the target. /// diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h index f672786f58f84d..98658ba0cac317 100644 --- a/lldb/include/lldb/Target/Statistics.h +++ b/lldb/include/lldb/Target/Statistics.h @@ -133,7 +133,7 @@ struct ConstStringStats { /// A class that represents statistics for a since lldb_private::Target. class TargetStats { public: - llvm::json::Value ToJSON(Target &target); + llvm::json::Value ToJSON(Target &target, bool summary_only = false); void SetLaunchOrAttachTime(); void SetFirstPrivateStopTime(); @@ -171,9 +171,14 @@ class DebuggerStats { /// The single target to emit statistics for if non NULL, otherwise dump /// statistics only for the specified target. /// + /// \param summary_only + /// If true, only report high level summary statistics without + /// targets/modules/breakpoints etc.. details. + /// /// \return /// Returns a JSON value that contains all target metrics. - static llvm::json::Value ReportStatistics(Debugger &debugger, Target *target); + static llvm::json::Value ReportStatistics(Debugger &debugger, Target *target, + bool summary_only = false); protected: // Collecting stats can be set to true to collect stats that are expensive diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index c37682e2a03859..4bf6c123dc1ddc 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1599,7 +1599,7 @@ class Target : public std::enable_shared_from_this<Target>, /// /// \return /// Returns a JSON value that contains all target metrics. - llvm::json::Value ReportStatistics(); + llvm::json::Value ReportStatistics(bool summary_only = false); TargetStats &GetStatistics() { return m_stats; } diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 8e616afbcb4e8d..615a00ceeaee16 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -197,7 +197,7 @@ SBDebugger SBTarget::GetDebugger() const { return debugger; } -SBStructuredData SBTarget::GetStatistics() { +SBStructuredData SBTarget::GetStatistics(bool summary_only) { LLDB_INSTRUMENT_VA(this); SBStructuredData data; @@ -205,9 +205,10 @@ SBStructuredData SBTarget::GetStatistics() { if (!target_sp) return data; std::string json_str = - llvm::formatv("{0:2}", - DebuggerStats::ReportStatistics(target_sp->GetDebugger(), - target_sp.get())).str(); + llvm::formatv( + "{0:2}", DebuggerStats::ReportStatistics( + target_sp->GetDebugger(), target_sp.get(), summary_only)) + .str(); data.m_impl_up->SetObjectSP(StructuredData::ParseJSON(json_str)); return data; } diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp index 262de0bda144a6..781b90794dc377 100644 --- a/lldb/source/Commands/CommandObjectStats.cpp +++ b/lldb/source/Commands/CommandObjectStats.cpp @@ -75,6 +75,9 @@ class CommandObjectStatsDump : public CommandObjectParsed { case 'a': m_all_targets = true; break; + case 's': + m_summary_only = true; + break; default: llvm_unreachable("Unimplemented option"); } @@ -83,6 +86,7 @@ class CommandObjectStatsDump : public CommandObjectParsed { void OptionParsingStarting(ExecutionContext *execution_context) override { m_all_targets = false; + m_summary_only = false; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { @@ -90,6 +94,7 @@ class CommandObjectStatsDump : public CommandObjectParsed { } bool m_all_targets = false; + bool m_summary_only = false; }; public: @@ -109,7 +114,8 @@ class CommandObjectStatsDump : public CommandObjectParsed { target = m_exe_ctx.GetTargetPtr(); result.AppendMessageWithFormatv( - "{0:2}", DebuggerStats::ReportStatistics(GetDebugger(), target)); + "{0:2}", DebuggerStats::ReportStatistics(GetDebugger(), target, + m_options.m_summary_only)); result.SetStatus(eReturnStatusSuccessFinishResult); } diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index ed3167727bcd32..dba2e74a33a662 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1412,4 +1412,7 @@ let Command = "trace schema" in { let Command = "statistics dump" in { def statistics_dump_all: Option<"all-targets", "a">, Group<1>, Desc<"Include statistics for all targets.">; + def statistics_dump_summary: Option<"summary", "s">, Group<1>, + Desc<"Dump only high level summary statistics." + "Exclude targets, modules, breakpoints etc.. details.">; } diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp index 4699710035b2d6..eab7f807ae40ea 100644 --- a/lldb/source/Target/Statistics.cpp +++ b/lldb/source/Target/Statistics.cpp @@ -12,6 +12,7 @@ #include "lldb/Core/Module.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" @@ -74,7 +75,7 @@ json::Value ModuleStats::ToJSON() const { if (!symfile_modules.empty()) { json::Array symfile_ids; - for (const auto symfile_id: symfile_modules) + for (const auto symfile_id : symfile_modules) symfile_ids.emplace_back(symfile_id); module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids)); } @@ -100,60 +101,91 @@ llvm::json::Value ConstStringStats::ToJSON() const { return obj; } -json::Value TargetStats::ToJSON(Target &target) { - CollectStats(target); +json::Value TargetStats::ToJSON(Target &target, bool summary_only) { + json::Object target_metrics_json; + ProcessSP process_sp = target.GetProcessSP(); + if (!summary_only) { + CollectStats(target); - json::Array json_module_uuid_array; - for (auto module_identifier : m_module_identifiers) - json_module_uuid_array.emplace_back(module_identifier); + json::Array json_module_uuid_array; + for (auto module_identifier : m_module_identifiers) + json_module_uuid_array.emplace_back(module_identifier); - json::Object target_metrics_json{ - {m_expr_eval.name, m_expr_eval.ToJSON()}, - {m_frame_var.name, m_frame_var.ToJSON()}, - {"moduleIdentifiers", std::move(json_module_uuid_array)}}; + target_metrics_json.try_emplace(m_expr_eval.name, m_expr_eval.ToJSON()); + target_metrics_json.try_emplace(m_frame_var.name, m_frame_var.ToJSON()); + target_metrics_json.try_emplace("moduleIdentifiers", + std::move(json_module_uuid_array)); - if (m_launch_or_attach_time && m_first_private_stop_time) { - double elapsed_time = - elapsed(*m_launch_or_attach_time, *m_first_private_stop_time); - target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time); - } - if (m_launch_or_attach_time && m_first_public_stop_time) { - double elapsed_time = - elapsed(*m_launch_or_attach_time, *m_first_public_stop_time); - target_metrics_json.try_emplace("firstStopTime", elapsed_time); + if (m_launch_or_attach_time && m_first_private_stop_time) { + double elapsed_time = + elapsed(*m_launch_or_attach_time, *m_first_private_stop_time); + target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time); + } + if (m_launch_or_attach_time && m_first_public_stop_time) { + double elapsed_time = + elapsed(*m_launch_or_attach_time, *m_first_public_stop_time); + target_metrics_json.try_emplace("firstStopTime", elapsed_time); + } + target_metrics_json.try_emplace("targetCreateTime", + m_create_time.get().count()); + + json::Array breakpoints_array; + double totalBreakpointResolveTime = 0.0; + // Rport 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(); + breakpoints_array.push_back(bp->GetStatistics()); + totalBreakpointResolveTime += bp->GetResolveTime().count(); + } + } + target_metrics_json.try_emplace("breakpoints", + std::move(breakpoints_array)); + target_metrics_json.try_emplace("totalBreakpointResolveTime", + totalBreakpointResolveTime); + + if (process_sp) { + UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals(); + if (unix_signals_sp) + target_metrics_json.try_emplace( + "signals", unix_signals_sp->GetHitCountStatistics()); + } } - target_metrics_json.try_emplace("targetCreateTime", - m_create_time.get().count()); - - json::Array breakpoints_array; - double totalBreakpointResolveTime = 0.0; - // Rport both the normal breakpoint list and the internal breakpoint list. - for (int i = 0; i < 2; ++i) { - BreakpointList &breakpoints = target.GetBreakpointList(i == 1); + + // Counting "totalSharedLibraryEventHitCount" from breakpoints of kind + // "shared-library-event". + { + uint32_t shared_library_event_breakpoint_hit_count = 0; + // The "shared-library-event" is only found in the internal breakpoint list. + BreakpointList &breakpoints = target.GetBreakpointList(/* internal */ true); 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(); - breakpoints_array.push_back(bp->GetStatistics()); - totalBreakpointResolveTime += bp->GetResolveTime().count(); + if (strcmp(bp->GetBreakpointKind(), "shared-library-event") == 0) + shared_library_event_breakpoint_hit_count += bp->GetHitCount(); } + + target_metrics_json.try_emplace("totalSharedLibraryEventHitCount", + shared_library_event_breakpoint_hit_count); } - ProcessSP process_sp = target.GetProcessSP(); if (process_sp) { - UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals(); - if (unix_signals_sp) - target_metrics_json.try_emplace("signals", - unix_signals_sp->GetHitCountStatistics()); uint32_t stop_id = process_sp->GetStopID(); target_metrics_json.try_emplace("stopCount", stop_id); - } - target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array)); - target_metrics_json.try_emplace("totalBreakpointResolveTime", - totalBreakpointResolveTime); - target_metrics_json.try_emplace("sourceMapDeduceCount", m_source_map_deduce_count); + llvm::StringRef dyld_plugin_name; + if (process_sp->GetDynamicLoader()) + dyld_plugin_name = process_sp->GetDynamicLoader()->GetPluginName(); + target_metrics_json.try_emplace("dyldPluginName", dyld_plugin_name); + } + target_metrics_json.try_emplace("sourceMapDeduceCount", + m_source_map_deduce_count); return target_metrics_json; } @@ -185,7 +217,8 @@ void TargetStats::IncreaseSourceMapDeduceCount() { bool DebuggerStats::g_collecting_stats = false; llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, - Target *target) { + Target *target, + bool summary_only) { json::Array json_targets; json::Array json_modules; double symtab_parse_time = 0.0; @@ -197,12 +230,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, uint32_t debug_index_loaded = 0; uint32_t debug_index_saved = 0; uint64_t debug_info_size = 0; - if (target) { - json_targets.emplace_back(target->ReportStatistics()); - } else { - for (const auto &target : debugger.GetTargetList().Targets()) - json_targets.emplace_back(target->ReportStatistics()); - } + std::vector<ModuleStats> modules; std::lock_guard<std::recursive_mutex> guard( Module::GetAllocationModuleCollectionMutex()); @@ -215,15 +243,6 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { Module *module = Module::GetAllocatedModuleAtIndex(image_idx); ModuleStats module_stat; - module_stat.identifier = (intptr_t)module; - module_stat.path = module->GetFileSpec().GetPath(); - if (ConstString object_name = module->GetObjectName()) { - module_stat.path.append(1, '('); - module_stat.path.append(object_name.GetStringRef().str()); - module_stat.path.append(1, ')'); - } - module_stat.uuid = module->GetUUID().GetAsString(); - module_stat.triple = module->GetArchitecture().GetTriple().str(); module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count(); module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count(); Symtab *symtab = module->GetSymtab(); @@ -237,13 +256,14 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, } SymbolFile *sym_file = module->GetSymbolFile(); if (sym_file) { - - if (sym_file->GetObjectFile() != module->GetObjectFile()) - module_stat.symfile_path = - sym_file->GetObjectFile()->GetFileSpec().GetPath(); - module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count(); - module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count(); - module_stat.debug_info_size = sym_file->GetDebugInfoSize(); + if (!summary_only) { + if (sym_file->GetObjectFile() != module->GetObjectFile()) + module_stat.symfile_path = + sym_file->GetObjectFile()->GetFileSpec().GetPath(); + ModuleList symbol_modules = sym_file->GetDebugInfoModules(); + for (const auto &symbol_module : symbol_modules.Modules()) + module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); + } module_stat.debug_info_index_loaded_from_cache = sym_file->GetDebugInfoIndexWasLoadedFromCache(); if (module_stat.debug_info_index_loaded_from_cache) @@ -252,9 +272,9 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, sym_file->GetDebugInfoIndexWasSavedToCache(); if (module_stat.debug_info_index_saved_to_cache) ++debug_index_saved; - ModuleList symbol_modules = sym_file->GetDebugInfoModules(); - for (const auto &symbol_module: symbol_modules.Modules()) - module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); + module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count(); + module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count(); + module_stat.debug_info_size = sym_file->GetDebugInfoSize(); module_stat.symtab_stripped = module->GetObjectFile()->IsStripped(); if (module_stat.symtab_stripped) ++num_stripped_modules; @@ -284,21 +304,21 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, if (module_stat.debug_info_had_incomplete_types) ++num_modules_with_incomplete_types; - json_modules.emplace_back(module_stat.ToJSON()); + if (!summary_only) { + module_stat.identifier = (intptr_t)module; + module_stat.path = module->GetFileSpec().GetPath(); + if (ConstString object_name = module->GetObjectName()) { + module_stat.path.append(1, '('); + module_stat.path.append(object_name.GetStringRef().str()); + module_stat.path.append(1, ')'); + } + module_stat.uuid = module->GetUUID().GetAsString(); + module_stat.triple = module->GetArchitecture().GetTriple().str(); + json_modules.emplace_back(module_stat.ToJSON()); + } } - ConstStringStats const_string_stats; - json::Object json_memory{ - {"strings", const_string_stats.ToJSON()}, - }; - - json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics(); - json::Object global_stats{ - {"targets", std::move(json_targets)}, - {"modules", std::move(json_modules)}, - {"memory", std::move(json_memory)}, - {"commands", std::move(cmd_stats)}, {"totalSymbolTableParseTime", symtab_parse_time}, {"totalSymbolTableIndexTime", symtab_index_time}, {"totalSymbolTablesLoadedFromCache", symtabs_loaded}, @@ -316,5 +336,25 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, {"totalDebugInfoEnabled", num_debug_info_enabled_modules}, {"totalSymbolTableStripped", num_stripped_modules}, }; + + if (target) { + json_targets.emplace_back(target->ReportStatistics(summary_only)); + } else { + for (const auto &target : debugger.GetTargetList().Targets()) + json_targets.emplace_back(target->ReportStatistics(summary_only)); + } + global_stats.try_emplace("targets", std::move(json_targets)); + + if (!summary_only) { + ConstStringStats const_string_stats; + json::Object json_memory{ + {"strings", const_string_stats.ToJSON()}, + }; + json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics(); + global_stats.try_emplace("modules", std::move(json_modules)); + global_stats.try_emplace("memory", std::move(json_memory)); + global_stats.try_emplace("commands", std::move(cmd_stats)); + } + return std::move(global_stats); } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index e969340fdf1eba..e36c03267853f8 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -4962,4 +4962,6 @@ std::recursive_mutex &Target::GetAPIMutex() { } /// Get metrics associated with this target in JSON format. -llvm::json::Value Target::ReportStatistics() { return m_stats.ToJSON(*this); } +llvm::json::Value Target::ReportStatistics(bool summary_only) { + return m_stats.ToJSON(*this, summary_only); +} diff --git a/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py b/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py index fe55922fe4c313..00a7ccb4b56ab6 100644 --- a/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py +++ b/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py @@ -74,6 +74,21 @@ def test_stats_api(self): 'Make sure the "failures" key in in "frameVariable" dictionary"', ) + # Test statistics summary. + stats_summary = target.GetStatistics(True) + stream_summary = lldb.SBStream() + res = stats_summary.GetAsJSON(stream_summary) + debug_stats_summary = json.loads(stream_summary.GetData()) + self.assertNotIn("modules", debug_stats_summary) + self.assertNotIn("memory", debug_stats_summary) + self.assertNotIn("commands", debug_stats_summary) + + # Summary values should be the same as in full statistics. + for key, value in debug_stats_summary.items(): + self.assertIn(key, debug_stats) + if key != "targets": + self.assertEqual(debug_stats[key], value) + def test_command_stats_api(self): """ Test GetCommandInterpreter::GetStatistics() API. >From 8b783cfb430397211bfad8e3df243e284849bb26 Mon Sep 17 00:00:00 2001 From: Wanyi Ye <wa...@fb.com> Date: Mon, 5 Feb 2024 15:33:16 -0800 Subject: [PATCH 2/4] address nit comments --- lldb/source/Commands/Options.td | 4 ++-- lldb/source/Target/Statistics.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index dba2e74a33a662..a87f457105aac0 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1413,6 +1413,6 @@ let Command = "statistics dump" in { def statistics_dump_all: Option<"all-targets", "a">, Group<1>, Desc<"Include statistics for all targets.">; def statistics_dump_summary: Option<"summary", "s">, Group<1>, - Desc<"Dump only high level summary statistics." - "Exclude targets, modules, breakpoints etc.. details.">; + Desc<"Dump only high-level summary statistics." + "Exclude targets, modules, breakpoints etc... details.">; } diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp index eab7f807ae40ea..26a6b26e2e8c9c 100644 --- a/lldb/source/Target/Statistics.cpp +++ b/lldb/source/Target/Statistics.cpp @@ -75,7 +75,7 @@ json::Value ModuleStats::ToJSON() const { if (!symfile_modules.empty()) { json::Array symfile_ids; - for (const auto symfile_id : symfile_modules) + for (const auto symfile_id: symfile_modules) symfile_ids.emplace_back(symfile_id); module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids)); } @@ -131,7 +131,7 @@ json::Value TargetStats::ToJSON(Target &target, bool summary_only) { json::Array breakpoints_array; double totalBreakpointResolveTime = 0.0; - // Rport both the normal breakpoint list and the internal breakpoint list. + // 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; >From aa031703aabe9a88407424b78b2c8d7b6e77b6ad Mon Sep 17 00:00:00 2001 From: Wanyi Ye <wa...@fb.com> Date: Mon, 5 Feb 2024 20:18:23 -0800 Subject: [PATCH 3/4] Create SBStatisticsOptions API Summary: We can't take away or change a previously available public API function. To avoid future changes, intruduce an option class that we can extend without modifying existing APIs. --- lldb/bindings/headers.swig | 1 + .../interface/SBStatisticsOptionsDocStrings.i | 8 +++ lldb/bindings/interfaces.swig | 2 + lldb/include/lldb/API/LLDB.h | 1 + lldb/include/lldb/API/SBDefines.h | 1 + lldb/include/lldb/API/SBStatisticsOptions.h | 36 ++++++++++++++ lldb/include/lldb/API/SBTarget.h | 14 ++++-- lldb/include/lldb/Target/Statistics.h | 12 +++-- lldb/include/lldb/Target/Target.h | 3 +- lldb/include/lldb/lldb-forward.h | 1 + lldb/source/API/CMakeLists.txt | 1 + lldb/source/API/SBStatisticsOptions.cpp | 49 +++++++++++++++++++ lldb/source/API/SBTarget.cpp | 14 ++++-- lldb/source/Commands/CommandObjectStats.cpp | 12 +++-- lldb/source/Target/Statistics.cpp | 18 ++++--- lldb/source/Target/Target.cpp | 5 +- .../stats_api/TestStatisticsAPI.py | 8 ++- 17 files changed, 160 insertions(+), 26 deletions(-) create mode 100644 lldb/bindings/interface/SBStatisticsOptionsDocStrings.i create mode 100644 lldb/include/lldb/API/SBStatisticsOptions.h create mode 100644 lldb/source/API/SBStatisticsOptions.cpp diff --git a/lldb/bindings/headers.swig b/lldb/bindings/headers.swig index 408db90b925f15..e8d0cda288141c 100644 --- a/lldb/bindings/headers.swig +++ b/lldb/bindings/headers.swig @@ -54,6 +54,7 @@ #include "lldb/API/SBScriptObject.h" #include "lldb/API/SBSection.h" #include "lldb/API/SBSourceManager.h" +#include "lldb/API/SBStatisticsOptions.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStringList.h" #include "lldb/API/SBStructuredData.h" diff --git a/lldb/bindings/interface/SBStatisticsOptionsDocStrings.i b/lldb/bindings/interface/SBStatisticsOptionsDocStrings.i new file mode 100644 index 00000000000000..f72cf84319e19b --- /dev/null +++ b/lldb/bindings/interface/SBStatisticsOptionsDocStrings.i @@ -0,0 +1,8 @@ +%feature("docstring", +"A container for options to use when dumping statistics." +) lldb::SBStatisticsOptions; + +%feature("docstring", "Sets whether the statistics should only dump a summary." +) lldb::SBStatisticsOptions::SetSummaryOnly; +%feature("docstring", "Gets whether the statistics only dump a summary." +) lldb::SBStatisticsOptions::GetSummaryOnly; diff --git a/lldb/bindings/interfaces.swig b/lldb/bindings/interfaces.swig index 9ca479218f621c..a31a0b4af1eb6c 100644 --- a/lldb/bindings/interfaces.swig +++ b/lldb/bindings/interfaces.swig @@ -56,6 +56,7 @@ %include "./interface/SBReproducerDocstrings.i" %include "./interface/SBSectionDocstrings.i" %include "./interface/SBSourceManagerDocstrings.i" +%include "./interface/SBStatisticsOptionsDocstrings.i" %include "./interface/SBStreamDocstrings.i" %include "./interface/SBStringListDocstrings.i" %include "./interface/SBStructuredDataDocstrings.i" @@ -131,6 +132,7 @@ %include "lldb/API/SBScriptObject.h" %include "lldb/API/SBSection.h" %include "lldb/API/SBSourceManager.h" +%include "lldb/API/SBStatisticsOptions.h" %include "lldb/API/SBStream.h" %include "lldb/API/SBStringList.h" %include "lldb/API/SBStructuredData.h" diff --git a/lldb/include/lldb/API/LLDB.h b/lldb/include/lldb/API/LLDB.h index f5f1b87a046c2a..c83eb92fcfb30a 100644 --- a/lldb/include/lldb/API/LLDB.h +++ b/lldb/include/lldb/API/LLDB.h @@ -56,6 +56,7 @@ #include "lldb/API/SBReproducer.h" #include "lldb/API/SBSection.h" #include "lldb/API/SBSourceManager.h" +#include "lldb/API/SBStatisticsOptions.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStringList.h" #include "lldb/API/SBStructuredData.h" diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h index 92d823fa1dfe25..1181920677b46f 100644 --- a/lldb/include/lldb/API/SBDefines.h +++ b/lldb/include/lldb/API/SBDefines.h @@ -99,6 +99,7 @@ class LLDB_API SBReproducer; class LLDB_API SBScriptObject; class LLDB_API SBSection; class LLDB_API SBSourceManager; +class LLDB_API SBStatisticsOptions; class LLDB_API SBStream; class LLDB_API SBStringList; class LLDB_API SBStructuredData; diff --git a/lldb/include/lldb/API/SBStatisticsOptions.h b/lldb/include/lldb/API/SBStatisticsOptions.h new file mode 100644 index 00000000000000..8019ed4315ca21 --- /dev/null +++ b/lldb/include/lldb/API/SBStatisticsOptions.h @@ -0,0 +1,36 @@ +//===-- SBStatisticsOptions.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_API_SBSTATISTICSOPTIONS_H +#define LLDB_API_SBSTATISTICSOPTIONS_H + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +/// This class handles the verbosity when dumping statistics +class LLDB_API SBStatisticsOptions { +public: + SBStatisticsOptions(); + SBStatisticsOptions(const lldb::SBStatisticsOptions &rhs); + ~SBStatisticsOptions(); + + const SBStatisticsOptions &operator=(const lldb::SBStatisticsOptions &rhs); + + void SetSummaryOnly(bool b); + bool GetSummaryOnly(); + +protected: + friend class SBTarget; + const lldb_private::StatisticsOptions &ref() const; + +private: + std::unique_ptr<lldb_private::StatisticsOptions> m_opaque_up; +}; +} // namespace lldb +#endif // LLDB_API_SBSTATISTICSOPTIONS_H diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 72b8997afd2704..f7bdd3093d2025 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -17,6 +17,7 @@ #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBLaunchInfo.h" +#include "lldb/API/SBStatisticsOptions.h" #include "lldb/API/SBSymbolContextList.h" #include "lldb/API/SBType.h" #include "lldb/API/SBValue.h" @@ -86,13 +87,18 @@ class LLDB_API SBTarget { /// Returns a dump of the collected statistics. /// - /// \param[in] summary_only - /// If true, only report high level summary statistics without - /// targets/modules/breakpoints etc.. details. + /// \return + /// A SBStructuredData with the statistics collected. + lldb::SBStructuredData GetStatistics(); + + /// Returns a dump of the collected statistics. + /// + /// \param[in] options + /// An objects object that contains all options for the statistics dumping. /// /// \return /// A SBStructuredData with the statistics collected. - lldb::SBStructuredData GetStatistics(bool summary_only = false); + lldb::SBStructuredData GetStatistics(SBStatisticsOptions options); /// Return the platform object associated with the target. /// diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h index 98658ba0cac317..f838fa17f80c24 100644 --- a/lldb/include/lldb/Target/Statistics.h +++ b/lldb/include/lldb/Target/Statistics.h @@ -130,10 +130,15 @@ struct ConstStringStats { ConstString::MemoryStats stats = ConstString::GetMemoryStats(); }; +struct StatisticsOptions { + bool summary_only = false; +}; + /// A class that represents statistics for a since lldb_private::Target. class TargetStats { public: - llvm::json::Value ToJSON(Target &target, bool summary_only = false); + llvm::json::Value ToJSON(Target &target, + const lldb_private::StatisticsOptions &options); void SetLaunchOrAttachTime(); void SetFirstPrivateStopTime(); @@ -177,8 +182,9 @@ class DebuggerStats { /// /// \return /// Returns a JSON value that contains all target metrics. - static llvm::json::Value ReportStatistics(Debugger &debugger, Target *target, - bool summary_only = false); + static llvm::json::Value + ReportStatistics(Debugger &debugger, Target *target, + const lldb_private::StatisticsOptions &options); protected: // Collecting stats can be set to true to collect stats that are expensive diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 4bf6c123dc1ddc..8f57358981d4d2 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1599,7 +1599,8 @@ class Target : public std::enable_shared_from_this<Target>, /// /// \return /// Returns a JSON value that contains all target metrics. - llvm::json::Value ReportStatistics(bool summary_only = false); + llvm::json::Value + ReportStatistics(const lldb_private::StatisticsOptions &options); TargetStats &GetStatistics() { return m_stats; } diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index d89ad21512215f..10ba921b9dac8c 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -298,6 +298,7 @@ struct CompilerContext; struct LineEntry; struct PropertyDefinition; struct ScriptSummaryFormat; +struct StatisticsOptions; struct StringSummaryFormat; template <unsigned N> class StreamBuffer; diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 7d478ecc7f599e..57cc44f7646753 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -69,6 +69,7 @@ add_lldb_library(liblldb SHARED ${option_framework} SBScriptObject.cpp SBSection.cpp SBSourceManager.cpp + SBStatisticsOptions.cpp SBStream.cpp SBStringList.cpp SBStructuredData.cpp diff --git a/lldb/source/API/SBStatisticsOptions.cpp b/lldb/source/API/SBStatisticsOptions.cpp new file mode 100644 index 00000000000000..77a7e26a6bd4b5 --- /dev/null +++ b/lldb/source/API/SBStatisticsOptions.cpp @@ -0,0 +1,49 @@ +//===-- SBStatisticsOptions.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBStatisticsOptions.h" +#include "lldb/Target/Statistics.h" +#include "lldb/Utility/Instrumentation.h" + +#include "Utils.h" + +using namespace lldb; +using namespace lldb_private; + +SBStatisticsOptions::SBStatisticsOptions() + : m_opaque_up(new StatisticsOptions()) { + LLDB_INSTRUMENT_VA(this); + m_opaque_up->summary_only = false; +} + +SBStatisticsOptions::SBStatisticsOptions(const SBStatisticsOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + m_opaque_up = clone(rhs.m_opaque_up); +} + +SBStatisticsOptions::~SBStatisticsOptions() = default; + +const SBStatisticsOptions & +SBStatisticsOptions::operator=(const SBStatisticsOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (this != &rhs) + m_opaque_up = clone(rhs.m_opaque_up); + return *this; +} + +void SBStatisticsOptions::SetSummaryOnly(bool b) { + m_opaque_up->summary_only = b; +} + +bool SBStatisticsOptions::GetSummaryOnly() { return m_opaque_up->summary_only; } + +const lldb_private::StatisticsOptions &SBStatisticsOptions::ref() const { + return *m_opaque_up; +} diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 615a00ceeaee16..cc9f1fdd76afaa 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -197,7 +197,13 @@ SBDebugger SBTarget::GetDebugger() const { return debugger; } -SBStructuredData SBTarget::GetStatistics(bool summary_only) { +SBStructuredData SBTarget::GetStatistics() { + LLDB_INSTRUMENT_VA(this); + SBStatisticsOptions options; + return GetStatistics(options); +} + +SBStructuredData SBTarget::GetStatistics(SBStatisticsOptions options) { LLDB_INSTRUMENT_VA(this); SBStructuredData data; @@ -205,9 +211,9 @@ SBStructuredData SBTarget::GetStatistics(bool summary_only) { if (!target_sp) return data; std::string json_str = - llvm::formatv( - "{0:2}", DebuggerStats::ReportStatistics( - target_sp->GetDebugger(), target_sp.get(), summary_only)) + llvm::formatv("{0:2}", DebuggerStats::ReportStatistics( + target_sp->GetDebugger(), target_sp.get(), + options.ref())) .str(); data.m_impl_up->SetObjectSP(StructuredData::ParseJSON(json_str)); return data; diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp index 781b90794dc377..0936ffb9bc6891 100644 --- a/lldb/source/Commands/CommandObjectStats.cpp +++ b/lldb/source/Commands/CommandObjectStats.cpp @@ -76,7 +76,7 @@ class CommandObjectStatsDump : public CommandObjectParsed { m_all_targets = true; break; case 's': - m_summary_only = true; + m_stats_options.summary_only = true; break; default: llvm_unreachable("Unimplemented option"); @@ -86,15 +86,17 @@ class CommandObjectStatsDump : public CommandObjectParsed { void OptionParsingStarting(ExecutionContext *execution_context) override { m_all_targets = false; - m_summary_only = false; + m_stats_options = StatisticsOptions(); } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { return llvm::ArrayRef(g_statistics_dump_options); } + StatisticsOptions GetStatisticsOptions() { return m_stats_options; } + bool m_all_targets = false; - bool m_summary_only = false; + StatisticsOptions m_stats_options = StatisticsOptions(); }; public: @@ -114,8 +116,8 @@ class CommandObjectStatsDump : public CommandObjectParsed { target = m_exe_ctx.GetTargetPtr(); result.AppendMessageWithFormatv( - "{0:2}", DebuggerStats::ReportStatistics(GetDebugger(), target, - m_options.m_summary_only)); + "{0:2}", DebuggerStats::ReportStatistics( + GetDebugger(), target, m_options.GetStatisticsOptions())); result.SetStatus(eReturnStatusSuccessFinishResult); } diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp index 26a6b26e2e8c9c..4f84caf5cbbe0f 100644 --- a/lldb/source/Target/Statistics.cpp +++ b/lldb/source/Target/Statistics.cpp @@ -101,9 +101,12 @@ llvm::json::Value ConstStringStats::ToJSON() const { return obj; } -json::Value TargetStats::ToJSON(Target &target, bool summary_only) { +json::Value +TargetStats::ToJSON(Target &target, + const lldb_private::StatisticsOptions &options) { json::Object target_metrics_json; ProcessSP process_sp = target.GetProcessSP(); + bool summary_only = options.summary_only; if (!summary_only) { CollectStats(target); @@ -216,9 +219,12 @@ void TargetStats::IncreaseSourceMapDeduceCount() { bool DebuggerStats::g_collecting_stats = false; -llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, - Target *target, - bool summary_only) { +llvm::json::Value DebuggerStats::ReportStatistics( + Debugger &debugger, Target *target, + const lldb_private::StatisticsOptions &options) { + + bool summary_only = options.summary_only; + json::Array json_targets; json::Array json_modules; double symtab_parse_time = 0.0; @@ -338,10 +344,10 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, }; if (target) { - json_targets.emplace_back(target->ReportStatistics(summary_only)); + json_targets.emplace_back(target->ReportStatistics(options)); } else { for (const auto &target : debugger.GetTargetList().Targets()) - json_targets.emplace_back(target->ReportStatistics(summary_only)); + json_targets.emplace_back(target->ReportStatistics(options)); } global_stats.try_emplace("targets", std::move(json_targets)); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index e36c03267853f8..e17bfcb5d5e2ad 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -4962,6 +4962,7 @@ std::recursive_mutex &Target::GetAPIMutex() { } /// Get metrics associated with this target in JSON format. -llvm::json::Value Target::ReportStatistics(bool summary_only) { - return m_stats.ToJSON(*this, summary_only); +llvm::json::Value +Target::ReportStatistics(const lldb_private::StatisticsOptions &options) { + return m_stats.ToJSON(*this, options); } diff --git a/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py b/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py index 00a7ccb4b56ab6..692cd662c393a3 100644 --- a/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py +++ b/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py @@ -75,7 +75,9 @@ def test_stats_api(self): ) # Test statistics summary. - stats_summary = target.GetStatistics(True) + stats_options = lldb.SBStatisticsOptions() + stats_options.SetSummaryOnly(True) + stats_summary = target.GetStatistics(stats_options) stream_summary = lldb.SBStream() res = stats_summary.GetAsJSON(stream_summary) debug_stats_summary = json.loads(stream_summary.GetData()) @@ -84,9 +86,13 @@ def test_stats_api(self): self.assertNotIn("commands", debug_stats_summary) # Summary values should be the same as in full statistics. + print(debug_stats) + print("\n") + print(debug_stats_summary) for key, value in debug_stats_summary.items(): self.assertIn(key, debug_stats) if key != "targets": + print(f"\nkey: {key}, value: {value}\n") self.assertEqual(debug_stats[key], value) def test_command_stats_api(self): >From 54a9ec1a18b3607b80d1fbebf056d09e634b1990 Mon Sep 17 00:00:00 2001 From: Wanyi Ye <wa...@fb.com> Date: Mon, 5 Feb 2024 11:33:03 -0800 Subject: [PATCH 4/4] Only report total currently loaded debug info --- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 5 +++-- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h | 2 +- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 2 +- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h | 4 ++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 23e0b8a7f2c06b..4e822742780f8d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -896,8 +896,9 @@ void DWARFUnit::ComputeAbsolutePath() { m_file_spec->MakeAbsolute(GetCompilationDirectory()); } -SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() { - ExtractUnitDIEIfNeeded(); +SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile(bool load_if_needed) { + if (load_if_needed) + ExtractUnitDIEIfNeeded(); if (m_dwo) return &llvm::cast<SymbolFileDWARFDwo>(m_dwo->GetSymbolFileDWARF()); return nullptr; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 9f6d127056fa56..815738d8a19330 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -241,7 +241,7 @@ class DWARFUnit : public UserID { FileSpec GetFile(size_t file_idx); FileSpec::Style GetPathStyle(); - SymbolFileDWARFDwo *GetDwoSymbolFile(); + SymbolFileDWARFDwo *GetDwoSymbolFile(bool load_if_needed = true); die_iterator_range dies() { ExtractDIEsIfNeeded(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 781f5c5a436778..0918a77f83cf74 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2687,7 +2687,7 @@ uint64_t SymbolFileDWARF::GetDebugInfoSize() { if (cu == nullptr) continue; - SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile(); + SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile(false); if (dwo) debug_info_size += dwo->GetDebugInfoSize(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 60baf694b463ec..b80699322688fe 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -186,6 +186,10 @@ class SymbolFileDWARF : public SymbolFileCommon { GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names) override; + /// Return total currently loaded debug info. + /// For cases like .dwo files, the debug info = skeleton debug info + all dwo + /// debug info where .dwo files might not be loaded yet. Calling this function + /// will not force the loading of any .dwo files. uint64_t GetDebugInfoSize() override; void FindTypes(const lldb_private::TypeQuery &match, _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits