https://github.com/royitaqi updated 
https://github.com/llvm/llvm-project/pull/92843

>From 8499f16ad46b3268f35da2bfcbfa02a10aab935a Mon Sep 17 00:00:00 2001
From: Roy Shi <roy...@meta.com>
Date: Mon, 20 May 2024 22:30:40 -0400
Subject: [PATCH 1/7] Add resolvedCommand to transcript, add transcript to
 statistics dump

---
 lldb/include/lldb/API/SBCommandInterpreter.h  |  3 +-
 .../lldb/Interpreter/CommandInterpreter.h     |  5 +--
 .../source/Interpreter/CommandInterpreter.cpp |  6 ++++
 lldb/source/Target/Statistics.cpp             | 31 +++++++++++++++++++
 .../commands/statistics/basic/TestStats.py    | 30 ++++++++++++++++++
 .../interpreter/TestCommandInterpreterAPI.py  | 20 ++++++++----
 6 files changed, 86 insertions(+), 9 deletions(-)

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..7f420daca450a 100644
--- a/lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -580,7 +580,7 @@ class CommandInterpreter : public Broadcaster,
   void SetEchoCommentCommands(bool enable);
 
   bool GetRepeatPreviousCommand() const;
-  
+
   bool GetRequireCommandOverwrite() const;
 
   const CommandObject::CommandMap &GetUserCommands() const {
@@ -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..73eef27095b6d 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 set -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 set -f main.c -l <line>
+        self.assertEqual(transcript[2]["command"], "br set -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.
 

>From 1cac4fa898051537b6cc9c8472dd368436c3a511 Mon Sep 17 00:00:00 2001
From: Roy Shi <roy...@meta.com>
Date: Mon, 20 May 2024 22:41:57 -0400
Subject: [PATCH 2/7] Small fixes

---
 lldb/include/lldb/Interpreter/CommandInterpreter.h            | 2 +-
 .../API/python_api/interpreter/TestCommandInterpreterAPI.py   | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h 
b/lldb/include/lldb/Interpreter/CommandInterpreter.h
index 7f420daca450a..6e21af7180f79 100644
--- a/lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -580,7 +580,7 @@ class CommandInterpreter : public Broadcaster,
   void SetEchoCommentCommands(bool enable);
 
   bool GetRepeatPreviousCommand() const;
-
+  
   bool GetRequireCommandOverwrite() const;
 
   const CommandObject::CommandMap &GetUserCommands() const {
diff --git a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py 
b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
index 73eef27095b6d..1541bcdddd1a4 100644
--- a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
+++ b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
@@ -118,7 +118,7 @@ def test_get_transcript(self):
         res = lldb.SBCommandReturnObject()
         ci.HandleCommand("version", res)
         ci.HandleCommand("an-unknown-command", res)
-        ci.HandleCommand("br 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)
@@ -161,7 +161,7 @@ def test_get_transcript(self):
             })
 
         # (lldb) br set -f main.c -l <line>
-        self.assertEqual(transcript[2]["command"], "br set -f main.c -l %d" % 
self.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"])

>From 67a1197a15682731f37890734a5c8674896e0428 Mon Sep 17 00:00:00 2001
From: Roy Shi <roy...@meta.com>
Date: Mon, 20 May 2024 22:42:42 -0400
Subject: [PATCH 3/7] More small fixes

---
 .../API/python_api/interpreter/TestCommandInterpreterAPI.py     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py 
b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
index 1541bcdddd1a4..157594b4aefa1 100644
--- a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
+++ b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
@@ -160,7 +160,7 @@ def test_get_transcript(self):
                 "error": "error: 'an-unknown-command' is not a valid 
command.\n",
             })
 
-        # (lldb) br set -f main.c -l <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

>From eadf71a28c7445b727e5ea783ffb4d070b5c8b3b Mon Sep 17 00:00:00 2001
From: Roy Shi <roy...@meta.com>
Date: Thu, 23 May 2024 22:26:54 -0400
Subject: [PATCH 4/7] Add timestamp into transcript, rename duration field, fix
 format for python files

---
 .../source/Interpreter/CommandInterpreter.cpp |  9 ++-
 .../commands/statistics/basic/TestStats.py    | 57 +++++++++---------
 .../interpreter/TestCommandInterpreterAPI.py  | 60 ++++++++++++++-----
 3 files changed, 83 insertions(+), 43 deletions(-)

diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp 
b/lldb/source/Interpreter/CommandInterpreter.cpp
index 04820bd7d39f6..97d581d21784f 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -6,6 +6,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include <chrono>
 #include <cstdlib>
 #include <limits>
 #include <memory>
@@ -1909,6 +1910,11 @@ bool CommandInterpreter::HandleCommand(const char 
*command_line,
 
     transcript_item = std::make_shared<StructuredData::Dictionary>();
     transcript_item->AddStringItem("command", command_line);
+    transcript_item->AddIntegerItem(
+        "timestampInEpochSeconds",
+        std::chrono::duration_cast<std::chrono::seconds>(
+            std::chrono::system_clock::now().time_since_epoch())
+            .count());
     m_transcript.AddItem(transcript_item);
   }
 
@@ -2078,7 +2084,8 @@ bool CommandInterpreter::HandleCommand(const char 
*command_line,
 
     transcript_item->AddStringItem("output", result.GetOutputData());
     transcript_item->AddStringItem("error", result.GetErrorData());
-    transcript_item->AddFloatItem("seconds", execute_time.get().count());
+    transcript_item->AddFloatItem("durationInSeconds",
+                                  execute_time.get().count());
   }
 
   return result.Succeeded();
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py 
b/lldb/test/API/commands/statistics/basic/TestStats.py
index a536ee2c9bbdc..abf610d78dd9f 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -624,32 +624,33 @@ def test_had_frame_variable_errors(self):
         # 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"], "")
+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 157594b4aefa1..9ac56266a6eba 100644
--- a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
+++ b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
@@ -133,17 +133,19 @@ def test_get_transcript(self):
             self.assertIn("resolvedCommand", command)
             self.assertIn("output", command)
             self.assertIn("error", command)
-            self.assertIn("seconds", command)
+            self.assertIn("durationInSeconds", command)
+            self.assertIn("timestampInEpochSeconds", command)
 
         # The following validates individual commands in the transcript.
         #
         # Notes:
         # 1. Some of the asserts rely on the exact output format of the
         #    commands. Hopefully we are not changing them any time soon.
-        # 2. We are removing the "seconds" field from each command, so that
-        #    some of the validations below can be easier / more readable.
+        # 2. We are removing the time-related fields from each command, so
+        #    that some of the validations below can be easier / more readable.
         for command in transcript:
-            del(command["seconds"])
+            del command["durationInSeconds"]
+            del command["timestampInEpochSeconds"]
 
         # (lldb) version
         self.assertEqual(transcript[0]["command"], "version")
@@ -152,17 +154,22 @@ def test_get_transcript(self):
         self.assertEqual(transcript[0]["error"], "")
 
         # (lldb) an-unknown-command
-        self.assertEqual(transcript[1],
+        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) 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)
+        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"], "")
@@ -176,13 +183,15 @@ def test_get_transcript(self):
         self.assertEqual(transcript[3]["error"], "")
 
         # (lldb) p a
