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 <roy...@meta.com> Date: Mon, 10 Jun 2024 17:04:11 -0700 Subject: [PATCH 01/11] 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 <roy...@meta.com> Date: Mon, 10 Jun 2024 17:04:11 -0700 Subject: [PATCH 02/11] 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 <roy...@meta.com> Date: Mon, 10 Jun 2024 21:54:40 -0700 Subject: [PATCH 03/11] 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 <roy...@meta.com> Date: Mon, 10 Jun 2024 21:55:44 -0700 Subject: [PATCH 04/11] 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 <roy...@meta.com> Date: Mon, 10 Jun 2024 22:10:00 -0700 Subject: [PATCH 05/11] 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 <roy...@meta.com> Date: Thu, 13 Jun 2024 16:45:00 -0700 Subject: [PATCH 06/11] 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 <roy...@meta.com> Date: Thu, 13 Jun 2024 16:51:28 -0700 Subject: [PATCH 07/11] 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 <roy...@meta.com> Date: Thu, 13 Jun 2024 17:14:22 -0700 Subject: [PATCH 08/11] 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 <roy...@meta.com> Date: Thu, 13 Jun 2024 17:26:42 -0700 Subject: [PATCH 09/11] 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 <roy...@meta.com> Date: Thu, 13 Jun 2024 17:30:07 -0700 Subject: [PATCH 10/11] 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 <roy...@meta.com> Date: Thu, 13 Jun 2024 17:37:25 -0700 Subject: [PATCH 11/11] 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, }, _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits