[Lldb-commits] [lldb] a939a9f - [LLDB-DAP] Send Progress update message over DAP (#123837)

via lldb-commits lldb-commits at lists.llvm.org
Wed Jan 22 15:49:17 PST 2025


Author: Jacob Lalonde
Date: 2025-01-22T15:49:13-08:00
New Revision: a939a9fd53d98f33b94f9121646d5906a2b9f598

URL: https://github.com/llvm/llvm-project/commit/a939a9fd53d98f33b94f9121646d5906a2b9f598
DIFF: https://github.com/llvm/llvm-project/commit/a939a9fd53d98f33b94f9121646d5906a2b9f598.diff

LOG: [LLDB-DAP] Send Progress update message over DAP (#123837)

When testing my SBProgress DAP PR (#123826), I noticed Progress update
messages aren't sent over DAP. This patch adds the lldb progress event's
message to the body when sent over DAP.

Before 

![image](https://github.com/user-attachments/assets/404adaa8-b784-4f23-895f-cd3625fdafad)


Now

![image](https://github.com/user-attachments/assets/eb1c3235-0936-4e36-96e5-0a0ee60dabb8)

Tested with my [progress tester
command](https://gist.github.com/Jlalond/48d85e75a91f7a137e3142e6a13d0947),
testing 10 events 5 seconds apart 1-10

Added: 
    lldb/test/API/tools/lldb-dap/progress/Makefile
    lldb/test/API/tools/lldb-dap/progress/Progress_emitter.py
    lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py
    lldb/test/API/tools/lldb-dap/progress/main.cpp

Modified: 
    lldb/tools/lldb-dap/ProgressEvent.cpp
    lldb/tools/lldb-dap/ProgressEvent.h

Removed: 
    


################################################################################
diff  --git a/lldb/test/API/tools/lldb-dap/progress/Makefile b/lldb/test/API/tools/lldb-dap/progress/Makefile
new file mode 100644
index 00000000000000..99998b20bcb050
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/progress/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules

diff  --git a/lldb/test/API/tools/lldb-dap/progress/Progress_emitter.py b/lldb/test/API/tools/lldb-dap/progress/Progress_emitter.py
new file mode 100644
index 00000000000000..7f4055cab9ddda
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/progress/Progress_emitter.py
@@ -0,0 +1,84 @@
+import inspect
+import optparse
+import shlex
+import sys
+import time
+
+import lldb
+
+
+class ProgressTesterCommand:
+    program = "test-progress"
+
+    @classmethod
+    def register_lldb_command(cls, debugger, module_name):
+        parser = cls.create_options()
+        cls.__doc__ = parser.format_help()
+        # Add any commands contained in this module to LLDB
+        command = "command script add -c %s.%s %s" % (
+            module_name,
+            cls.__name__,
+            cls.program,
+        )
+        debugger.HandleCommand(command)
+        print(
+            'The "{0}" command has been installed, type "help {0}" or "{0} '
+            '--help" for detailed help.'.format(cls.program)
+        )
+
+    @classmethod
+    def create_options(cls):
+        usage = "usage: %prog [options]"
+        description = "SBProgress testing tool"
+        # Opt parse is deprecated, but leaving this the way it is because it allows help formating
+        # Additionally all our commands use optparse right now, ideally we migrate them all in one go.
+        parser = optparse.OptionParser(
+            description=description, prog=cls.program, usage=usage
+        )
+
+        parser.add_option(
+            "--total", dest="total", help="Total to count up.", type="int"
+        )
+
+        parser.add_option(
+            "--seconds",
+            dest="seconds",
+            help="Total number of seconds to wait between increments",
+            type="int",
+        )
+
+        return parser
+
+    def get_short_help(self):
+        return "Progress Tester"
+
+    def get_long_help(self):
+        return self.help_string
+
+    def __init__(self, debugger, unused):
+        self.parser = self.create_options()
+        self.help_string = self.parser.format_help()
+
+    def __call__(self, debugger, command, exe_ctx, result):
+        command_args = shlex.split(command)
+        try:
+            (cmd_options, args) = self.parser.parse_args(command_args)
+        except:
+            result.SetError("option parsing failed")
+            return
+
+        total = cmd_options.total
+        progress = lldb.SBProgress("Progress tester", "Detail", total, debugger)
+
+        for i in range(1, total):
+            progress.Increment(1, f"Step {i}")
+            time.sleep(cmd_options.seconds)
+
+
+def __lldb_init_module(debugger, dict):
+    # Register all classes that have a register_lldb_command method
+    for _name, cls in inspect.getmembers(sys.modules[__name__]):
+        if inspect.isclass(cls) and callable(
+            getattr(cls, "register_lldb_command", None)
+        ):
+            cls.register_lldb_command(debugger, __name__)

diff  --git a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py
new file mode 100755
index 00000000000000..36c0cef9c47143
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py
@@ -0,0 +1,49 @@
+"""
+Test lldb-dap output events
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import os
+import time
+
+import lldbdap_testcase
+
+
+class TestDAP_progress(lldbdap_testcase.DAPTestCaseBase):
+    @skipIfWindows
+    def test_output(self):
+        program = self.getBuildArtifact("a.out")
+        self.build_and_launch(program)
+        progress_emitter = os.path.join(os.getcwd(), "Progress_emitter.py")
+        print(f"Progress emitter path: {progress_emitter}")
+        source = "main.cpp"
+        # Set breakpoint in the thread function so we can step the threads
+        breakpoint_ids = self.set_source_breakpoints(
+            source, [line_number(source, "// break here")]
+        )
+        self.continue_to_breakpoints(breakpoint_ids)
+        self.dap_server.request_evaluate(
+            f"`command script import {progress_emitter}", context="repl"
+        )
+        self.dap_server.request_evaluate(
+            "`test-progress --total 3 --seconds 1", context="repl"
+        )
+
+        self.dap_server.wait_for_event("progressEnd", 15)
+        # Expect at least a start, an update, and end event
+        # However because the underlying Progress instance is an RAII object and we can't guaruntee
+        # it's deterministic destruction in the python API, we verify just start and update
+        # otherwise this test could be flakey.
+        self.assertTrue(len(self.dap_server.progress_events) > 0)
+        start_found = False
+        update_found = False
+        for event in self.dap_server.progress_events:
+            event_type = event["event"]
+            if "progressStart" in event_type:
+                start_found = True
+            if "progressUpdate" in event_type:
+                update_found = True
+
+        self.assertTrue(start_found)
+        self.assertTrue(update_found)

diff  --git a/lldb/test/API/tools/lldb-dap/progress/main.cpp b/lldb/test/API/tools/lldb-dap/progress/main.cpp
new file mode 100644
index 00000000000000..3bac5d0fd6db1a
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/progress/main.cpp
@@ -0,0 +1,5 @@
+int main() {
+  char *ptr = "unused";
+  // break here
+  return 0;
+}

diff  --git a/lldb/tools/lldb-dap/ProgressEvent.cpp b/lldb/tools/lldb-dap/ProgressEvent.cpp
index 0dcc2ee81001d5..6a4978c055e516 100644
--- a/lldb/tools/lldb-dap/ProgressEvent.cpp
+++ b/lldb/tools/lldb-dap/ProgressEvent.cpp
@@ -117,6 +117,9 @@ json::Value ProgressEvent::ToJSON() const {
     body.try_emplace("cancellable", false);
   }
 
+  if (m_event_type == progressUpdate)
+    EmplaceSafeString(body, "message", m_message);
+
   std::string timestamp(llvm::formatv("{0:f9}", m_creation_time.count()));
   EmplaceSafeString(body, "timestamp", timestamp);
 
@@ -164,10 +167,10 @@ const ProgressEvent &ProgressEventManager::GetMostRecentEvent() const {
   return m_last_update_event ? *m_last_update_event : m_start_event;
 }
 
-void ProgressEventManager::Update(uint64_t progress_id, uint64_t completed,
-                                  uint64_t total) {
+void ProgressEventManager::Update(uint64_t progress_id, llvm::StringRef message,
+                                  uint64_t completed, uint64_t total) {
   if (std::optional<ProgressEvent> event = ProgressEvent::Create(
-          progress_id, std::nullopt, completed, total, &GetMostRecentEvent())) {
+          progress_id, message, completed, total, &GetMostRecentEvent())) {
     if (event->GetEventType() == progressEnd)
       m_finished = true;
 
@@ -227,7 +230,7 @@ void ProgressEventReporter::Push(uint64_t progress_id, const char *message,
       m_unreported_start_events.push(event_manager);
     }
   } else {
-    it->second->Update(progress_id, completed, total);
+    it->second->Update(progress_id, StringRef(message), completed, total);
     if (it->second->Finished())
       m_event_managers.erase(it);
   }

diff  --git a/lldb/tools/lldb-dap/ProgressEvent.h b/lldb/tools/lldb-dap/ProgressEvent.h
index 72317b879c803a..d1b9b9dd887cd8 100644
--- a/lldb/tools/lldb-dap/ProgressEvent.h
+++ b/lldb/tools/lldb-dap/ProgressEvent.h
@@ -99,7 +99,8 @@ class ProgressEventManager {
 
   /// Receive a new progress event for the start event and try to report it if
   /// appropriate.
-  void Update(uint64_t progress_id, uint64_t completed, uint64_t total);
+  void Update(uint64_t progress_id, llvm::StringRef message, uint64_t completed,
+              uint64_t total);
 
   /// \return
   ///     \b true if a \a progressEnd event has been notified. There's no


        


More information about the lldb-commits mailing list