-        self.assertEqual(transcript[4],
+        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")
@@ -202,7 +211,10 @@ def test_save_transcript_setting_default(self):
         res = lldb.SBCommandReturnObject()
 
         # The setting's default value should be "false"
-        self.runCmd("settings show interpreter.save-transcript", 
"interpreter.save-transcript (boolean) = false\n")
+        self.runCmd(
+            "settings show interpreter.save-transcript",
+            "interpreter.save-transcript (boolean) = false\n",
+        )
 
     def test_save_transcript_setting_off(self):
         ci = self.buildAndCreateTarget()
@@ -247,17 +259,37 @@ def test_get_transcript_returns_copy(self):
         structured_data_1 = ci.GetTranscript()
         self.assertTrue(structured_data_1.IsValid())
         self.assertEqual(structured_data_1.GetSize(), 1)
-        
self.assertEqual(structured_data_1.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100),
 "version")
+        self.assertEqual(
+            structured_data_1.GetItemAtIndex(0)
+            .GetValueForKey("command")
+            .GetStringValue(100),
+            "version",
+        )
 
         # Run some more commands and get the transcript as structured data 
again
         self.runCmd("help")
         structured_data_2 = ci.GetTranscript()
         self.assertTrue(structured_data_2.IsValid())
         self.assertEqual(structured_data_2.GetSize(), 2)
-        
self.assertEqual(structured_data_2.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100),
 "version")
-        
self.assertEqual(structured_data_2.GetItemAtIndex(1).GetValueForKey("command").GetStringValue(100),
 "help")
+        self.assertEqual(
+            structured_data_2.GetItemAtIndex(0)
+            .GetValueForKey("command")
+            .GetStringValue(100),
+            "version",
+        )
+        self.assertEqual(
+            structured_data_2.GetItemAtIndex(1)
+            .GetValueForKey("command")
+            .GetStringValue(100),
+            "help",
+        )
 
         # Now, the first structured data should remain unchanged
         self.assertTrue(structured_data_1.IsValid())
         self.assertEqual(structured_data_1.GetSize(), 1)
