[Lldb-commits] [lldb] [lldb] Add/change options in `statistics dump` to control what sections are dumped (PR #95075)
via lldb-commits
lldb-commits at lists.llvm.org
Tue Jun 18 13:37:48 PDT 2024
https://github.com/royitaqi updated https://github.com/llvm/llvm-project/pull/95075
>From f57f98f22425d3c869621b43b65da705d50b5934 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Mon, 10 Jun 2024 17:04:11 -0700
Subject: [PATCH 01/19] Add --targets and --modules option to statistics dump
---
lldb/include/lldb/Target/Statistics.h | 2 ++
lldb/source/Commands/CommandObjectStats.cpp | 6 ++++++
lldb/source/Commands/Options.td | 16 +++++++++++++---
lldb/source/Target/Statistics.cpp | 21 ++++++++++++++-------
4 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index c04d529290fff..b24520b72a95d 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -133,6 +133,8 @@ struct ConstStringStats {
struct StatisticsOptions {
bool summary_only = false;
bool load_all_debug_info = false;
+ bool include_targets = false;
+ bool include_modules = false;
bool include_transcript = false;
};
diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp
index 1935b0fdfadfb..1347b1ba25b1d 100644
--- a/lldb/source/Commands/CommandObjectStats.cpp
+++ b/lldb/source/Commands/CommandObjectStats.cpp
@@ -81,6 +81,12 @@ class CommandObjectStatsDump : public CommandObjectParsed {
case 'f':
m_stats_options.load_all_debug_info = true;
break;
+ case 'r':
+ m_stats_options.include_targets = true;
+ break;
+ case 'm':
+ m_stats_options.include_modules = true;
+ break;
case 't':
m_stats_options.include_transcript = true;
break;
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index cee5a81d3796b..45f46334d5c73 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1416,16 +1416,26 @@ let Command = "trace schema" in {
}
let Command = "statistics dump" in {
- def statistics_dump_all: Option<"all-targets", "a">, Group<1>,
+ def statistics_dump_all: Option<"all-targets", "a">, GroupRange<1, 2>,
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.">;
- def statistics_dump_force: Option<"load-all-debug-info", "f">, Group<1>,
+ def statistics_dump_force: Option<"load-all-debug-info", "f">, GroupRange<1, 2>,
Desc<"Dump the total possible debug info statistics. "
"Force loading all the debug information if not yet loaded, and collect "
"statistics with those.">;
- def statistics_dump_transcript: Option<"transcript", "t">, Group<1>,
+ def statistics_dump_targets: Option<"targets", "r">, Group<2>,
+ Desc<"Dump statistics for the targets, including breakpoints, expression "
+ "evaluations, frame variables, etc. "
+ "If both the '--targets' and the '--modules' options are specified, a "
+ "list of module identifiers will be added to the 'targets' section.">;
+ def statistics_dump_modules: Option<"modules", "m">, Group<2>,
+ Desc<"Dump statistics for the modules, including time and size of various "
+ "aspects of the module and debug information, type system, path, etc. "
+ "If both the '--targets' and the '--modules' options are specified, a "
+ "list of module identifiers will be added to the 'targets' section.">;
+ def statistics_dump_transcript: Option<"transcript", "t">, Group<2>,
Desc<"If the setting interpreter.save-transcript is enabled and this "
"option is specified, include a JSON array with all commands the user and/"
"or scripts executed during a debug session.">;
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 2a5300012511a..13c430d73990e 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -226,6 +226,8 @@ llvm::json::Value DebuggerStats::ReportStatistics(
const bool summary_only = options.summary_only;
const bool load_all_debug_info = options.load_all_debug_info;
+ const bool include_targets = options.include_targets;
+ const bool include_modules = options.include_modules;
const bool include_transcript = options.include_transcript;
json::Array json_targets;
@@ -347,13 +349,15 @@ llvm::json::Value DebuggerStats::ReportStatistics(
{"totalSymbolTableStripped", num_stripped_modules},
};
- if (target) {
- json_targets.emplace_back(target->ReportStatistics(options));
- } else {
- for (const auto &target : debugger.GetTargetList().Targets())
+ if (!summary_only || include_targets) {
+ if (target) {
json_targets.emplace_back(target->ReportStatistics(options));
+ } else {
+ for (const auto &target : debugger.GetTargetList().Targets())
+ json_targets.emplace_back(target->ReportStatistics(options));
+ }
+ global_stats.try_emplace("targets", std::move(json_targets));
}
- global_stats.try_emplace("targets", std::move(json_targets));
ConstStringStats const_string_stats;
json::Object json_memory{
@@ -362,11 +366,14 @@ llvm::json::Value DebuggerStats::ReportStatistics(
global_stats.try_emplace("memory", std::move(json_memory));
if (!summary_only) {
json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();
- global_stats.try_emplace("modules", std::move(json_modules));
global_stats.try_emplace("commands", std::move(cmd_stats));
}
- if (include_transcript) {
+ if (!summary_only || include_modules) {
+ global_stats.try_emplace("modules", std::move(json_modules));
+ }
+
+ if (!summary_only || include_transcript) {
// When transcript is available, add it to the to-be-returned statistics.
//
// NOTE:
>From abfa4fd52f059f9500b223d43bfe50829ad376f2 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Mon, 10 Jun 2024 17:04:11 -0700
Subject: [PATCH 02/19] Add --targets and --modules option to statistics dump
---
lldb/include/lldb/Target/Statistics.h | 2 +
lldb/source/Commands/CommandObjectStats.cpp | 6 ++
lldb/source/Commands/Options.td | 16 ++-
lldb/source/Target/Statistics.cpp | 33 ++++--
.../commands/statistics/basic/TestStats.py | 102 ++++++++++++++++--
5 files changed, 140 insertions(+), 19 deletions(-)
diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index c04d529290fff..b24520b72a95d 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -133,6 +133,8 @@ struct ConstStringStats {
struct StatisticsOptions {
bool summary_only = false;
bool load_all_debug_info = false;
+ bool include_targets = false;
+ bool include_modules = false;
bool include_transcript = false;
};
diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp
index 1935b0fdfadfb..1347b1ba25b1d 100644
--- a/lldb/source/Commands/CommandObjectStats.cpp
+++ b/lldb/source/Commands/CommandObjectStats.cpp
@@ -81,6 +81,12 @@ class CommandObjectStatsDump : public CommandObjectParsed {
case 'f':
m_stats_options.load_all_debug_info = true;
break;
+ case 'r':
+ m_stats_options.include_targets = true;
+ break;
+ case 'm':
+ m_stats_options.include_modules = true;
+ break;
case 't':
m_stats_options.include_transcript = true;
break;
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index cee5a81d3796b..45f46334d5c73 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1416,16 +1416,26 @@ let Command = "trace schema" in {
}
let Command = "statistics dump" in {
- def statistics_dump_all: Option<"all-targets", "a">, Group<1>,
+ def statistics_dump_all: Option<"all-targets", "a">, GroupRange<1, 2>,
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.">;
- def statistics_dump_force: Option<"load-all-debug-info", "f">, Group<1>,
+ def statistics_dump_force: Option<"load-all-debug-info", "f">, GroupRange<1, 2>,
Desc<"Dump the total possible debug info statistics. "
"Force loading all the debug information if not yet loaded, and collect "
"statistics with those.">;
- def statistics_dump_transcript: Option<"transcript", "t">, Group<1>,
+ def statistics_dump_targets: Option<"targets", "r">, Group<2>,
+ Desc<"Dump statistics for the targets, including breakpoints, expression "
+ "evaluations, frame variables, etc. "
+ "If both the '--targets' and the '--modules' options are specified, a "
+ "list of module identifiers will be added to the 'targets' section.">;
+ def statistics_dump_modules: Option<"modules", "m">, Group<2>,
+ Desc<"Dump statistics for the modules, including time and size of various "
+ "aspects of the module and debug information, type system, path, etc. "
+ "If both the '--targets' and the '--modules' options are specified, a "
+ "list of module identifiers will be added to the 'targets' section.">;
+ def statistics_dump_transcript: Option<"transcript", "t">, Group<2>,
Desc<"If the setting interpreter.save-transcript is enabled and this "
"option is specified, include a JSON array with all commands the user and/"
"or scripts executed during a debug session.">;
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 2a5300012511a..15c7dfe07ac87 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -108,6 +108,10 @@ TargetStats::ToJSON(Target &target,
json::Object target_metrics_json;
ProcessSP process_sp = target.GetProcessSP();
const bool summary_only = options.summary_only;
+ const bool include_targets = options.include_targets;
+ const bool include_modules = options.include_modules;
+ const bool include_transcript = options.include_transcript;
+ const bool include_default_sections = !summary_only && !include_targets && !include_modules && !include_transcript;
if (!summary_only) {
CollectStats(target);
@@ -117,8 +121,9 @@ TargetStats::ToJSON(Target &target,
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 (include_default_sections || include_modules)
+ 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 =
@@ -226,7 +231,10 @@ llvm::json::Value DebuggerStats::ReportStatistics(
const bool summary_only = options.summary_only;
const bool load_all_debug_info = options.load_all_debug_info;
+ const bool include_targets = options.include_targets;
+ const bool include_modules = options.include_modules;
const bool include_transcript = options.include_transcript;
+ const bool include_default_sections = !summary_only && !include_targets && !include_modules && !include_transcript;
json::Array json_targets;
json::Array json_modules;
@@ -314,7 +322,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
if (module_stat.debug_info_had_incomplete_types)
++num_modules_with_incomplete_types;
- if (!summary_only) {
+ if (include_default_sections || include_modules) {
module_stat.identifier = (intptr_t)module;
module_stat.path = module->GetFileSpec().GetPath();
if (ConstString object_name = module->GetObjectName()) {
@@ -347,13 +355,15 @@ llvm::json::Value DebuggerStats::ReportStatistics(
{"totalSymbolTableStripped", num_stripped_modules},
};
- if (target) {
- json_targets.emplace_back(target->ReportStatistics(options));
- } else {
- for (const auto &target : debugger.GetTargetList().Targets())
+ if (include_default_sections || include_targets) {
+ if (target) {
json_targets.emplace_back(target->ReportStatistics(options));
+ } else {
+ for (const auto &target : debugger.GetTargetList().Targets())
+ json_targets.emplace_back(target->ReportStatistics(options));
+ }
+ global_stats.try_emplace("targets", std::move(json_targets));
}
- global_stats.try_emplace("targets", std::move(json_targets));
ConstStringStats const_string_stats;
json::Object json_memory{
@@ -362,11 +372,14 @@ llvm::json::Value DebuggerStats::ReportStatistics(
global_stats.try_emplace("memory", std::move(json_memory));
if (!summary_only) {
json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();
- global_stats.try_emplace("modules", std::move(json_modules));
global_stats.try_emplace("commands", std::move(cmd_stats));
}
- if (include_transcript) {
+ if (include_default_sections || include_modules) {
+ global_stats.try_emplace("modules", std::move(json_modules));
+ }
+
+ if (include_default_sections || include_transcript) {
// When transcript is available, add it to the to-be-returned statistics.
//
// NOTE:
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py
index ebe6166eb45e5..2132d2df03b4b 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -657,16 +657,106 @@ def test_transcript_happy_path(self):
# The second "statistics dump" in the transcript should have no output
self.assertNotIn("output", transcript[2])
- def test_transcript_should_not_exist_when_not_asked_for(self):
+ def test_sections_existence(self):
"""
- Test "statistics dump" and the transcript information.
+ Test "statistics dump" and the existence of sections when different
+ options are given.
"""
self.build()
exe = self.getBuildArtifact("a.out")
target = self.createTestTarget(file_path=exe)
self.runCmd("settings set interpreter.save-transcript true")
- self.runCmd("version")
- # Verify the output of a first "statistics dump"
- debug_stats = self.get_stats() # Not with "--transcript"
- self.assertNotIn("transcript", debug_stats)
+ test_cases = [
+ { # statistics dump
+ "options": "",
+ "expect": {
+ "commands": True,
+ "targets": True,
+ "targets.moduleIdentifiers": True,
+ "targets.breakpoints": True,
+ "modules": True,
+ "transcript": True,
+ },
+ },
+ { # statistics dump --summary
+ "options": " --summary",
+ "expect": {
+ "commands": False,
+ "targets": False,
+ "targets.moduleIdentifiers": False,
+ "targets.breakpoints": False,
+ "modules": False,
+ "transcript": False,
+ },
+ },
+ { # statistics dump --targets
+ "options": " --targets",
+ "expect": {
+ "commands": True,
+ "targets": True,
+ "targets.moduleIdentifiers": False,
+ "targets.breakpoints": True,
+ "modules": False,
+ "transcript": False,
+ },
+ },
+ { # statistics dump --modules
+ "options": " --modules",
+ "expect": {
+ "commands": True,
+ "targets": False,
+ "targets.moduleIdentifiers": False,
+ "targets.breakpoints": False,
+ "modules": True,
+ "transcript": False,
+ },
+ },
+ { # statistics dump --targets --modules
+ "options": " --targets --modules",
+ "expect": {
+ "commands": True,
+ "targets": True,
+ "targets.moduleIdentifiers": True,
+ "targets.breakpoints": True,
+ "modules": True,
+ "transcript": False,
+ },
+ },
+ { # statistics dump --transcript
+ "options": " --transcript",
+ "expect": {
+ "commands": True,
+ "targets": False,
+ "targets.moduleIdentifiers": False,
+ "targets.breakpoints": False,
+ "modules": False,
+ "transcript": True,
+ },
+ },
+ ]
+
+ for test_case in test_cases:
+ options = test_case["options"]
+ debug_stats = self.get_stats(options)
+ # The following fields should always exist
+ self.assertIn("totalDebugInfoEnabled", debug_stats, "Global stats should always exist")
+ self.assertIn("memory", debug_stats, "'memory' should always exist")
+ # The following fields should exist/not exist depending on the test case
+ for field_name in test_case["expect"]:
+ idx = field_name.find(".")
+ if idx == -1:
+ # `field` is a top-level field
+ exists = field_name in debug_stats
+ should_exist = test_case["expect"][field_name]
+ should_exist_string = "" if should_exist else "not "
+ self.assertEqual(exists, should_exist, f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'")
+ else:
+ # `field` is a string of "<top-level field>.<second-level field>"
+ top_level_field_name = field_name[0:idx]
+ second_level_field_name = field_name[idx+1:]
+ for top_level_field in debug_stats[top_level_field_name] if top_level_field_name in debug_stats else []:
+ exists = second_level_field_name in top_level_field
+ should_exist = test_case["expect"][field_name]
+ should_exist_string = "" if should_exist else "not "
+ self.assertEqual(exists, should_exist, f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'")
>From 358497da7fb85394aceca4a14ea55e7649e5d4db Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Mon, 10 Jun 2024 21:54:40 -0700
Subject: [PATCH 03/19] Fix C++ format
---
lldb/source/Target/Statistics.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 15c7dfe07ac87..bbb556925eb1f 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -111,7 +111,8 @@ TargetStats::ToJSON(Target &target,
const bool include_targets = options.include_targets;
const bool include_modules = options.include_modules;
const bool include_transcript = options.include_transcript;
- const bool include_default_sections = !summary_only && !include_targets && !include_modules && !include_transcript;
+ const bool include_default_sections = !summary_only && !include_targets &&
+ !include_modules && !include_transcript;
if (!summary_only) {
CollectStats(target);
@@ -234,7 +235,8 @@ llvm::json::Value DebuggerStats::ReportStatistics(
const bool include_targets = options.include_targets;
const bool include_modules = options.include_modules;
const bool include_transcript = options.include_transcript;
- const bool include_default_sections = !summary_only && !include_targets && !include_modules && !include_transcript;
+ const bool include_default_sections = !summary_only && !include_targets &&
+ !include_modules && !include_transcript;
json::Array json_targets;
json::Array json_modules;
>From 32e51e0e4f1debfc3338af8a8f226f02ec7187f7 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Mon, 10 Jun 2024 21:55:44 -0700
Subject: [PATCH 04/19] Fix python format
---
.../commands/statistics/basic/TestStats.py | 36 +++++++++++++------
1 file changed, 25 insertions(+), 11 deletions(-)
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py
index 2132d2df03b4b..db254e36c4b6c 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -668,7 +668,7 @@ def test_sections_existence(self):
self.runCmd("settings set interpreter.save-transcript true")
test_cases = [
- { # statistics dump
+ { # statistics dump
"options": "",
"expect": {
"commands": True,
@@ -679,7 +679,7 @@ def test_sections_existence(self):
"transcript": True,
},
},
- { # statistics dump --summary
+ { # statistics dump --summary
"options": " --summary",
"expect": {
"commands": False,
@@ -690,7 +690,7 @@ def test_sections_existence(self):
"transcript": False,
},
},
- { # statistics dump --targets
+ { # statistics dump --targets
"options": " --targets",
"expect": {
"commands": True,
@@ -701,7 +701,7 @@ def test_sections_existence(self):
"transcript": False,
},
},
- { # statistics dump --modules
+ { # statistics dump --modules
"options": " --modules",
"expect": {
"commands": True,
@@ -712,7 +712,7 @@ def test_sections_existence(self):
"transcript": False,
},
},
- { # statistics dump --targets --modules
+ { # statistics dump --targets --modules
"options": " --targets --modules",
"expect": {
"commands": True,
@@ -723,7 +723,7 @@ def test_sections_existence(self):
"transcript": False,
},
},
- { # statistics dump --transcript
+ { # statistics dump --transcript
"options": " --transcript",
"expect": {
"commands": True,
@@ -740,7 +740,9 @@ def test_sections_existence(self):
options = test_case["options"]
debug_stats = self.get_stats(options)
# The following fields should always exist
- self.assertIn("totalDebugInfoEnabled", debug_stats, "Global stats should always exist")
+ self.assertIn(
+ "totalDebugInfoEnabled", debug_stats, "Global stats should always exist"
+ )
self.assertIn("memory", debug_stats, "'memory' should always exist")
# The following fields should exist/not exist depending on the test case
for field_name in test_case["expect"]:
@@ -750,13 +752,25 @@ def test_sections_existence(self):
exists = field_name in debug_stats
should_exist = test_case["expect"][field_name]
should_exist_string = "" if should_exist else "not "
- self.assertEqual(exists, should_exist, f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'")
+ self.assertEqual(
+ exists,
+ should_exist,
+ f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'",
+ )
else:
# `field` is a string of "<top-level field>.<second-level field>"
top_level_field_name = field_name[0:idx]
- second_level_field_name = field_name[idx+1:]
- for top_level_field in debug_stats[top_level_field_name] if top_level_field_name in debug_stats else []:
+ second_level_field_name = field_name[idx + 1 :]
+ for top_level_field in (
+ debug_stats[top_level_field_name]
+ if top_level_field_name in debug_stats
+ else []
+ ):
exists = second_level_field_name in top_level_field
should_exist = test_case["expect"][field_name]
should_exist_string = "" if should_exist else "not "
- self.assertEqual(exists, should_exist, f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'")
+ self.assertEqual(
+ exists,
+ should_exist,
+ f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'",
+ )
>From a8fc16d5f31fd45258b5b7f950cd080a9d83680a Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Mon, 10 Jun 2024 22:10:00 -0700
Subject: [PATCH 05/19] Add options into SBStatisticsOptions
---
lldb/include/lldb/API/SBStatisticsOptions.h | 9 ++++++++
lldb/source/API/SBStatisticsOptions.cpp | 24 +++++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/lldb/include/lldb/API/SBStatisticsOptions.h b/lldb/include/lldb/API/SBStatisticsOptions.h
index a0055135e36c2..35ebe3db1c53b 100644
--- a/lldb/include/lldb/API/SBStatisticsOptions.h
+++ b/lldb/include/lldb/API/SBStatisticsOptions.h
@@ -25,6 +25,15 @@ class LLDB_API SBStatisticsOptions {
void SetSummaryOnly(bool b);
bool GetSummaryOnly();
+ void SetIncludeTargets(bool b);
+ bool GetIncludeTargets() const;
+
+ void SetIncludeModules(bool b);
+ bool GetIncludeModules() const;
+
+ void SetIncludeTranscript(bool b);
+ bool GetIncludeTranscript() const;
+
/// If set to true, the debugger will load all debug info that is available
/// and report statistics on the total amount. If this is set to false, then
/// only report statistics on the currently loaded debug information.
diff --git a/lldb/source/API/SBStatisticsOptions.cpp b/lldb/source/API/SBStatisticsOptions.cpp
index 7e826c4c93ebc..7cf8664955ae7 100644
--- a/lldb/source/API/SBStatisticsOptions.cpp
+++ b/lldb/source/API/SBStatisticsOptions.cpp
@@ -44,6 +44,30 @@ void SBStatisticsOptions::SetSummaryOnly(bool b) {
bool SBStatisticsOptions::GetSummaryOnly() { return m_opaque_up->summary_only; }
+void SBStatisticsOptions::SetIncludeTargets(bool b) {
+ m_opaque_up->include_targets = b;
+}
+
+bool SBStatisticsOptions::GetIncludeTargets() const {
+ return m_opaque_up->include_targets;
+}
+
+void SBStatisticsOptions::SetIncludeModules(bool b) {
+ m_opaque_up->include_modules = b;
+}
+
+bool SBStatisticsOptions::GetIncludeModules() const {
+ return m_opaque_up->include_modules;
+}
+
+void SBStatisticsOptions::SetIncludeTranscript(bool b) {
+ m_opaque_up->include_transcript = b;
+}
+
+bool SBStatisticsOptions::GetIncludeTranscript() const {
+ return m_opaque_up->include_transcript;
+}
+
void SBStatisticsOptions::SetReportAllAvailableDebugInfo(bool b) {
m_opaque_up->load_all_debug_info = b;
}
>From fb0108c7e78692bf5f919daf4fe48045e4397357 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Thu, 13 Jun 2024 16:45:00 -0700
Subject: [PATCH 06/19] Reframe the options by composition
---
.../lldb/Interpreter/OptionArgParser.h | 2 +
lldb/include/lldb/Interpreter/Options.h | 2 +-
lldb/include/lldb/Target/Statistics.h | 6 +-
lldb/source/Commands/CommandObjectStats.cpp | 19 ++-
lldb/source/Commands/Options.td | 13 +-
lldb/source/Interpreter/OptionArgParser.cpp | 13 ++
lldb/source/Interpreter/Options.cpp | 1 +
lldb/source/Target/Statistics.cpp | 16 +--
.../commands/statistics/basic/TestStats.py | 113 +++++++++++++-----
9 files changed, 133 insertions(+), 52 deletions(-)
diff --git a/lldb/include/lldb/Interpreter/OptionArgParser.h b/lldb/include/lldb/Interpreter/OptionArgParser.h
index 66b16112fce96..9bae7674ea2f1 100644
--- a/lldb/include/lldb/Interpreter/OptionArgParser.h
+++ b/lldb/include/lldb/Interpreter/OptionArgParser.h
@@ -29,6 +29,8 @@ struct OptionArgParser {
static bool ToBoolean(llvm::StringRef s, bool fail_value, bool *success_ptr);
+ static bool ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg, bool fail_value, Status &error);
+
static char ToChar(llvm::StringRef s, char fail_value, bool *success_ptr);
static int64_t ToOptionEnum(llvm::StringRef s,
diff --git a/lldb/include/lldb/Interpreter/Options.h b/lldb/include/lldb/Interpreter/Options.h
index 9a6a17c2793fa..a95111262c25f 100644
--- a/lldb/include/lldb/Interpreter/Options.h
+++ b/lldb/include/lldb/Interpreter/Options.h
@@ -217,7 +217,7 @@ class Options {
void OptionsSetUnion(const OptionSet &set_a, const OptionSet &set_b,
OptionSet &union_set);
-
+
// Subclasses must reset their option values prior to starting a new option
// parse. Each subclass must override this function and revert all option
// settings to default values.
diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index b24520b72a95d..268de2f1d9686 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -133,9 +133,9 @@ struct ConstStringStats {
struct StatisticsOptions {
bool summary_only = false;
bool load_all_debug_info = false;
- bool include_targets = false;
- bool include_modules = false;
- bool include_transcript = false;
+ bool include_targets = true;
+ bool include_modules = true;
+ bool include_transcript = true;
};
/// A class that represents statistics for a since lldb_private::Target.
diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp
index 1347b1ba25b1d..929a79180070f 100644
--- a/lldb/source/Commands/CommandObjectStats.cpp
+++ b/lldb/source/Commands/CommandObjectStats.cpp
@@ -11,6 +11,7 @@
#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Target/Target.h"
using namespace lldb;
@@ -77,18 +78,30 @@ class CommandObjectStatsDump : public CommandObjectParsed {
break;
case 's':
m_stats_options.summary_only = true;
+ // In the "summary" mode, the following sections should be omitted by
+ // default unless their corresponding options are explicitly given.
+ // If such options were processed before 's', `m_seen_options` should
+ // contain them, and we will skip setting them to `false` here. If such
+ // options are not yet processed, we will set them to `false` here, and
+ // they will be overwritten when the options are processed.
+ if (m_seen_options.find((int)'r') == m_seen_options.end())
+ m_stats_options.include_targets = false;
+ if (m_seen_options.find((int)'m') == m_seen_options.end())
+ m_stats_options.include_modules = false;
+ if (m_seen_options.find((int)'t') == m_seen_options.end())
+ m_stats_options.include_transcript = false;
break;
case 'f':
m_stats_options.load_all_debug_info = true;
break;
case 'r':
- m_stats_options.include_targets = true;
+ m_stats_options.include_targets = OptionArgParser::ToBoolean("--targets", option_arg, true /* doesn't matter */, error);
break;
case 'm':
- m_stats_options.include_modules = true;
+ m_stats_options.include_modules = OptionArgParser::ToBoolean("--modules", option_arg, true /* doesn't matter */, error);
break;
case 't':
- m_stats_options.include_transcript = true;
+ m_stats_options.include_transcript = OptionArgParser::ToBoolean("--transcript", option_arg, true /* doesn't matter */, error);
break;
default:
llvm_unreachable("Unimplemented option");
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 45f46334d5c73..b7e8fa22cdaa4 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1416,26 +1416,29 @@ let Command = "trace schema" in {
}
let Command = "statistics dump" in {
- def statistics_dump_all: Option<"all-targets", "a">, GroupRange<1, 2>,
+ 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.">;
- def statistics_dump_force: Option<"load-all-debug-info", "f">, GroupRange<1, 2>,
+ def statistics_dump_force: Option<"load-all-debug-info", "f">, Group<1>,
Desc<"Dump the total possible debug info statistics. "
"Force loading all the debug information if not yet loaded, and collect "
"statistics with those.">;
- def statistics_dump_targets: Option<"targets", "r">, Group<2>,
+ def statistics_dump_targets: Option<"targets", "r">, Group<1>,
+ Arg<"Boolean">,
Desc<"Dump statistics for the targets, including breakpoints, expression "
"evaluations, frame variables, etc. "
"If both the '--targets' and the '--modules' options are specified, a "
"list of module identifiers will be added to the 'targets' section.">;
- def statistics_dump_modules: Option<"modules", "m">, Group<2>,
+ def statistics_dump_modules: Option<"modules", "m">, Group<1>,
+ Arg<"Boolean">,
Desc<"Dump statistics for the modules, including time and size of various "
"aspects of the module and debug information, type system, path, etc. "
"If both the '--targets' and the '--modules' options are specified, a "
"list of module identifiers will be added to the 'targets' section.">;
- def statistics_dump_transcript: Option<"transcript", "t">, Group<2>,
+ def statistics_dump_transcript: Option<"transcript", "t">, Group<1>,
+ Arg<"Boolean">,
Desc<"If the setting interpreter.save-transcript is enabled and this "
"option is specified, include a JSON array with all commands the user and/"
"or scripts executed during a debug session.">;
diff --git a/lldb/source/Interpreter/OptionArgParser.cpp b/lldb/source/Interpreter/OptionArgParser.cpp
index 9a8275128ede9..963828d6bdda1 100644
--- a/lldb/source/Interpreter/OptionArgParser.cpp
+++ b/lldb/source/Interpreter/OptionArgParser.cpp
@@ -35,6 +35,19 @@ bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value,
return fail_value;
}
+bool OptionArgParser::ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg, bool fail_value, Status &error)
+{
+ bool parse_success;
+ const bool arg_value =
+ ToBoolean(option_arg, fail_value, &parse_success);
+ if (!parse_success)
+ error.SetErrorStringWithFormat(
+ "Invalid boolean value for option '%s': '%s'",
+ option_name.str().c_str(),
+ option_arg.empty() ? "<null>" : option_arg.str().c_str());
+ return arg_value;
+}
+
char OptionArgParser::ToChar(llvm::StringRef s, char fail_value,
bool *success_ptr) {
if (success_ptr)
diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp
index 4e7d074ace1b8..65d95013fc903 100644
--- a/lldb/source/Interpreter/Options.cpp
+++ b/lldb/source/Interpreter/Options.cpp
@@ -18,6 +18,7 @@
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/STLExtras.h"
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index bbb556925eb1f..716f80a7fd6bb 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -108,11 +108,7 @@ TargetStats::ToJSON(Target &target,
json::Object target_metrics_json;
ProcessSP process_sp = target.GetProcessSP();
const bool summary_only = options.summary_only;
- const bool include_targets = options.include_targets;
const bool include_modules = options.include_modules;
- const bool include_transcript = options.include_transcript;
- const bool include_default_sections = !summary_only && !include_targets &&
- !include_modules && !include_transcript;
if (!summary_only) {
CollectStats(target);
@@ -122,7 +118,7 @@ TargetStats::ToJSON(Target &target,
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());
- if (include_default_sections || include_modules)
+ if (include_modules)
target_metrics_json.try_emplace("moduleIdentifiers",
std::move(json_module_uuid_array));
@@ -235,8 +231,6 @@ llvm::json::Value DebuggerStats::ReportStatistics(
const bool include_targets = options.include_targets;
const bool include_modules = options.include_modules;
const bool include_transcript = options.include_transcript;
- const bool include_default_sections = !summary_only && !include_targets &&
- !include_modules && !include_transcript;
json::Array json_targets;
json::Array json_modules;
@@ -324,7 +318,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
if (module_stat.debug_info_had_incomplete_types)
++num_modules_with_incomplete_types;
- if (include_default_sections || include_modules) {
+ if (include_modules) {
module_stat.identifier = (intptr_t)module;
module_stat.path = module->GetFileSpec().GetPath();
if (ConstString object_name = module->GetObjectName()) {
@@ -357,7 +351,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
{"totalSymbolTableStripped", num_stripped_modules},
};
- if (include_default_sections || include_targets) {
+ if (include_targets) {
if (target) {
json_targets.emplace_back(target->ReportStatistics(options));
} else {
@@ -377,11 +371,11 @@ llvm::json::Value DebuggerStats::ReportStatistics(
global_stats.try_emplace("commands", std::move(cmd_stats));
}
- if (include_default_sections || include_modules) {
+ if (include_modules) {
global_stats.try_emplace("modules", std::move(json_modules));
}
- if (include_default_sections || include_transcript) {
+ if (include_transcript) {
// When transcript is available, add it to the to-be-returned statistics.
//
// NOTE:
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py
index db254e36c4b6c..f19ec89bfe777 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -1,6 +1,7 @@
import lldb
import json
import os
+import re
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
@@ -635,7 +636,7 @@ def test_transcript_happy_path(self):
self.runCmd("version")
# Verify the output of a first "statistics dump"
- debug_stats = self.get_stats("--transcript")
+ debug_stats = self.get_stats("--transcript true")
self.assertIn("transcript", debug_stats)
transcript = debug_stats["transcript"]
self.assertEqual(len(transcript), 2)
@@ -645,7 +646,7 @@ def test_transcript_happy_path(self):
self.assertNotIn("output", transcript[1])
# Verify the output of a second "statistics dump"
- debug_stats = self.get_stats("--transcript")
+ debug_stats = self.get_stats("--transcript true")
self.assertIn("transcript", debug_stats)
transcript = debug_stats["transcript"]
self.assertEqual(len(transcript), 3)
@@ -665,92 +666,107 @@ def test_sections_existence(self):
self.build()
exe = self.getBuildArtifact("a.out")
target = self.createTestTarget(file_path=exe)
- self.runCmd("settings set interpreter.save-transcript true")
+ # Create some transcript so that it can be tested.
+ self.runCmd("settings set interpreter.save-transcript true")
+ self.runCmd("version")
+ self.runCmd("b main")
+ # But disable transcript so that it won't change during verification
+ self.runCmd("settings set interpreter.save-transcript false")
+
+ # Expectation
+ should_always_exist_or_not = {
+ "totalDebugInfoEnabled": True,
+ "memory": True,
+ }
test_cases = [
- { # statistics dump
+ { # Everything mode
"options": "",
"expect": {
"commands": True,
"targets": True,
"targets.moduleIdentifiers": True,
"targets.breakpoints": True,
+ "targets.expressionEvaluation": True,
"modules": True,
"transcript": True,
},
},
- { # statistics dump --summary
+ { # Summary mode
"options": " --summary",
"expect": {
"commands": False,
"targets": False,
"targets.moduleIdentifiers": False,
"targets.breakpoints": False,
+ "targets.expressionEvaluation": False,
"modules": False,
"transcript": False,
},
},
- { # statistics dump --targets
- "options": " --targets",
+ { # Summary mode with targets
+ "options": " --summary --targets=true",
"expect": {
- "commands": True,
+ "commands": False,
"targets": True,
"targets.moduleIdentifiers": False,
- "targets.breakpoints": True,
+ "targets.breakpoints": False,
+ "targets.expressionEvaluation": False,
+ "targets.totalSharedLibraryEventHitCount": True,
"modules": False,
"transcript": False,
},
},
- { # statistics dump --modules
- "options": " --modules",
+ { # Summary mode with modules
+ "options": " --summary --modules=true",
"expect": {
- "commands": True,
+ "commands": False,
"targets": False,
"targets.moduleIdentifiers": False,
"targets.breakpoints": False,
+ "targets.expressionEvaluation": True,
"modules": True,
"transcript": False,
},
},
- { # statistics dump --targets --modules
- "options": " --targets --modules",
+ { # Everything mode but without modules and transcript
+ "options": " --modules=false --transcript=false",
"expect": {
"commands": True,
"targets": True,
- "targets.moduleIdentifiers": True,
+ "targets.moduleIdentifiers": False,
"targets.breakpoints": True,
- "modules": True,
+ "targets.expressionEvaluation": True,
+ "modules": False,
"transcript": False,
},
},
- { # statistics dump --transcript
- "options": " --transcript",
+ { # Everything mode but without modules
+ "options": " --modules=false",
"expect": {
"commands": True,
- "targets": False,
+ "targets": True,
"targets.moduleIdentifiers": False,
- "targets.breakpoints": False,
+ "targets.breakpoints": True,
+ "targets.expressionEvaluation": True,
"modules": False,
"transcript": True,
},
},
]
+ # Verification
for test_case in test_cases:
options = test_case["options"]
debug_stats = self.get_stats(options)
- # The following fields should always exist
- self.assertIn(
- "totalDebugInfoEnabled", debug_stats, "Global stats should always exist"
- )
- self.assertIn("memory", debug_stats, "'memory' should always exist")
- # The following fields should exist/not exist depending on the test case
- for field_name in test_case["expect"]:
+ # Verify that each field should exist (or not)
+ expectation = {**should_always_exist_or_not, **test_case["expect"]}
+ for field_name in expectation:
idx = field_name.find(".")
if idx == -1:
# `field` is a top-level field
exists = field_name in debug_stats
- should_exist = test_case["expect"][field_name]
+ should_exist = expectation[field_name]
should_exist_string = "" if should_exist else "not "
self.assertEqual(
exists,
@@ -767,10 +783,49 @@ def test_sections_existence(self):
else []
):
exists = second_level_field_name in top_level_field
- should_exist = test_case["expect"][field_name]
+ should_exist = expectation[field_name]
should_exist_string = "" if should_exist else "not "
self.assertEqual(
exists,
should_exist,
f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'",
)
+
+ def test_order_of_options_do_not_matter(self):
+ """
+ Test "statistics dump" and the order of options.
+ """
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ target = self.createTestTarget(file_path=exe)
+
+ # Create some transcript so that it can be tested.
+ self.runCmd("settings set interpreter.save-transcript true")
+ self.runCmd("version")
+ self.runCmd("b main")
+ # But disable transcript so that it won't change during verification
+ self.runCmd("settings set interpreter.save-transcript false")
+
+ # The order of the following options shouldn't matter
+ test_cases = [
+ (" --summary", " --targets=true"),
+ (" --summary", " --targets=false"),
+ (" --summary", " --modules=true"),
+ (" --summary", " --modules=false"),
+ (" --summary", " --transcript=true"),
+ (" --summary", " --transcript=false"),
+ ]
+
+ # Verification
+ for options in test_cases:
+ debug_stats_0 = self.get_stats(options[0] + options[1])
+ debug_stats_1 = self.get_stats(options[1] + options[0])
+ # Redact all numbers
+ debug_stats_0 = re.sub(r"\d+", "0", json.dumps(debug_stats_0))
+ debug_stats_1 = re.sub(r"\d+", "0", json.dumps(debug_stats_1))
+ # Verify that the two output are the same
+ self.assertEqual(
+ debug_stats_0,
+ debug_stats_1,
+ f"The order of options '{options[0]}' and '{options[1]}' should not matter",
+ )
>From 111ee64a5935dac64d71688280540834213043e6 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Thu, 13 Jun 2024 16:51:28 -0700
Subject: [PATCH 07/19] Fix format
---
lldb/include/lldb/Interpreter/OptionArgParser.h | 3 ++-
lldb/include/lldb/Interpreter/Options.h | 2 +-
lldb/source/Commands/CommandObjectStats.cpp | 9 ++++++---
lldb/source/Interpreter/OptionArgParser.cpp | 8 ++++----
4 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/lldb/include/lldb/Interpreter/OptionArgParser.h b/lldb/include/lldb/Interpreter/OptionArgParser.h
index 9bae7674ea2f1..af20cd258aff3 100644
--- a/lldb/include/lldb/Interpreter/OptionArgParser.h
+++ b/lldb/include/lldb/Interpreter/OptionArgParser.h
@@ -29,7 +29,8 @@ struct OptionArgParser {
static bool ToBoolean(llvm::StringRef s, bool fail_value, bool *success_ptr);
- static bool ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg, bool fail_value, Status &error);
+ static bool ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg,
+ bool fail_value, Status &error);
static char ToChar(llvm::StringRef s, char fail_value, bool *success_ptr);
diff --git a/lldb/include/lldb/Interpreter/Options.h b/lldb/include/lldb/Interpreter/Options.h
index a95111262c25f..9a6a17c2793fa 100644
--- a/lldb/include/lldb/Interpreter/Options.h
+++ b/lldb/include/lldb/Interpreter/Options.h
@@ -217,7 +217,7 @@ class Options {
void OptionsSetUnion(const OptionSet &set_a, const OptionSet &set_b,
OptionSet &union_set);
-
+
// Subclasses must reset their option values prior to starting a new option
// parse. Each subclass must override this function and revert all option
// settings to default values.
diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp
index 929a79180070f..b093c6607d5d8 100644
--- a/lldb/source/Commands/CommandObjectStats.cpp
+++ b/lldb/source/Commands/CommandObjectStats.cpp
@@ -95,13 +95,16 @@ class CommandObjectStatsDump : public CommandObjectParsed {
m_stats_options.load_all_debug_info = true;
break;
case 'r':
- m_stats_options.include_targets = OptionArgParser::ToBoolean("--targets", option_arg, true /* doesn't matter */, error);
+ m_stats_options.include_targets = OptionArgParser::ToBoolean(
+ "--targets", option_arg, true /* doesn't matter */, error);
break;
case 'm':
- m_stats_options.include_modules = OptionArgParser::ToBoolean("--modules", option_arg, true /* doesn't matter */, error);
+ m_stats_options.include_modules = OptionArgParser::ToBoolean(
+ "--modules", option_arg, true /* doesn't matter */, error);
break;
case 't':
- m_stats_options.include_transcript = OptionArgParser::ToBoolean("--transcript", option_arg, true /* doesn't matter */, error);
+ m_stats_options.include_transcript = OptionArgParser::ToBoolean(
+ "--transcript", option_arg, true /* doesn't matter */, error);
break;
default:
llvm_unreachable("Unimplemented option");
diff --git a/lldb/source/Interpreter/OptionArgParser.cpp b/lldb/source/Interpreter/OptionArgParser.cpp
index 963828d6bdda1..978032807ebd1 100644
--- a/lldb/source/Interpreter/OptionArgParser.cpp
+++ b/lldb/source/Interpreter/OptionArgParser.cpp
@@ -35,11 +35,11 @@ bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value,
return fail_value;
}
-bool OptionArgParser::ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg, bool fail_value, Status &error)
-{
+bool OptionArgParser::ToBoolean(llvm::StringRef option_name,
+ llvm::StringRef option_arg, bool fail_value,
+ Status &error) {
bool parse_success;
- const bool arg_value =
- ToBoolean(option_arg, fail_value, &parse_success);
+ const bool arg_value = ToBoolean(option_arg, fail_value, &parse_success);
if (!parse_success)
error.SetErrorStringWithFormat(
"Invalid boolean value for option '%s': '%s'",
>From 140feac7a63b05e99b90767f321cd283b2c448a4 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Thu, 13 Jun 2024 17:14:22 -0700
Subject: [PATCH 08/19] Fix option descriptions
---
lldb/source/Commands/Options.td | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index b7e8fa22cdaa4..dffaf525ef052 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1429,17 +1429,17 @@ let Command = "statistics dump" in {
Arg<"Boolean">,
Desc<"Dump statistics for the targets, including breakpoints, expression "
"evaluations, frame variables, etc. "
- "If both the '--targets' and the '--modules' options are specified, a "
- "list of module identifiers will be added to the 'targets' section.">;
+ "If both the '--targets' and the '--modules' options are 'true', a list "
+ "of module identifiers will be added to the 'targets' section.">;
def statistics_dump_modules: Option<"modules", "m">, Group<1>,
Arg<"Boolean">,
Desc<"Dump statistics for the modules, including time and size of various "
"aspects of the module and debug information, type system, path, etc. "
- "If both the '--targets' and the '--modules' options are specified, a "
- "list of module identifiers will be added to the 'targets' section.">;
+ "If both the '--targets' and the '--modules' options are 'true', a list "
+ "of module identifiers will be added to the 'targets' section.">;
def statistics_dump_transcript: Option<"transcript", "t">, Group<1>,
Arg<"Boolean">,
Desc<"If the setting interpreter.save-transcript is enabled and this "
- "option is specified, include a JSON array with all commands the user and/"
- "or scripts executed during a debug session.">;
+ "option is 'true', include a JSON array with all commands the user and/or "
+ "scripts executed during a debug session.">;
}
>From 1d9f8aa016133c644cd4979bb64289f9b42d2d31 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Thu, 13 Jun 2024 17:26:42 -0700
Subject: [PATCH 09/19] Add unittest for the new function
OptionArgParser::ToBoolean
---
.../Interpreter/TestOptionArgParser.cpp | 79 ++++++++-----------
1 file changed, 31 insertions(+), 48 deletions(-)
diff --git a/lldb/unittests/Interpreter/TestOptionArgParser.cpp b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
index e173febcfa8fe..70ac5db7b2826 100644
--- a/lldb/unittests/Interpreter/TestOptionArgParser.cpp
+++ b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
@@ -8,61 +8,44 @@
#include "gtest/gtest.h"
#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Utility/Status.h"
+#include "llvm/ADT/StringRef.h"
using namespace lldb_private;
-TEST(OptionArgParserTest, toBoolean) {
+void TestToBoolean(llvm::StringRef option_arg, bool fail_value, bool expected_value, bool expected_success) {
+ EXPECT_EQ(expected_value,
+ OptionArgParser::ToBoolean(option_arg, fail_value, nullptr));
+
bool success = false;
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("true"), false, nullptr));
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("on"), false, nullptr));
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("yes"), false, nullptr));
- EXPECT_TRUE(OptionArgParser::ToBoolean(llvm::StringRef("1"), false, nullptr));
-
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("true"), false, &success));
- EXPECT_TRUE(success);
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("on"), false, &success));
- EXPECT_TRUE(success);
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("yes"), false, &success));
- EXPECT_TRUE(success);
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("1"), false, &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(expected_value,
+ OptionArgParser::ToBoolean(option_arg, fail_value, &success));
+ EXPECT_EQ(expected_success, success);
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("false"), true, nullptr));
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("off"), true, nullptr));
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("no"), true, nullptr));
- EXPECT_FALSE(OptionArgParser::ToBoolean(llvm::StringRef("0"), true, nullptr));
+ Status status;
+ EXPECT_EQ(expected_value,
+ OptionArgParser::ToBoolean(llvm::StringRef("--test"), option_arg, fail_value, status));
+ EXPECT_EQ(expected_success, status.Success());
+}
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("false"), true, &success));
- EXPECT_TRUE(success);
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("off"), true, &success));
- EXPECT_TRUE(success);
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("no"), true, &success));
- EXPECT_TRUE(success);
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("0"), true, &success));
- EXPECT_TRUE(success);
+TEST(OptionArgParserTest, toBoolean) {
+ // "True"-ish values should be successfully parsed and return `true`.
+ TestToBoolean(llvm::StringRef("true"), false, true, true);
+ TestToBoolean(llvm::StringRef("on"), false, true, true);
+ TestToBoolean(llvm::StringRef("yes"), false, true, true);
+ TestToBoolean(llvm::StringRef("1"), false, true, true);
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("10"), false, &success));
- EXPECT_FALSE(success);
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("10"), true, &success));
- EXPECT_FALSE(success);
- EXPECT_TRUE(OptionArgParser::ToBoolean(llvm::StringRef(""), true, &success));
- EXPECT_FALSE(success);
+ // "False"-ish values should be successfully parsed and return `false`.
+ TestToBoolean(llvm::StringRef("false"), true, false, true);
+ TestToBoolean(llvm::StringRef("off"), true, false, true);
+ TestToBoolean(llvm::StringRef("no"), true, false, true);
+ TestToBoolean(llvm::StringRef("0"), true, false, true);
+
+ // Other values should fail the parse and return the given `fail_value`.
+ TestToBoolean(llvm::StringRef("10"), false, false, false);
+ TestToBoolean(llvm::StringRef("10"), true, true, false);
+ TestToBoolean(llvm::StringRef(""), false, false, false);
+ TestToBoolean(llvm::StringRef(""), true, true, false);
}
TEST(OptionArgParserTest, toChar) {
>From 8b6066b1d019f3ef987265afab71b19bd6f8127b Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Thu, 13 Jun 2024 17:30:07 -0700
Subject: [PATCH 10/19] Fix format
---
lldb/unittests/Interpreter/TestOptionArgParser.cpp | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/lldb/unittests/Interpreter/TestOptionArgParser.cpp b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
index 70ac5db7b2826..8e5a100888e95 100644
--- a/lldb/unittests/Interpreter/TestOptionArgParser.cpp
+++ b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
@@ -13,18 +13,20 @@
using namespace lldb_private;
-void TestToBoolean(llvm::StringRef option_arg, bool fail_value, bool expected_value, bool expected_success) {
+void TestToBoolean(llvm::StringRef option_arg, bool fail_value,
+ bool expected_value, bool expected_success) {
EXPECT_EQ(expected_value,
- OptionArgParser::ToBoolean(option_arg, fail_value, nullptr));
+ OptionArgParser::ToBoolean(option_arg, fail_value, nullptr));
bool success = false;
EXPECT_EQ(expected_value,
- OptionArgParser::ToBoolean(option_arg, fail_value, &success));
+ OptionArgParser::ToBoolean(option_arg, fail_value, &success));
EXPECT_EQ(expected_success, success);
Status status;
EXPECT_EQ(expected_value,
- OptionArgParser::ToBoolean(llvm::StringRef("--test"), option_arg, fail_value, status));
+ OptionArgParser::ToBoolean(llvm::StringRef("--test"), option_arg,
+ fail_value, status));
EXPECT_EQ(expected_success, status.Success());
}
>From d6073538548ebccb9e673967aacf34eaab95023b Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Thu, 13 Jun 2024 17:37:25 -0700
Subject: [PATCH 11/19] Minor fix in test
---
lldb/test/API/commands/statistics/basic/TestStats.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py
index f19ec89bfe777..10acca69b4ce2 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -724,7 +724,7 @@ def test_sections_existence(self):
"targets": False,
"targets.moduleIdentifiers": False,
"targets.breakpoints": False,
- "targets.expressionEvaluation": True,
+ "targets.expressionEvaluation": False,
"modules": True,
"transcript": False,
},
>From 6fca90c558948e35d86cdd678597caf2657e4aae Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Mon, 17 Jun 2024 08:52:37 -0700
Subject: [PATCH 12/19] Change StatisticsOptions to use accessors + optional
fields
---
lldb/include/lldb/Target/Statistics.h | 47 ++++-
lldb/source/API/SBStatisticsOptions.cpp | 23 +--
lldb/source/Commands/CommandObjectStats.cpp | 28 +--
lldb/source/Target/Statistics.cpp | 14 +-
.../commands/statistics/basic/TestStats.py | 169 ++++++++++++------
5 files changed, 185 insertions(+), 96 deletions(-)
diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index 268de2f1d9686..7e1533e7e00a0 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -131,11 +131,48 @@ struct ConstStringStats {
};
struct StatisticsOptions {
- bool summary_only = false;
- bool load_all_debug_info = false;
- bool include_targets = true;
- bool include_modules = true;
- bool include_transcript = true;
+public:
+ void SetSummaryOnly(bool value) { m_summary_only = value; }
+ bool GetSummaryOnly() const { return m_summary_only.value_or(false); }
+
+ void SetLoadAllDebugInfo(bool value) { m_load_all_debug_info = value; }
+ bool GetLoadAllDebugInfo() const {
+ return m_load_all_debug_info.value_or(false);
+ }
+
+ void SetIncludeTargets(bool value) { m_include_targets = value; }
+ bool GetIncludeTargets() const {
+ if (m_include_targets.has_value())
+ return m_include_targets.value();
+ // `m_include_targets` has no value set, so return a value base on
+ // `m_summary_only`
+ return !GetSummaryOnly();
+ }
+
+ void SetIncludeModules(bool value) { m_include_modules = value; }
+ bool GetIncludeModules() const {
+ if (m_include_modules.has_value())
+ return m_include_modules.value();
+ // `m_include_modules` has no value set, so return a value base on
+ // `m_summary_only`
+ return !GetSummaryOnly();
+ }
+
+ void SetIncludeTranscript(bool value) { m_include_transcript = value; }
+ bool GetIncludeTranscript() const {
+ if (m_include_transcript.has_value())
+ return m_include_transcript.value();
+ // `m_include_transcript` has no value set, so return a value base on
+ // `m_summary_only`
+ return !GetSummaryOnly();
+ }
+
+private:
+ std::optional<bool> m_summary_only;
+ std::optional<bool> m_load_all_debug_info;
+ std::optional<bool> m_include_transcript;
+ std::optional<bool> m_include_targets;
+ std::optional<bool> m_include_modules;
};
/// A class that represents statistics for a since lldb_private::Target.
diff --git a/lldb/source/API/SBStatisticsOptions.cpp b/lldb/source/API/SBStatisticsOptions.cpp
index 7cf8664955ae7..71d4048573b56 100644
--- a/lldb/source/API/SBStatisticsOptions.cpp
+++ b/lldb/source/API/SBStatisticsOptions.cpp
@@ -18,7 +18,6 @@ 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) {
@@ -39,41 +38,43 @@ SBStatisticsOptions::operator=(const SBStatisticsOptions &rhs) {
}
void SBStatisticsOptions::SetSummaryOnly(bool b) {
- m_opaque_up->summary_only = b;
+ m_opaque_up->SetSummaryOnly(b);
}
-bool SBStatisticsOptions::GetSummaryOnly() { return m_opaque_up->summary_only; }
+bool SBStatisticsOptions::GetSummaryOnly() {
+ return m_opaque_up->GetSummaryOnly();
+}
void SBStatisticsOptions::SetIncludeTargets(bool b) {
- m_opaque_up->include_targets = b;
+ m_opaque_up->SetIncludeTargets(b);
}
bool SBStatisticsOptions::GetIncludeTargets() const {
- return m_opaque_up->include_targets;
+ return m_opaque_up->GetIncludeTargets();
}
void SBStatisticsOptions::SetIncludeModules(bool b) {
- m_opaque_up->include_modules = b;
+ m_opaque_up->SetIncludeModules(b);
}
bool SBStatisticsOptions::GetIncludeModules() const {
- return m_opaque_up->include_modules;
+ return m_opaque_up->GetIncludeModules();
}
void SBStatisticsOptions::SetIncludeTranscript(bool b) {
- m_opaque_up->include_transcript = b;
+ m_opaque_up->SetIncludeTranscript(b);
}
bool SBStatisticsOptions::GetIncludeTranscript() const {
- return m_opaque_up->include_transcript;
+ return m_opaque_up->GetIncludeTranscript();
}
void SBStatisticsOptions::SetReportAllAvailableDebugInfo(bool b) {
- m_opaque_up->load_all_debug_info = b;
+ m_opaque_up->SetLoadAllDebugInfo(b);
}
bool SBStatisticsOptions::GetReportAllAvailableDebugInfo() {
- return m_opaque_up->load_all_debug_info;
+ return m_opaque_up->GetLoadAllDebugInfo();
}
const lldb_private::StatisticsOptions &SBStatisticsOptions::ref() const {
diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp
index b093c6607d5d8..5541f46dfc55c 100644
--- a/lldb/source/Commands/CommandObjectStats.cpp
+++ b/lldb/source/Commands/CommandObjectStats.cpp
@@ -77,34 +77,22 @@ class CommandObjectStatsDump : public CommandObjectParsed {
m_all_targets = true;
break;
case 's':
- m_stats_options.summary_only = true;
- // In the "summary" mode, the following sections should be omitted by
- // default unless their corresponding options are explicitly given.
- // If such options were processed before 's', `m_seen_options` should
- // contain them, and we will skip setting them to `false` here. If such
- // options are not yet processed, we will set them to `false` here, and
- // they will be overwritten when the options are processed.
- if (m_seen_options.find((int)'r') == m_seen_options.end())
- m_stats_options.include_targets = false;
- if (m_seen_options.find((int)'m') == m_seen_options.end())
- m_stats_options.include_modules = false;
- if (m_seen_options.find((int)'t') == m_seen_options.end())
- m_stats_options.include_transcript = false;
+ m_stats_options.SetSummaryOnly(true);
break;
case 'f':
- m_stats_options.load_all_debug_info = true;
+ m_stats_options.SetLoadAllDebugInfo(true);
break;
case 'r':
- m_stats_options.include_targets = OptionArgParser::ToBoolean(
- "--targets", option_arg, true /* doesn't matter */, error);
+ m_stats_options.SetIncludeTargets(OptionArgParser::ToBoolean(
+ "--targets", option_arg, true /* doesn't matter */, error));
break;
case 'm':
- m_stats_options.include_modules = OptionArgParser::ToBoolean(
- "--modules", option_arg, true /* doesn't matter */, error);
+ m_stats_options.SetIncludeModules(OptionArgParser::ToBoolean(
+ "--modules", option_arg, true /* doesn't matter */, error));
break;
case 't':
- m_stats_options.include_transcript = OptionArgParser::ToBoolean(
- "--transcript", option_arg, true /* doesn't matter */, error);
+ m_stats_options.SetIncludeTranscript(OptionArgParser::ToBoolean(
+ "--transcript", option_arg, true /* doesn't matter */, error));
break;
default:
llvm_unreachable("Unimplemented option");
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 716f80a7fd6bb..583d1524881fc 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -107,8 +107,8 @@ TargetStats::ToJSON(Target &target,
const lldb_private::StatisticsOptions &options) {
json::Object target_metrics_json;
ProcessSP process_sp = target.GetProcessSP();
- const bool summary_only = options.summary_only;
- const bool include_modules = options.include_modules;
+ const bool summary_only = options.GetSummaryOnly();
+ const bool include_modules = options.GetIncludeModules();
if (!summary_only) {
CollectStats(target);
@@ -226,11 +226,11 @@ llvm::json::Value DebuggerStats::ReportStatistics(
Debugger &debugger, Target *target,
const lldb_private::StatisticsOptions &options) {
- const bool summary_only = options.summary_only;
- const bool load_all_debug_info = options.load_all_debug_info;
- const bool include_targets = options.include_targets;
- const bool include_modules = options.include_modules;
- const bool include_transcript = options.include_transcript;
+ const bool summary_only = options.GetSummaryOnly();
+ const bool load_all_debug_info = options.GetLoadAllDebugInfo();
+ const bool include_targets = options.GetIncludeTargets();
+ const bool include_modules = options.GetIncludeModules();
+ const bool include_transcript = options.GetIncludeTranscript();
json::Array json_targets;
json::Array json_modules;
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py
index 10acca69b4ce2..66c04a6d8bc77 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -658,30 +658,44 @@ def test_transcript_happy_path(self):
# The second "statistics dump" in the transcript should have no output
self.assertNotIn("output", transcript[2])
- def test_sections_existence(self):
- """
- Test "statistics dump" and the existence of sections when different
- options are given.
- """
- self.build()
- exe = self.getBuildArtifact("a.out")
- target = self.createTestTarget(file_path=exe)
-
- # Create some transcript so that it can be tested.
- self.runCmd("settings set interpreter.save-transcript true")
- self.runCmd("version")
- self.runCmd("b main")
- # But disable transcript so that it won't change during verification
- self.runCmd("settings set interpreter.save-transcript false")
+ def verify_stats(self, stats, expectation, options):
+ for field_name in expectation:
+ idx = field_name.find(".")
+ if idx == -1:
+ # `field` is a top-level field
+ exists = field_name in stats
+ should_exist = expectation[field_name]
+ should_exist_string = "" if should_exist else "not "
+ self.assertEqual(
+ exists,
+ should_exist,
+ f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'",
+ )
+ else:
+ # `field` is a string of "<top-level field>.<second-level field>"
+ top_level_field_name = field_name[0:idx]
+ second_level_field_name = field_name[idx + 1 :]
+ for top_level_field in (
+ stats[top_level_field_name] if top_level_field_name in stats else {}
+ ):
+ exists = second_level_field_name in top_level_field
+ should_exist = expectation[field_name]
+ should_exist_string = "" if should_exist else "not "
+ self.assertEqual(
+ exists,
+ should_exist,
+ f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'",
+ )
- # Expectation
+ def get_expectations_for_sections_existence(self):
should_always_exist_or_not = {
"totalDebugInfoEnabled": True,
"memory": True,
}
test_cases = [
{ # Everything mode
- "options": "",
+ "command_options": "",
+ "api_options": {},
"expect": {
"commands": True,
"targets": True,
@@ -693,7 +707,10 @@ def test_sections_existence(self):
},
},
{ # Summary mode
- "options": " --summary",
+ "command_options": " --summary",
+ "api_options": {
+ "SetSummaryOnly": True,
+ },
"expect": {
"commands": False,
"targets": False,
@@ -705,7 +722,11 @@ def test_sections_existence(self):
},
},
{ # Summary mode with targets
- "options": " --summary --targets=true",
+ "command_options": " --summary --targets=true",
+ "api_options": {
+ "SetSummaryOnly": True,
+ "SetIncludeTargets": True,
+ },
"expect": {
"commands": False,
"targets": True,
@@ -718,7 +739,11 @@ def test_sections_existence(self):
},
},
{ # Summary mode with modules
- "options": " --summary --modules=true",
+ "command_options": " --summary --modules=true",
+ "api_options": {
+ "SetSummaryOnly": True,
+ "SetIncludeModules": True,
+ },
"expect": {
"commands": False,
"targets": False,
@@ -730,7 +755,11 @@ def test_sections_existence(self):
},
},
{ # Everything mode but without modules and transcript
- "options": " --modules=false --transcript=false",
+ "command_options": " --modules=false --transcript=false",
+ "api_options": {
+ "SetIncludeModules": False,
+ "SetIncludeTranscript": False,
+ },
"expect": {
"commands": True,
"targets": True,
@@ -742,7 +771,10 @@ def test_sections_existence(self):
},
},
{ # Everything mode but without modules
- "options": " --modules=false",
+ "command_options": " --modules=false",
+ "api_options": {
+ "SetIncludeModules": False,
+ },
"expect": {
"commands": True,
"targets": True,
@@ -754,42 +786,73 @@ def test_sections_existence(self):
},
},
]
+ return (should_always_exist_or_not, test_cases)
+
+ def test_sections_existence_through_command(self):
+ """
+ Test "statistics dump" and the existence of sections when different
+ options are given through the command line (CLI or HandleCommand).
+ """
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ target = self.createTestTarget(file_path=exe)
+
+ # Create some transcript so that it can be tested.
+ self.runCmd("settings set interpreter.save-transcript true")
+ self.runCmd("version")
+ self.runCmd("b main")
+ # But disable transcript so that it won't change during verification
+ self.runCmd("settings set interpreter.save-transcript false")
+
+ # Expectation
+ should_always_exist_or_not, test_cases = (
+ self.get_expectations_for_sections_existence()
+ )
# Verification
for test_case in test_cases:
- options = test_case["options"]
- debug_stats = self.get_stats(options)
+ options = test_case["command_options"]
+ # Get statistics dump result
+ stats = self.get_stats(options)
# Verify that each field should exist (or not)
expectation = {**should_always_exist_or_not, **test_case["expect"]}
- for field_name in expectation:
- idx = field_name.find(".")
- if idx == -1:
- # `field` is a top-level field
- exists = field_name in debug_stats
- should_exist = expectation[field_name]
- should_exist_string = "" if should_exist else "not "
- self.assertEqual(
- exists,
- should_exist,
- f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'",
- )
- else:
- # `field` is a string of "<top-level field>.<second-level field>"
- top_level_field_name = field_name[0:idx]
- second_level_field_name = field_name[idx + 1 :]
- for top_level_field in (
- debug_stats[top_level_field_name]
- if top_level_field_name in debug_stats
- else []
- ):
- exists = second_level_field_name in top_level_field
- should_exist = expectation[field_name]
- should_exist_string = "" if should_exist else "not "
- self.assertEqual(
- exists,
- should_exist,
- f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'",
- )
+ self.verify_stats(stats, expectation, options)
+
+ def test_sections_existence_through_api(self):
+ """
+ Test "statistics dump" and the existence of sections when different
+ options are given through the public API.
+ """
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ target = self.createTestTarget(file_path=exe)
+
+ # Create some transcript so that it can be tested.
+ self.runCmd("settings set interpreter.save-transcript true")
+ self.runCmd("version")
+ self.runCmd("b main")
+ # But disable transcript so that it won't change during verification
+ self.runCmd("settings set interpreter.save-transcript false")
+
+ # Expectation
+ should_always_exist_or_not, test_cases = (
+ self.get_expectations_for_sections_existence()
+ )
+
+ # Verification
+ for test_case in test_cases:
+ # Create options
+ options = test_case["api_options"]
+ sb_options = lldb.SBStatisticsOptions()
+ for method_name, param_value in options.items():
+ getattr(sb_options, method_name)(param_value)
+ # Get statistics dump result
+ stream = lldb.SBStream()
+ target.GetStatistics(sb_options).GetAsJSON(stream)
+ stats = json.loads(stream.GetData())
+ # Verify that each field should exist (or not)
+ expectation = {**should_always_exist_or_not, **test_case["expect"]}
+ self.verify_stats(stats, expectation, options)
def test_order_of_options_do_not_matter(self):
"""
>From dfdf528d74a84670f05c2fc822dcff16be8716bd Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Mon, 17 Jun 2024 09:08:34 -0700
Subject: [PATCH 13/19] Minor fixes
---
lldb/include/lldb/Target/Statistics.h | 2 +-
lldb/source/Interpreter/Options.cpp | 1 -
.../API/commands/statistics/basic/TestStats.py | 14 +++++++-------
lldb/unittests/Interpreter/TestOptionArgParser.cpp | 1 -
4 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index 7e1533e7e00a0..5c6fee6b8a7b1 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -170,9 +170,9 @@ struct StatisticsOptions {
private:
std::optional<bool> m_summary_only;
std::optional<bool> m_load_all_debug_info;
- std::optional<bool> m_include_transcript;
std::optional<bool> m_include_targets;
std::optional<bool> m_include_modules;
+ std::optional<bool> m_include_transcript;
};
/// A class that represents statistics for a since lldb_private::Target.
diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp
index 65d95013fc903..4e7d074ace1b8 100644
--- a/lldb/source/Interpreter/Options.cpp
+++ b/lldb/source/Interpreter/Options.cpp
@@ -18,7 +18,6 @@
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/STLExtras.h"
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py
index 66c04a6d8bc77..44dec7199fad7 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -662,7 +662,7 @@ def verify_stats(self, stats, expectation, options):
for field_name in expectation:
idx = field_name.find(".")
if idx == -1:
- # `field` is a top-level field
+ # `field_name` is a top-level field
exists = field_name in stats
should_exist = expectation[field_name]
should_exist_string = "" if should_exist else "not "
@@ -672,7 +672,7 @@ def verify_stats(self, stats, expectation, options):
f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'",
)
else:
- # `field` is a string of "<top-level field>.<second-level field>"
+ # `field_name` is a string of "<top-level field>.<second-level field>"
top_level_field_name = field_name[0:idx]
second_level_field_name = field_name[idx + 1 :]
for top_level_field in (
@@ -687,7 +687,7 @@ def verify_stats(self, stats, expectation, options):
f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'",
)
- def get_expectations_for_sections_existence(self):
+ def get_test_cases_for_sections_existence(self):
should_always_exist_or_not = {
"totalDebugInfoEnabled": True,
"memory": True,
@@ -801,12 +801,12 @@ def test_sections_existence_through_command(self):
self.runCmd("settings set interpreter.save-transcript true")
self.runCmd("version")
self.runCmd("b main")
- # But disable transcript so that it won't change during verification
+ # Then disable transcript so that it won't change during verification
self.runCmd("settings set interpreter.save-transcript false")
# Expectation
should_always_exist_or_not, test_cases = (
- self.get_expectations_for_sections_existence()
+ self.get_test_cases_for_sections_existence()
)
# Verification
@@ -836,7 +836,7 @@ def test_sections_existence_through_api(self):
# Expectation
should_always_exist_or_not, test_cases = (
- self.get_expectations_for_sections_existence()
+ self.get_test_cases_for_sections_existence()
)
# Verification
@@ -866,7 +866,7 @@ def test_order_of_options_do_not_matter(self):
self.runCmd("settings set interpreter.save-transcript true")
self.runCmd("version")
self.runCmd("b main")
- # But disable transcript so that it won't change during verification
+ # Then disable transcript so that it won't change during verification
self.runCmd("settings set interpreter.save-transcript false")
# The order of the following options shouldn't matter
diff --git a/lldb/unittests/Interpreter/TestOptionArgParser.cpp b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
index 8e5a100888e95..c17a443421ad5 100644
--- a/lldb/unittests/Interpreter/TestOptionArgParser.cpp
+++ b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
@@ -9,7 +9,6 @@
#include "gtest/gtest.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Utility/Status.h"
-#include "llvm/ADT/StringRef.h"
using namespace lldb_private;
>From 7b17e773efff1e538f898736cfd591175120cfa1 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Mon, 17 Jun 2024 13:09:37 -0700
Subject: [PATCH 14/19] Fix format
---
.../API/commands/statistics/basic/TestStats.py | 14 ++++++++------
lldb/unittests/Interpreter/TestOptionArgParser.cpp | 2 +-
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py
index 44dec7199fad7..136c44e17c645 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -805,9 +805,10 @@ def test_sections_existence_through_command(self):
self.runCmd("settings set interpreter.save-transcript false")
# Expectation
- should_always_exist_or_not, test_cases = (
- self.get_test_cases_for_sections_existence()
- )
+ (
+ should_always_exist_or_not,
+ test_cases,
+ ) = self.get_test_cases_for_sections_existence()
# Verification
for test_case in test_cases:
@@ -835,9 +836,10 @@ def test_sections_existence_through_api(self):
self.runCmd("settings set interpreter.save-transcript false")
# Expectation
- should_always_exist_or_not, test_cases = (
- self.get_test_cases_for_sections_existence()
- )
+ (
+ should_always_exist_or_not,
+ test_cases,
+ ) = self.get_test_cases_for_sections_existence()
# Verification
for test_case in test_cases:
diff --git a/lldb/unittests/Interpreter/TestOptionArgParser.cpp b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
index c17a443421ad5..ca6a0c30f828b 100644
--- a/lldb/unittests/Interpreter/TestOptionArgParser.cpp
+++ b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
@@ -6,9 +6,9 @@
//
//===----------------------------------------------------------------------===//
-#include "gtest/gtest.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Utility/Status.h"
+#include "gtest/gtest.h"
using namespace lldb_private;
>From 64afbe153da892912c76e0e9afcddb1a5d2d80b8 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Mon, 17 Jun 2024 13:15:44 -0700
Subject: [PATCH 15/19] Minor fixes
---
lldb/include/lldb/Target/Statistics.h | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/lldb/include/lldb/Target/Statistics.h b/lldb/include/lldb/Target/Statistics.h
index 5c6fee6b8a7b1..122eb3ddd711f 100644
--- a/lldb/include/lldb/Target/Statistics.h
+++ b/lldb/include/lldb/Target/Statistics.h
@@ -144,8 +144,8 @@ struct StatisticsOptions {
bool GetIncludeTargets() const {
if (m_include_targets.has_value())
return m_include_targets.value();
- // `m_include_targets` has no value set, so return a value base on
- // `m_summary_only`
+ // `m_include_targets` has no value set, so return a value based on
+ // `m_summary_only`.
return !GetSummaryOnly();
}
@@ -153,8 +153,8 @@ struct StatisticsOptions {
bool GetIncludeModules() const {
if (m_include_modules.has_value())
return m_include_modules.value();
- // `m_include_modules` has no value set, so return a value base on
- // `m_summary_only`
+ // `m_include_modules` has no value set, so return a value based on
+ // `m_summary_only`.
return !GetSummaryOnly();
}
@@ -162,8 +162,8 @@ struct StatisticsOptions {
bool GetIncludeTranscript() const {
if (m_include_transcript.has_value())
return m_include_transcript.value();
- // `m_include_transcript` has no value set, so return a value base on
- // `m_summary_only`
+ // `m_include_transcript` has no value set, so return a value based on
+ // `m_summary_only`.
return !GetSummaryOnly();
}
>From 5a61950dbdd6209206b35b306fef1f7201269a0b Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Tue, 18 Jun 2024 13:12:05 -0700
Subject: [PATCH 16/19] Change the newly added `OptionArgParser::ToBoolean` to
return `llvm::Expected<bool>`
---
.../lldb/Interpreter/OptionArgParser.h | 3 +-
lldb/source/Commands/CommandObjectStats.cpp | 18 ++-
lldb/source/Interpreter/OptionArgParser.cpp | 14 +-
.../Interpreter/TestOptionArgParser.cpp | 120 +++++++++++++-----
4 files changed, 105 insertions(+), 50 deletions(-)
diff --git a/lldb/include/lldb/Interpreter/OptionArgParser.h b/lldb/include/lldb/Interpreter/OptionArgParser.h
index af20cd258aff3..9c5d37bbe1f50 100644
--- a/lldb/include/lldb/Interpreter/OptionArgParser.h
+++ b/lldb/include/lldb/Interpreter/OptionArgParser.h
@@ -29,8 +29,7 @@ struct OptionArgParser {
static bool ToBoolean(llvm::StringRef s, bool fail_value, bool *success_ptr);
- static bool ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg,
- bool fail_value, Status &error);
+ static llvm::Expected<bool> ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg);
static char ToChar(llvm::StringRef s, char fail_value, bool *success_ptr);
diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp
index 5541f46dfc55c..d7a40b02e2b0e 100644
--- a/lldb/source/Commands/CommandObjectStats.cpp
+++ b/lldb/source/Commands/CommandObjectStats.cpp
@@ -83,16 +83,22 @@ class CommandObjectStatsDump : public CommandObjectParsed {
m_stats_options.SetLoadAllDebugInfo(true);
break;
case 'r':
- m_stats_options.SetIncludeTargets(OptionArgParser::ToBoolean(
- "--targets", option_arg, true /* doesn't matter */, error));
+ if (llvm::Expected<bool> bool_or_error = OptionArgParser::ToBoolean("--targets", option_arg))
+ m_stats_options.SetIncludeTargets(*bool_or_error);
+ else
+ error = bool_or_error.takeError();
break;
case 'm':
- m_stats_options.SetIncludeModules(OptionArgParser::ToBoolean(
- "--modules", option_arg, true /* doesn't matter */, error));
+ if (llvm::Expected<bool> bool_or_error = OptionArgParser::ToBoolean("--modules", option_arg))
+ m_stats_options.SetIncludeModules(*bool_or_error);
+ else
+ error = bool_or_error.takeError();
break;
case 't':
- m_stats_options.SetIncludeTranscript(OptionArgParser::ToBoolean(
- "--transcript", option_arg, true /* doesn't matter */, error));
+ if (llvm::Expected<bool> bool_or_error = OptionArgParser::ToBoolean("--transcript", option_arg))
+ m_stats_options.SetIncludeTranscript(*bool_or_error);
+ else
+ error = bool_or_error.takeError();
break;
default:
llvm_unreachable("Unimplemented option");
diff --git a/lldb/source/Interpreter/OptionArgParser.cpp b/lldb/source/Interpreter/OptionArgParser.cpp
index 978032807ebd1..39f6f670c0d68 100644
--- a/lldb/source/Interpreter/OptionArgParser.cpp
+++ b/lldb/source/Interpreter/OptionArgParser.cpp
@@ -35,17 +35,15 @@ bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value,
return fail_value;
}
-bool OptionArgParser::ToBoolean(llvm::StringRef option_name,
- llvm::StringRef option_arg, bool fail_value,
- Status &error) {
+llvm::Expected<bool> OptionArgParser::ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg) {
bool parse_success;
- const bool arg_value = ToBoolean(option_arg, fail_value, &parse_success);
- if (!parse_success)
- error.SetErrorStringWithFormat(
- "Invalid boolean value for option '%s': '%s'",
+ const bool option_value = ToBoolean(option_arg, false /* doesn't matter */, &parse_success);
+ if (parse_success)
+ return option_value;
+ else
+ return llvm::createStringError("Invalid boolean value for option '%s': '%s'",
option_name.str().c_str(),
option_arg.empty() ? "<null>" : option_arg.str().c_str());
- return arg_value;
}
char OptionArgParser::ToChar(llvm::StringRef s, char fail_value,
diff --git a/lldb/unittests/Interpreter/TestOptionArgParser.cpp b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
index ca6a0c30f828b..ea8aa4fc5b4e0 100644
--- a/lldb/unittests/Interpreter/TestOptionArgParser.cpp
+++ b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
@@ -6,47 +6,99 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Interpreter/OptionArgParser.h"
-#include "lldb/Utility/Status.h"
#include "gtest/gtest.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "llvm/Support/Error.h"
using namespace lldb_private;
-void TestToBoolean(llvm::StringRef option_arg, bool fail_value,
- bool expected_value, bool expected_success) {
- EXPECT_EQ(expected_value,
- OptionArgParser::ToBoolean(option_arg, fail_value, nullptr));
-
+TEST(OptionArgParserTest, toBoolean) {
bool success = false;
- EXPECT_EQ(expected_value,
- OptionArgParser::ToBoolean(option_arg, fail_value, &success));
- EXPECT_EQ(expected_success, success);
-
- Status status;
- EXPECT_EQ(expected_value,
- OptionArgParser::ToBoolean(llvm::StringRef("--test"), option_arg,
- fail_value, status));
- EXPECT_EQ(expected_success, status.Success());
+ EXPECT_TRUE(
+ OptionArgParser::ToBoolean(llvm::StringRef("true"), false, nullptr));
+ EXPECT_TRUE(
+ OptionArgParser::ToBoolean(llvm::StringRef("on"), false, nullptr));
+ EXPECT_TRUE(
+ OptionArgParser::ToBoolean(llvm::StringRef("yes"), false, nullptr));
+ EXPECT_TRUE(OptionArgParser::ToBoolean(llvm::StringRef("1"), false, nullptr));
+
+ EXPECT_TRUE(
+ OptionArgParser::ToBoolean(llvm::StringRef("true"), false, &success));
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(
+ OptionArgParser::ToBoolean(llvm::StringRef("on"), false, &success));
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(
+ OptionArgParser::ToBoolean(llvm::StringRef("yes"), false, &success));
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(
+ OptionArgParser::ToBoolean(llvm::StringRef("1"), false, &success));
+ EXPECT_TRUE(success);
+
+ EXPECT_FALSE(
+ OptionArgParser::ToBoolean(llvm::StringRef("false"), true, nullptr));
+ EXPECT_FALSE(
+ OptionArgParser::ToBoolean(llvm::StringRef("off"), true, nullptr));
+ EXPECT_FALSE(
+ OptionArgParser::ToBoolean(llvm::StringRef("no"), true, nullptr));
+ EXPECT_FALSE(OptionArgParser::ToBoolean(llvm::StringRef("0"), true, nullptr));
+
+ EXPECT_FALSE(
+ OptionArgParser::ToBoolean(llvm::StringRef("false"), true, &success));
+ EXPECT_TRUE(success);
+ EXPECT_FALSE(
+ OptionArgParser::ToBoolean(llvm::StringRef("off"), true, &success));
+ EXPECT_TRUE(success);
+ EXPECT_FALSE(
+ OptionArgParser::ToBoolean(llvm::StringRef("no"), true, &success));
+ EXPECT_TRUE(success);
+ EXPECT_FALSE(
+ OptionArgParser::ToBoolean(llvm::StringRef("0"), true, &success));
+ EXPECT_TRUE(success);
+
+ EXPECT_FALSE(
+ OptionArgParser::ToBoolean(llvm::StringRef("10"), false, &success));
+ EXPECT_FALSE(success);
+ EXPECT_TRUE(
+ OptionArgParser::ToBoolean(llvm::StringRef("10"), true, &success));
+ EXPECT_FALSE(success);
+ EXPECT_TRUE(OptionArgParser::ToBoolean(llvm::StringRef(""), true, &success));
+ EXPECT_FALSE(success);
}
-TEST(OptionArgParserTest, toBoolean) {
- // "True"-ish values should be successfully parsed and return `true`.
- TestToBoolean(llvm::StringRef("true"), false, true, true);
- TestToBoolean(llvm::StringRef("on"), false, true, true);
- TestToBoolean(llvm::StringRef("yes"), false, true, true);
- TestToBoolean(llvm::StringRef("1"), false, true, true);
-
- // "False"-ish values should be successfully parsed and return `false`.
- TestToBoolean(llvm::StringRef("false"), true, false, true);
- TestToBoolean(llvm::StringRef("off"), true, false, true);
- TestToBoolean(llvm::StringRef("no"), true, false, true);
- TestToBoolean(llvm::StringRef("0"), true, false, true);
-
- // Other values should fail the parse and return the given `fail_value`.
- TestToBoolean(llvm::StringRef("10"), false, false, false);
- TestToBoolean(llvm::StringRef("10"), true, true, false);
- TestToBoolean(llvm::StringRef(""), false, false, false);
- TestToBoolean(llvm::StringRef(""), true, true, false);
+void TestToBooleanWithExpectedBool(llvm::StringRef option_arg, bool expected_parse_success, bool expected_result)
+{
+ llvm::Expected<bool> bool_or_error = OptionArgParser::ToBoolean(llvm::StringRef("test_option"), option_arg);
+ EXPECT_EQ(expected_parse_success, (bool)bool_or_error);
+ if (expected_parse_success)
+ EXPECT_EQ(expected_result, *bool_or_error);
+ else {
+ std::string error = llvm::toString(bool_or_error.takeError());
+ EXPECT_NE(std::string::npos, error.find("test_option"));
+ }
+}
+
+TEST(OptionArgParserTest, toBooleanWithExpectedBool) {
+ TestToBooleanWithExpectedBool(llvm::StringRef("true"), true, true);
+ TestToBooleanWithExpectedBool(llvm::StringRef("on"), true, true);
+ TestToBooleanWithExpectedBool(llvm::StringRef("yes"), true, true);
+ TestToBooleanWithExpectedBool(llvm::StringRef("1"), true, true);
+
+ TestToBooleanWithExpectedBool(llvm::StringRef("True"), true, true);
+ TestToBooleanWithExpectedBool(llvm::StringRef("On"), true, true);
+ TestToBooleanWithExpectedBool(llvm::StringRef("Yes"), true, true);
+
+ TestToBooleanWithExpectedBool(llvm::StringRef("false"), true, false);
+ TestToBooleanWithExpectedBool(llvm::StringRef("off"), true, false);
+ TestToBooleanWithExpectedBool(llvm::StringRef("no"), true, false);
+ TestToBooleanWithExpectedBool(llvm::StringRef("0"), true, false);
+
+ TestToBooleanWithExpectedBool(llvm::StringRef("False"), true, false);
+ TestToBooleanWithExpectedBool(llvm::StringRef("Off"), true, false);
+ TestToBooleanWithExpectedBool(llvm::StringRef("No"), true, false);
+
+ TestToBooleanWithExpectedBool(llvm::StringRef("10"), false, false /* doesn't matter */);
+ TestToBooleanWithExpectedBool(llvm::StringRef(""), false, false /* doesn't matter */);
}
TEST(OptionArgParserTest, toChar) {
>From 233a1e17b335e3840c753d7f66f8be3f93a83648 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Tue, 18 Jun 2024 13:28:48 -0700
Subject: [PATCH 17/19] Update doc strings
---
lldb/include/lldb/API/SBStatisticsOptions.h | 16 ++++++++++++++++
lldb/source/Commands/Options.td | 9 ++++++++-
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/lldb/include/lldb/API/SBStatisticsOptions.h b/lldb/include/lldb/API/SBStatisticsOptions.h
index 35ebe3db1c53b..691eca00efee0 100644
--- a/lldb/include/lldb/API/SBStatisticsOptions.h
+++ b/lldb/include/lldb/API/SBStatisticsOptions.h
@@ -22,15 +22,31 @@ class LLDB_API SBStatisticsOptions {
const SBStatisticsOptions &operator=(const lldb::SBStatisticsOptions &rhs);
+ /// If true, dump only high-level summary statistics. Exclude details like targets, modules, breakpoints, etc.
+ ///
+ /// Default is false.
void SetSummaryOnly(bool b);
bool GetSummaryOnly();
+ /// If true, dump statistics for the targets, including breakpoints, expression evaluations, frame variables, etc.
+ ///
+ /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case this is turned off unless specified.
+ ///
+ /// If both `IncludeTargets` and `IncludeModules` are true, a list of module identifiers will be added to the "targets" section.
void SetIncludeTargets(bool b);
bool GetIncludeTargets() const;
+ /// If true, dump statistics for the modules, including time and size of various aspects of the module and debug information, type system, path, etc.
+ ///
+ /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case this is turned off unless specified.
+ ///
+ /// If both `IncludeTargets` and `IncludeModules` are true, a list of module identifiers will be added to the "targets" section.
void SetIncludeModules(bool b);
bool GetIncludeModules() const;
+ /// If true and the setting `interpreter.save-transcript` is enabled, include a JSON array with all commands the user and/or scripts executed during a debug session.
+ ///
+ /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case this is turned off unless specified.
void SetIncludeTranscript(bool b);
bool GetIncludeTranscript() const;
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index dffaf525ef052..ba256e5ab917a 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1429,17 +1429,24 @@ let Command = "statistics dump" in {
Arg<"Boolean">,
Desc<"Dump statistics for the targets, including breakpoints, expression "
"evaluations, frame variables, etc. "
+ "Defaults to true, unless the '--summary' mode is enabled, in which case "
+ "this is turned off unless specified. "
"If both the '--targets' and the '--modules' options are 'true', a list "
"of module identifiers will be added to the 'targets' section.">;
def statistics_dump_modules: Option<"modules", "m">, Group<1>,
Arg<"Boolean">,
Desc<"Dump statistics for the modules, including time and size of various "
"aspects of the module and debug information, type system, path, etc. "
+ "Defaults to true, unless the '--summary' mode is enabled, in which case "
+ "this is turned off unless specified. "
"If both the '--targets' and the '--modules' options are 'true', a list "
"of module identifiers will be added to the 'targets' section.">;
def statistics_dump_transcript: Option<"transcript", "t">, Group<1>,
Arg<"Boolean">,
Desc<"If the setting interpreter.save-transcript is enabled and this "
"option is 'true', include a JSON array with all commands the user and/or "
- "scripts executed during a debug session.">;
+ "scripts executed during a debug session. "
+ "Defaults to true, unless the '--summary' mode is enabled, in which case "
+ "this is turned off unless specified.">;
+
}
>From 3cc46f58136cb50243b5f73771f1e2c348b7be8d Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Tue, 18 Jun 2024 13:31:27 -0700
Subject: [PATCH 18/19] Fix format
---
lldb/include/lldb/API/SBStatisticsOptions.h | 29 +++++++++++++------
.../lldb/Interpreter/OptionArgParser.h | 3 +-
lldb/source/Commands/CommandObjectStats.cpp | 21 ++++++++------
lldb/source/Interpreter/OptionArgParser.cpp | 9 ++++--
.../Interpreter/TestOptionArgParser.cpp | 14 +++++----
5 files changed, 49 insertions(+), 27 deletions(-)
diff --git a/lldb/include/lldb/API/SBStatisticsOptions.h b/lldb/include/lldb/API/SBStatisticsOptions.h
index 691eca00efee0..fefeefe9feffb 100644
--- a/lldb/include/lldb/API/SBStatisticsOptions.h
+++ b/lldb/include/lldb/API/SBStatisticsOptions.h
@@ -22,31 +22,42 @@ class LLDB_API SBStatisticsOptions {
const SBStatisticsOptions &operator=(const lldb::SBStatisticsOptions &rhs);
- /// If true, dump only high-level summary statistics. Exclude details like targets, modules, breakpoints, etc.
+ /// If true, dump only high-level summary statistics. Exclude details like
+ /// targets, modules, breakpoints, etc.
///
/// Default is false.
void SetSummaryOnly(bool b);
bool GetSummaryOnly();
- /// If true, dump statistics for the targets, including breakpoints, expression evaluations, frame variables, etc.
+ /// If true, dump statistics for the targets, including breakpoints,
+ /// expression evaluations, frame variables, etc.
///
- /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case this is turned off unless specified.
+ /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case
+ /// this is turned off unless specified.
///
- /// If both `IncludeTargets` and `IncludeModules` are true, a list of module identifiers will be added to the "targets" section.
+ /// If both `IncludeTargets` and `IncludeModules` are true, a list of module
+ /// identifiers will be added to the "targets" section.
void SetIncludeTargets(bool b);
bool GetIncludeTargets() const;
- /// If true, dump statistics for the modules, including time and size of various aspects of the module and debug information, type system, path, etc.
+ /// If true, dump statistics for the modules, including time and size of
+ /// various aspects of the module and debug information, type system, path,
+ /// etc.
///
- /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case this is turned off unless specified.
+ /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case
+ /// this is turned off unless specified.
///
- /// If both `IncludeTargets` and `IncludeModules` are true, a list of module identifiers will be added to the "targets" section.
+ /// If both `IncludeTargets` and `IncludeModules` are true, a list of module
+ /// identifiers will be added to the "targets" section.
void SetIncludeModules(bool b);
bool GetIncludeModules() const;
- /// If true and the setting `interpreter.save-transcript` is enabled, include a JSON array with all commands the user and/or scripts executed during a debug session.
+ /// If true and the setting `interpreter.save-transcript` is enabled, include
+ /// a JSON array with all commands the user and/or scripts executed during a
+ /// debug session.
///
- /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case this is turned off unless specified.
+ /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case
+ /// this is turned off unless specified.
void SetIncludeTranscript(bool b);
bool GetIncludeTranscript() const;
diff --git a/lldb/include/lldb/Interpreter/OptionArgParser.h b/lldb/include/lldb/Interpreter/OptionArgParser.h
index 9c5d37bbe1f50..76a48fca69208 100644
--- a/lldb/include/lldb/Interpreter/OptionArgParser.h
+++ b/lldb/include/lldb/Interpreter/OptionArgParser.h
@@ -29,7 +29,8 @@ struct OptionArgParser {
static bool ToBoolean(llvm::StringRef s, bool fail_value, bool *success_ptr);
- static llvm::Expected<bool> ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg);
+ static llvm::Expected<bool> ToBoolean(llvm::StringRef option_name,
+ llvm::StringRef option_arg);
static char ToChar(llvm::StringRef s, char fail_value, bool *success_ptr);
diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp
index d7a40b02e2b0e..53855e7d03165 100644
--- a/lldb/source/Commands/CommandObjectStats.cpp
+++ b/lldb/source/Commands/CommandObjectStats.cpp
@@ -83,22 +83,25 @@ class CommandObjectStatsDump : public CommandObjectParsed {
m_stats_options.SetLoadAllDebugInfo(true);
break;
case 'r':
- if (llvm::Expected<bool> bool_or_error = OptionArgParser::ToBoolean("--targets", option_arg))
- m_stats_options.SetIncludeTargets(*bool_or_error);
+ if (llvm::Expected<bool> bool_or_error =
+ OptionArgParser::ToBoolean("--targets", option_arg))
+ m_stats_options.SetIncludeTargets(*bool_or_error);
else
- error = bool_or_error.takeError();
+ error = bool_or_error.takeError();
break;
case 'm':
- if (llvm::Expected<bool> bool_or_error = OptionArgParser::ToBoolean("--modules", option_arg))
- m_stats_options.SetIncludeModules(*bool_or_error);
+ if (llvm::Expected<bool> bool_or_error =
+ OptionArgParser::ToBoolean("--modules", option_arg))
+ m_stats_options.SetIncludeModules(*bool_or_error);
else
- error = bool_or_error.takeError();
+ error = bool_or_error.takeError();
break;
case 't':
- if (llvm::Expected<bool> bool_or_error = OptionArgParser::ToBoolean("--transcript", option_arg))
- m_stats_options.SetIncludeTranscript(*bool_or_error);
+ if (llvm::Expected<bool> bool_or_error =
+ OptionArgParser::ToBoolean("--transcript", option_arg))
+ m_stats_options.SetIncludeTranscript(*bool_or_error);
else
- error = bool_or_error.takeError();
+ error = bool_or_error.takeError();
break;
default:
llvm_unreachable("Unimplemented option");
diff --git a/lldb/source/Interpreter/OptionArgParser.cpp b/lldb/source/Interpreter/OptionArgParser.cpp
index 39f6f670c0d68..105d4846da148 100644
--- a/lldb/source/Interpreter/OptionArgParser.cpp
+++ b/lldb/source/Interpreter/OptionArgParser.cpp
@@ -35,13 +35,16 @@ bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value,
return fail_value;
}
-llvm::Expected<bool> OptionArgParser::ToBoolean(llvm::StringRef option_name, llvm::StringRef option_arg) {
+llvm::Expected<bool> OptionArgParser::ToBoolean(llvm::StringRef option_name,
+ llvm::StringRef option_arg) {
bool parse_success;
- const bool option_value = ToBoolean(option_arg, false /* doesn't matter */, &parse_success);
+ const bool option_value =
+ ToBoolean(option_arg, false /* doesn't matter */, &parse_success);
if (parse_success)
return option_value;
else
- return llvm::createStringError("Invalid boolean value for option '%s': '%s'",
+ return llvm::createStringError(
+ "Invalid boolean value for option '%s': '%s'",
option_name.str().c_str(),
option_arg.empty() ? "<null>" : option_arg.str().c_str());
}
diff --git a/lldb/unittests/Interpreter/TestOptionArgParser.cpp b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
index ea8aa4fc5b4e0..25335e5396fbd 100644
--- a/lldb/unittests/Interpreter/TestOptionArgParser.cpp
+++ b/lldb/unittests/Interpreter/TestOptionArgParser.cpp
@@ -66,9 +66,11 @@ TEST(OptionArgParserTest, toBoolean) {
EXPECT_FALSE(success);
}
-void TestToBooleanWithExpectedBool(llvm::StringRef option_arg, bool expected_parse_success, bool expected_result)
-{
- llvm::Expected<bool> bool_or_error = OptionArgParser::ToBoolean(llvm::StringRef("test_option"), option_arg);
+void TestToBooleanWithExpectedBool(llvm::StringRef option_arg,
+ bool expected_parse_success,
+ bool expected_result) {
+ llvm::Expected<bool> bool_or_error =
+ OptionArgParser::ToBoolean(llvm::StringRef("test_option"), option_arg);
EXPECT_EQ(expected_parse_success, (bool)bool_or_error);
if (expected_parse_success)
EXPECT_EQ(expected_result, *bool_or_error);
@@ -97,8 +99,10 @@ TEST(OptionArgParserTest, toBooleanWithExpectedBool) {
TestToBooleanWithExpectedBool(llvm::StringRef("Off"), true, false);
TestToBooleanWithExpectedBool(llvm::StringRef("No"), true, false);
- TestToBooleanWithExpectedBool(llvm::StringRef("10"), false, false /* doesn't matter */);
- TestToBooleanWithExpectedBool(llvm::StringRef(""), false, false /* doesn't matter */);
+ TestToBooleanWithExpectedBool(llvm::StringRef("10"), false,
+ false /* doesn't matter */);
+ TestToBooleanWithExpectedBool(llvm::StringRef(""), false,
+ false /* doesn't matter */);
}
TEST(OptionArgParserTest, toChar) {
>From 0a96d72eb5c22509987064ce262a708afe0e7c25 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Tue, 18 Jun 2024 13:37:29 -0700
Subject: [PATCH 19/19] Minor docstring edits
---
lldb/include/lldb/API/SBStatisticsOptions.h | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/lldb/include/lldb/API/SBStatisticsOptions.h b/lldb/include/lldb/API/SBStatisticsOptions.h
index fefeefe9feffb..74bea03eff9c9 100644
--- a/lldb/include/lldb/API/SBStatisticsOptions.h
+++ b/lldb/include/lldb/API/SBStatisticsOptions.h
@@ -23,16 +23,17 @@ class LLDB_API SBStatisticsOptions {
const SBStatisticsOptions &operator=(const lldb::SBStatisticsOptions &rhs);
/// If true, dump only high-level summary statistics. Exclude details like
- /// targets, modules, breakpoints, etc.
+ /// targets, modules, breakpoints, etc. This turns off `IncludeTargets`,
+ /// `IncludeModules` and `IncludeTranscript` by default.
///
- /// Default is false.
+ /// Defaults to false.
void SetSummaryOnly(bool b);
bool GetSummaryOnly();
/// If true, dump statistics for the targets, including breakpoints,
/// expression evaluations, frame variables, etc.
///
- /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case
+ /// Defaults to true, unless the `SummaryOnly` mode is enabled, in which case
/// this is turned off unless specified.
///
/// If both `IncludeTargets` and `IncludeModules` are true, a list of module
@@ -44,7 +45,7 @@ class LLDB_API SBStatisticsOptions {
/// various aspects of the module and debug information, type system, path,
/// etc.
///
- /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case
+ /// Defaults to true, unless the `SummaryOnly` mode is enabled, in which case
/// this is turned off unless specified.
///
/// If both `IncludeTargets` and `IncludeModules` are true, a list of module
@@ -56,7 +57,7 @@ class LLDB_API SBStatisticsOptions {
/// a JSON array with all commands the user and/or scripts executed during a
/// debug session.
///
- /// Defaults to true, unless the "SummaryOnly" mode is enabled, in which case
+ /// Defaults to true, unless the `SummaryOnly` mode is enabled, in which case
/// this is turned off unless specified.
void SetIncludeTranscript(bool b);
bool GetIncludeTranscript() const;
More information about the lldb-commits
mailing list