-
Notifications
You must be signed in to change notification settings - Fork 14.3k
A few updates around "transcript" #92843
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-lldb Author: None (royitaqi) ChangesChanges
Test
Full diff: https://github.com/llvm/llvm-project/pull/92843.diff 6 Files Affected:
diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h b/lldb/include/lldb/API/SBCommandInterpreter.h
index 8ac36344b3a79..8eb4a71cb7f88 100644
--- a/lldb/include/lldb/API/SBCommandInterpreter.h
+++ b/lldb/include/lldb/API/SBCommandInterpreter.h
@@ -320,7 +320,8 @@ class SBCommandInterpreter {
/// Returns a list of handled commands, output and error. Each element in
/// the list is a dictionary with the following keys/values:
- /// - "command" (string): The command that was executed.
+ /// - "command" (string): The command that was given by the user.
+ /// - "resolvedCommand" (string): The expanded command that was executed.
/// - "output" (string): The output of the command. Empty ("") if no output.
/// - "error" (string): The error of the command. Empty ("") if no error.
/// - "seconds" (float): The time it took to execute the command.
diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h
index ccc30cf4f1a82..6e21af7180f79 100644
--- a/lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -776,7 +776,8 @@ class CommandInterpreter : public Broadcaster,
/// Contains a list of handled commands and their details. Each element in
/// the list is a dictionary with the following keys/values:
- /// - "command" (string): The command that was executed.
+ /// - "command" (string): The command that was given by the user.
+ /// - "resolvedCommand" (string): The expanded command that was executed.
/// - "output" (string): The output of the command. Empty ("") if no output.
/// - "error" (string): The error of the command. Empty ("") if no error.
/// - "seconds" (float): The time it took to execute the command.
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 811726e30af4d..04820bd7d39f6 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -2011,6 +2011,12 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
wants_raw_input ? "True" : "False");
}
+ // To test whether or not transcript should be saved, `transcript_item` is
+ // used instead of `GetSaveTrasncript()`. This is because the latter will
+ // fail when the command is "settings set interpreter.save-transcript true".
+ if (transcript_item)
+ transcript_item->AddStringItem("resolvedCommand", command_string);
+
// Phase 2.
// Take care of things like setting up the history command & calling the
// appropriate Execute method on the CommandObject, with the appropriate
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 7f866ae0ef324..fd31377abd06b 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -16,6 +16,7 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
@@ -362,6 +363,36 @@ llvm::json::Value DebuggerStats::ReportStatistics(
global_stats.try_emplace("modules", std::move(json_modules));
global_stats.try_emplace("memory", std::move(json_memory));
global_stats.try_emplace("commands", std::move(cmd_stats));
+
+ // When transcript is available, add it to the to-be-returned statistics.
+ //
+ // NOTE:
+ // When the statistics is polled by an LLDB command:
+ // - The transcript in the returned statistics *will NOT* contain the
+ // returned statistics itself.
+ // - The returned statistics *will* be written to the internal transcript
+ // buffer as the output of the said LLDB command. It *will* appear in
+ // the next statistcs or transcript poll.
+ //
+ // For example, let's say the following commands are run in order:
+ // - "version"
+ // - "statistics dump" <- call it "A"
+ // - "statistics dump" <- call it "B"
+ // The output of "A" will contain the transcript of "version" and
+ // "statistics dump" (A), with the latter having empty output. The output
+ // of B will contain the trascnript of "version", "statistics dump" (A),
+ // "statistics dump" (B), with A's output populated and B's output empty.
+ const StructuredData::Array &transcript =
+ debugger.GetCommandInterpreter().GetTranscript();
+ if (transcript.GetSize() != 0) {
+ std::string buffer;
+ llvm::raw_string_ostream ss(buffer);
+ json::OStream json_os(ss);
+ transcript.Serialize(json_os);
+ if (auto json_transcript = llvm::json::parse(ss.str()))
+ global_stats.try_emplace("transcript",
+ std::move(json_transcript.get()));
+ }
}
return std::move(global_stats);
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py
index fb6fc07d2d443..a536ee2c9bbdc 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -623,3 +623,33 @@ def test_had_frame_variable_errors(self):
# Verify that the top level statistic that aggregates the number of
# modules with debugInfoHadVariableErrors is greater than zero
self.assertGreater(stats["totalModuleCountWithVariableErrors"], 0)
+
+def test_transcript(self):
+ """
+ Test "statistics dump" and the transcript information.
+ """
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ target = self.createTestTarget(file_path=exe)
+ self.runCmd("settings set target.save-transcript true")
+ self.runCmd("version")
+
+ # Verify the output of a first "statistics dump"
+ debug_stats = self.get_stats()
+ self.assertIn("transcript", debug_stats)
+ transcript = debug_stats["transcript"]
+ self.assertEqual(len(transcript), 2)
+ self.assertEqual(transcript[0]["command"], "version")
+ self.assertEqual(transcript[1]["command"], "statistics dump")
+ self.assertEqual(transcript[1]["output"], "")
+
+ # Verify the output of a second "statistics dump"
+ debug_stats = self.get_stats()
+ self.assertIn("transcript", debug_stats)
+ transcript = debug_stats["transcript"]
+ self.assertEqual(len(transcript), 3)
+ self.assertEqual(transcript[0]["command"], "version")
+ self.assertEqual(transcript[1]["command"], "statistics dump")
+ self.assertNotEqual(transcript[1]["output"], "")
+ self.assertEqual(transcript[2]["command"], "statistics dump")
+ self.assertEqual(transcript[2]["output"], "")
diff --git a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
index 95643eef0d344..157594b4aefa1 100644
--- a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
+++ b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
@@ -104,7 +104,7 @@ def getTranscriptAsPythonObject(self, ci):
return json.loads(stream.GetData())
- def test_structured_transcript(self):
+ def test_get_transcript(self):
"""Test structured transcript generation and retrieval."""
ci = self.buildAndCreateTarget()
@@ -118,7 +118,7 @@ def test_structured_transcript(self):
res = lldb.SBCommandReturnObject()
ci.HandleCommand("version", res)
ci.HandleCommand("an-unknown-command", res)
- ci.HandleCommand("breakpoint set -f main.c -l %d" % self.line, res)
+ ci.HandleCommand("br s -f main.c -l %d" % self.line, res)
ci.HandleCommand("r", res)
ci.HandleCommand("p a", res)
ci.HandleCommand("statistics dump", res)
@@ -130,6 +130,7 @@ def test_structured_transcript(self):
# All commands should have expected fields.
for command in transcript:
self.assertIn("command", command)
+ self.assertIn("resolvedCommand", command)
self.assertIn("output", command)
self.assertIn("error", command)
self.assertIn("seconds", command)
@@ -146,6 +147,7 @@ def test_structured_transcript(self):
# (lldb) version
self.assertEqual(transcript[0]["command"], "version")
+ self.assertEqual(transcript[0]["resolvedCommand"], "version")
self.assertIn("lldb version", transcript[0]["output"])
self.assertEqual(transcript[0]["error"], "")
@@ -153,18 +155,21 @@ def test_structured_transcript(self):
self.assertEqual(transcript[1],
{
"command": "an-unknown-command",
+ "resolvedCommand": "an-unknown-command",
"output": "",
"error": "error: 'an-unknown-command' is not a valid command.\n",
})
- # (lldb) breakpoint set -f main.c -l <line>
- self.assertEqual(transcript[2]["command"], "breakpoint set -f main.c -l %d" % self.line)
+ # (lldb) br s -f main.c -l <line>
+ self.assertEqual(transcript[2]["command"], "br s -f main.c -l %d" % self.line)
+ self.assertEqual(transcript[2]["resolvedCommand"], "breakpoint set -f main.c -l %d" % self.line)
# Breakpoint 1: where = a.out`main + 29 at main.c:5:3, address = 0x0000000100000f7d
self.assertIn("Breakpoint 1: where = a.out`main ", transcript[2]["output"])
self.assertEqual(transcript[2]["error"], "")
# (lldb) r
self.assertEqual(transcript[3]["command"], "r")
+ self.assertEqual(transcript[3]["resolvedCommand"], "process launch -X true --")
# Process 25494 launched: '<path>/TestCommandInterpreterAPI.test_structured_transcript/a.out' (x86_64)
self.assertIn("Process", transcript[3]["output"])
self.assertIn("launched", transcript[3]["output"])
@@ -174,11 +179,15 @@ def test_structured_transcript(self):
self.assertEqual(transcript[4],
{
"command": "p a",
+ "resolvedCommand": "dwim-print -- a",
"output": "(int) 123\n",
"error": "",
})
# (lldb) statistics dump
+ self.assertEqual(transcript[5]["command"], "statistics dump")
+ self.assertEqual(transcript[5]["resolvedCommand"], "statistics dump")
+ self.assertEqual(transcript[5]["error"], "")
statistics_dump = json.loads(transcript[5]["output"])
# Dump result should be valid JSON
self.assertTrue(statistics_dump is not json.JSONDecodeError)
@@ -194,7 +203,6 @@ def test_save_transcript_setting_default(self):
# The setting's default value should be "false"
self.runCmd("settings show interpreter.save-transcript", "interpreter.save-transcript (boolean) = false\n")
- # self.assertEqual(res.GetOutput(), )
def test_save_transcript_setting_off(self):
ci = self.buildAndCreateTarget()
@@ -220,7 +228,7 @@ def test_save_transcript_setting_on(self):
self.assertEqual(len(transcript), 1)
self.assertEqual(transcript[0]["command"], "version")
- def test_save_transcript_returns_copy(self):
+ def test_get_transcript_returns_copy(self):
"""
Test that the returned structured data is *at least* a shallow copy.
|
✅ With the latest revision this PR passed the Python code formatter. |
cc @clayborg and @jeffreytan81 about this PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This appears to be failing the I'm testing it on a linux machine. |
Here is the test error:
I have proposed a fix in #94067 |
We also see the same test error on our bots. |
Can you please revert the patch if it's going to take a while to land the fix because I don't want our builders to stay red over the weekend? |
This reverts commit ad884d9.
Reverts #92843 because it broke some lldb tests: https://luci-milo.appspot.com/ui/p/fuchsia/builders/toolchain.ci/clang-linux-x64/b8746385730949743489/overview
The fix PR is ready, as linked in the above (#94067). I just need someone to approve it and merge it. I'm quite new to this process. Isn't reverting also require creating a new patch and someone who has the merge privilege to approve and merge it? FWIW, I have created the revert PR. If someone can approve-and-merge either the revert PR or the forward fix PR, that will be great:
|
This reverts commit ad884d9.
Problematic PR: #92843 Reverted by: #94088 The first PR added a test which fails in Linux builds (see the last few comments there). This PR contains all the changes in the first PR, plus the fix to the said test. --------- Co-authored-by: Roy Shi <[email protected]>
Changes
commandName
andcommandArguments
. They will hold the name and the arguments string of the expanded/executed command (e.g.breakpoint set
and-f main.cpp -l 4
). This is not to be confused with thecommand
field, which holds the user input (e.g.br s -f main.cpp -l 4
).timestampInEpochSeconds
. It will hold the timestamp when the command is executed.seconds
todurationInSeconds
, to improve readability, especially sincetimestampInEpochSeconds
is added.--transcript
is present, add the transcript to the output ofstatistics dump
, as a JSON array under a new fieldtranscript
.Test