-        
self.assertEqual(structured_data_1.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100),
 "version")
+        self.assertEqual(
+            structured_data_1.GetItemAtIndex(0)
+            .GetValueForKey("command")
+            .GetStringValue(100),
+            "version",
+        )

>From d2389e3d722a71313186eb99b91043c3d9b672cf Mon Sep 17 00:00:00 2001
From: Roy Shi <roy...@meta.com>
Date: Thu, 23 May 2024 23:05:07 -0400
Subject: [PATCH 5/7] Fix test and comment

---
 lldb/include/lldb/API/SBCommandInterpreter.h  |  4 +-
 .../lldb/Interpreter/CommandInterpreter.h     |  6 +-
 .../commands/statistics/basic/TestStats.py    | 64 ++++++++++---------
 3 files changed, 42 insertions(+), 32 deletions(-)

diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h 
b/lldb/include/lldb/API/SBCommandInterpreter.h
index 8eb4a71cb7f88..a2d28b2d17968 100644
--- a/lldb/include/lldb/API/SBCommandInterpreter.h
+++ b/lldb/include/lldb/API/SBCommandInterpreter.h
@@ -324,7 +324,9 @@ class SBCommandInterpreter {
   /// - "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.
+  /// - "durationInSeconds" (float): The time it took to execute the command.
+  /// - "timestampInEpochSeconds" (int): The timestamp when the command is
+  ///   executed.
   SBStructuredData GetTranscript();
 
 protected:
diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h 
b/lldb/include/lldb/Interpreter/CommandInterpreter.h
index 6e21af7180f79..e59948a333bfd 100644
--- a/lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -580,7 +580,7 @@ class CommandInterpreter : public Broadcaster,
   void SetEchoCommentCommands(bool enable);
 
   bool GetRepeatPreviousCommand() const;
-  
+
   bool GetRequireCommandOverwrite() const;
 
   const CommandObject::CommandMap &GetUserCommands() const {
@@ -780,7 +780,9 @@ class CommandInterpreter : public Broadcaster,
   /// - "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.
+  /// - "durationInSeconds" (float): The time it took to execute the command.
+  /// - "timestampInEpochSeconds" (int): The timestamp when the command is
+  ///   executed.
   ///
   /// Turn on settings `interpreter.save-transcript` for LLDB to populate
   /// this list. Otherwise this list is empty.
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py 
b/lldb/test/API/commands/statistics/basic/TestStats.py
index abf610d78dd9f..4b0d3256f0c7e 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -624,33 +624,39 @@ def test_had_frame_variable_errors(self):
         # 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 interpreter.save-transcript true")
+        self.runCmd("version")
 
-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"], "")
+        # Verify the output of a first "statistics dump"
+        debug_stats = self.get_stats()
+        self.assertIn("transcript", debug_stats)
+        transcript = debug_stats["transcript"]
+        print("DEBUG1")
+        print(transcript)
+        self.assertEqual(len(transcript), 2)
+        self.assertEqual(transcript[0]["resolvedCommand"], "version")
+        self.assertEqual(transcript[1]["resolvedCommand"], "statistics dump")
+        # The first "statistics dump" in the transcript should have no output
+        self.assertNotIn("output", transcript[1])
+
+        # Verify the output of a second "statistics dump"
+        debug_stats = self.get_stats()
+        self.assertIn("transcript", debug_stats)
+        transcript = debug_stats["transcript"]
+        print("DEBUG2")
+        print(transcript)
+        self.assertEqual(len(transcript), 3)
+        self.assertEqual(transcript[0]["resolvedCommand"], "version")
+        self.assertEqual(transcript[1]["resolvedCommand"], "statistics dump")
+        # The first "statistics dump" in the transcript should have output now
+        self.assertIn("output", transcript[1])
+        self.assertEqual(transcript[2]["resolvedCommand"], "statistics dump")
+        # The second "statistics dump" in the transcript should have no output
+        self.assertNotIn("output", transcript[2])

>From a2ea0ef10eeba6f1c2be187b85a5f7bc2dc41fa6 Mon Sep 17 00:00:00 2001
From: Roy Shi <roy...@meta.com>
Date: Thu, 23 May 2024 23:12:24 -0400
Subject: [PATCH 6/7] Fix more format

---
 .../lldb/Interpreter/CommandInterpreter.h     |  2 +-
 .../interpreter/TestCommandInterpreterAPI.py  | 45 ++++---------------
 2 files changed, 10 insertions(+), 37 deletions(-)

diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h 
b/lldb/include/lldb/Interpreter/CommandInterpreter.h
index e59948a333bfd..3b9f920f12b8d 100644
--- a/lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -580,7 +580,7 @@ class CommandInterpreter : public Broadcaster,
   void SetEchoCommentCommands(bool enable);
 
   bool GetRepeatPreviousCommand() const;
-
+  
   bool GetRequireCommandOverwrite() const;
 
   const CommandObject::CommandMap &GetUserCommands() const {
diff --git a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py 
b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
index 9ac56266a6eba..17793e7ab00a9 100644
--- a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
+++ b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
@@ -154,15 +154,13 @@ def test_get_transcript(self):
         self.assertEqual(transcript[0]["error"], "")
 
         # (lldb) an-unknown-command
-        self.assertEqual(
-            transcript[1],
+        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) br s -f main.c -l <line>
         self.assertEqual(transcript[2]["command"], "br s -f main.c -l %d" % 
self.line)
@@ -183,15 +181,13 @@ def test_get_transcript(self):
         self.assertEqual(transcript[3]["error"], "")
 
         # (lldb) p a
-        self.assertEqual(
-            transcript[4],
+        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")
@@ -211,10 +207,7 @@ def test_save_transcript_setting_default(self):
         res = lldb.SBCommandReturnObject()
 
         # The setting's default value should be "false"
-        self.runCmd(
-            "settings show interpreter.save-transcript",
-            "interpreter.save-transcript (boolean) = false\n",
-        )
+        self.runCmd("settings show interpreter.save-transcript", 
"interpreter.save-transcript (boolean) = false\n")
 
     def test_save_transcript_setting_off(self):
         ci = self.buildAndCreateTarget()
@@ -259,37 +252,17 @@ def test_get_transcript_returns_copy(self):
         structured_data_1 = ci.GetTranscript()
         self.assertTrue(structured_data_1.IsValid())
         self.assertEqual(structured_data_1.GetSize(), 1)
-        self.assertEqual(
-            structured_data_1.GetItemAtIndex(0)
-            .GetValueForKey("command")
-            .GetStringValue(100),
-            "version",
-        )
+        
self.assertEqual(structured_data_1.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100),
 "version")
 
         # Run some more commands and get the transcript as structured data 
again
         self.runCmd("help")
         structured_data_2 = ci.GetTranscript()
         self.assertTrue(structured_data_2.IsValid())
         self.assertEqual(structured_data_2.GetSize(), 2)
-        self.assertEqual(
-            structured_data_2.GetItemAtIndex(0)
-            .GetValueForKey("command")
-            .GetStringValue(100),
-            "version",
-        )
-        self.assertEqual(
-            structured_data_2.GetItemAtIndex(1)
-            .GetValueForKey("command")
-            .GetStringValue(100),
-            "help",
-        )
+        
self.assertEqual(structured_data_2.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100),
 "version")
+        
self.assertEqual(structured_data_2.GetItemAtIndex(1).GetValueForKey("command").GetStringValue(100),
 "help")
 
         # Now, the first structured data should remain unchanged
         self.assertTrue(structured_data_1.IsValid())
         self.assertEqual(structured_data_1.GetSize(), 1)
-        self.assertEqual(
-            structured_data_1.GetItemAtIndex(0)
-            .GetValueForKey("command")
-            .GetStringValue(100),
-            "version",
-        )
+        
self.assertEqual(structured_data_1.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100),
 "version")

>From 83df90b8ee2375bb78acf314b92b8de349fc9699 Mon Sep 17 00:00:00 2001
From: Roy Shi <roy...@meta.com>
Date: Thu, 23 May 2024 23:22:58 -0400
Subject: [PATCH 7/7] Remove debug prints

---
 lldb/test/API/commands/statistics/basic/TestStats.py | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py 
b/lldb/test/API/commands/statistics/basic/TestStats.py
index 4b0d3256f0c7e..844aa7d0e9a68 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -638,8 +638,6 @@ def test_transcript(self):
         debug_stats = self.get_stats()
         self.assertIn("transcript", debug_stats)
         transcript = debug_stats["transcript"]
-        print("DEBUG1")
-        print(transcript)
         self.assertEqual(len(transcript), 2)
         self.assertEqual(transcript[0]["resolvedCommand"], "version")
         self.assertEqual(transcript[1]["resolvedCommand"], "statistics dump")
@@ -650,8 +648,6 @@ def test_transcript(self):
         debug_stats = self.get_stats()
         self.assertIn("transcript", debug_stats)
         transcript = debug_stats["transcript"]
-        print("DEBUG2")
-        print(transcript)
         self.assertEqual(len(transcript), 3)
         self.assertEqual(transcript[0]["resolvedCommand"], "version")
         self.assertEqual(transcript[1]["resolvedCommand"], "statistics dump")

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to