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