wallace created this revision.
wallace added reviewers: clayborg, kusmour.
wallace requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Currently, lldb-vscode is reading and processing requests one at a time, which
doesn't match exactly the interactivity of the UI. What happens when LLDB is
working hard parsing symbols, and at the same time the user is hovering around,
pressing resume multiple times, expanding variables in the variables view, etc?
In this case, LLDB will eventually process all of these actions one by one 
even though the user has already pressed resume, which means that most of the
responses will be discarded by the UI. This imposes a big burden on lldb.

A way to fix that is to parallelize the reading and processing of requests,
so that while a request is being processed, the reader can filter out pending
useless requests.

This diff only contains the concurrent queue used for this. If this code makes
sense, I'll proceed to add some filtering logic for pending requests.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D101198

Files:
  lldb/tools/lldb-vscode/lldb-vscode.cpp

Index: lldb/tools/lldb-vscode/lldb-vscode.cpp
===================================================================
--- lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -3145,6 +3145,93 @@
   return new_stdout_fd;
 }
 
+class RequestQueue {
+public:
+  RequestQueue() = default;
+
+  RequestQueue(const RequestQueue &) = delete ;
+  RequestQueue& operator=(const RequestQueue &) = delete;
+
+  /// Get the next front element from the queue or \a None if
+  /// the queue has been terminated.
+  llvm::Optional<llvm::json::Object> Pop() {
+    std::unique_lock<std::mutex> lock(m_mutex);
+    while(m_data.empty() && !m_termination_status)
+      m_can_consume.wait(lock);
+
+    if (m_termination_status)
+      return llvm::None;
+
+    llvm::json::Object request(std::move(m_data.front()));
+    m_data.pop_front();
+    return std::move(request);
+  }
+
+  /// Push a new element in the queue, unless it has been terminated.
+  void Push(llvm::json::Object &&obj) {
+    std::lock_guard<std::mutex> lock(m_mutex);
+    if (m_termination_status)
+      return;
+
+    bool was_empty = m_data.empty();
+    m_data.emplace_back(std::move(obj));
+    if (was_empty)
+      m_can_consume.notify_one();
+  }
+
+  /// Terminate the queue. It won't accept more requests not provide more elements to the reader.
+  void Terminate(bool success) {
+    std::lock_guard<std::mutex> lock(m_mutex);
+
+    if (!m_termination_status)
+      m_termination_status = success;
+    m_can_consume.notify_one();
+  }
+
+  bool GetTerminationStatus() {
+    return *m_termination_status;
+  }
+
+private:
+  std::list<llvm::json::Object> m_data;
+  std::mutex m_mutex;
+  std::condition_variable m_can_consume;
+  llvm::Optional<bool> m_termination_status;
+};
+
+int StartReceivingPackets() {
+  RequestQueue requests;
+
+  std::thread reader_thread ([&]{
+    uint32_t packet_idx = 0;
+    while (!g_vsc.sent_terminated_event) {
+      llvm::json::Object object;
+      lldb_vscode::PacketStatus status = g_vsc.GetNextObject(object);
+      if (status == lldb_vscode::PacketStatus::EndOfFile)
+        break;
+      if (status != lldb_vscode::PacketStatus::Success) {
+        requests.Terminate(false);
+        break;
+      }
+
+      requests.Push(std::move(object));
+      ++packet_idx;
+    }
+    requests.Terminate(true);
+  });
+
+  std::thread worker_thread([&]() {
+    while (llvm::Optional<llvm::json::Object> object = requests.Pop()) {
+      if (!g_vsc.HandleObject(*object))
+        requests.Terminate(false);
+    }
+  });
+  reader_thread.join();
+  worker_thread.join();
+
+  return requests.GetTerminationStatus() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
 int main(int argc, char *argv[]) {
   llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
   llvm::PrettyStackTraceProgram X(argc, argv);
@@ -3224,19 +3311,5 @@
     g_vsc.output.descriptor = StreamDescriptor::from_file(new_stdout_fd, false);
   }
 
-  uint32_t packet_idx = 0;
-  while (!g_vsc.sent_terminated_event) {
-    llvm::json::Object object;
-    lldb_vscode::PacketStatus status = g_vsc.GetNextObject(object);
-    if (status == lldb_vscode::PacketStatus::EndOfFile)
-      break;
-    if (status != lldb_vscode::PacketStatus::Success)
-      return 1; // Fatal error
-
-    if (!g_vsc.HandleObject(object))
-      return 1;
-    ++packet_idx;
-  }
-
-  return EXIT_SUCCESS;
+  return StartReceivingPackets();
 }
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D... walter erquinigo via Phabricator via lldb-commits

Reply via email to