[Lldb-commits] [lldb] cc88d30 - [lldb-vscode] Reduce chattiness of progress events
Walter Erquinigo via lldb-commits
lldb-commits at lists.llvm.org
Wed Apr 14 13:00:33 PDT 2021
Author: Walter Erquinigo
Date: 2021-04-14T13:00:01-07:00
New Revision: cc88d301a0bcd8b93c632af2870503949038c87f
URL: https://github.com/llvm/llvm-project/commit/cc88d301a0bcd8b93c632af2870503949038c87f
DIFF: https://github.com/llvm/llvm-project/commit/cc88d301a0bcd8b93c632af2870503949038c87f.diff
LOG: [lldb-vscode] Reduce chattiness of progress events
Progress events internally have a completed count and a total count, which can mean that for a job with 20000 total counts, then there will be 20000 events fired. Sending all these events to the IDE can break it. For example, debugging a huge binary resulted in around 50 million messages, which rendered the IDE useless, as it was spending all of its resources simply parsing messages and updating the UI.
A way to fix this is to send unique percentage updates, which are at most 100 per job, which is not much. I was able to debug that big target and confirm that only unique percentage notifications are sent. I can't write a test for this because the current test is flaky. I'll figure out later how to make the test reliable, but fixing this will unblock us from deploy a new version of lldb-vscode.
Differential Revision: https://reviews.llvm.org/D100443
Added:
lldb/tools/lldb-vscode/ProgressEvent.cpp
lldb/tools/lldb-vscode/ProgressEvent.h
Modified:
lldb/tools/lldb-vscode/CMakeLists.txt
lldb/tools/lldb-vscode/VSCode.cpp
lldb/tools/lldb-vscode/VSCode.h
lldb/tools/lldb-vscode/lldb-vscode.cpp
Removed:
################################################################################
diff --git a/lldb/tools/lldb-vscode/CMakeLists.txt b/lldb/tools/lldb-vscode/CMakeLists.txt
index c5346aaf9e865..eb2f65156f22d 100644
--- a/lldb/tools/lldb-vscode/CMakeLists.txt
+++ b/lldb/tools/lldb-vscode/CMakeLists.txt
@@ -32,6 +32,7 @@ add_lldb_tool(lldb-vscode
IOStream.cpp
JSONUtils.cpp
LLDBUtils.cpp
+ ProgressEvent.cpp
RunInTerminal.cpp
SourceBreakpoint.cpp
VSCode.cpp
diff --git a/lldb/tools/lldb-vscode/ProgressEvent.cpp b/lldb/tools/lldb-vscode/ProgressEvent.cpp
new file mode 100644
index 0000000000000..c282021a1969b
--- /dev/null
+++ b/lldb/tools/lldb-vscode/ProgressEvent.cpp
@@ -0,0 +1,93 @@
+//===-- ProgressEvent.cpp ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProgressEvent.h"
+
+#include "JSONUtils.h"
+
+using namespace lldb_vscode;
+using namespace llvm;
+
+ProgressEvent::ProgressEvent(uint64_t progress_id, const char *message,
+ uint64_t completed, uint64_t total)
+ : m_progress_id(progress_id), m_message(message) {
+ if (completed == total)
+ m_event_type = progressEnd;
+ else if (completed == 0)
+ m_event_type = progressStart;
+ else if (completed < total)
+ m_event_type = progressUpdate;
+ else
+ m_event_type = progressInvalid;
+
+ if (0 < total && total < UINT64_MAX)
+ m_percentage = (uint32_t)(((float)completed / (float)total) * 100.0);
+}
+
+bool ProgressEvent::operator==(const ProgressEvent &other) const {
+ return m_progress_id == other.m_progress_id &&
+ m_event_type == other.m_event_type &&
+ m_percentage == other.m_percentage;
+}
+
+const char *ProgressEvent::GetEventName() const {
+ if (m_event_type == progressStart)
+ return "progressStart";
+ else if (m_event_type == progressEnd)
+ return "progressEnd";
+ else if (m_event_type == progressUpdate)
+ return "progressUpdate";
+ else
+ return "progressInvalid";
+}
+
+bool ProgressEvent::IsValid() const { return m_event_type != progressInvalid; }
+
+uint64_t ProgressEvent::GetID() const { return m_progress_id; }
+
+json::Value ProgressEvent::ToJSON() const {
+ llvm::json::Object event(CreateEventObject(GetEventName()));
+ llvm::json::Object body;
+
+ std::string progress_id_str;
+ llvm::raw_string_ostream progress_id_strm(progress_id_str);
+ progress_id_strm << m_progress_id;
+ progress_id_strm.flush();
+ body.try_emplace("progressId", progress_id_str);
+
+ if (m_event_type == progressStart) {
+ EmplaceSafeString(body, "title", m_message);
+ body.try_emplace("cancellable", false);
+ }
+
+ auto now = std::chrono::duration<double>(
+ std::chrono::system_clock::now().time_since_epoch());
+ std::string timestamp(llvm::formatv("{0:f9}", now.count()));
+ EmplaceSafeString(body, "timestamp", timestamp);
+
+ if (m_percentage)
+ body.try_emplace("percentage", *m_percentage);
+
+ event.try_emplace("body", std::move(body));
+ return json::Value(std::move(event));
+}
+
+ProgressEventFilterQueue::ProgressEventFilterQueue(
+ std::function<void(ProgressEvent)> callback)
+ : m_callback(callback) {}
+
+void ProgressEventFilterQueue::Push(const ProgressEvent &event) {
+ if (!event.IsValid())
+ return;
+
+ auto it = m_last_events.find(event.GetID());
+ if (it == m_last_events.end() || !(it->second == event)) {
+ m_last_events[event.GetID()] = event;
+ m_callback(event);
+ }
+}
diff --git a/lldb/tools/lldb-vscode/ProgressEvent.h b/lldb/tools/lldb-vscode/ProgressEvent.h
new file mode 100644
index 0000000000000..bafe7b30cc3a7
--- /dev/null
+++ b/lldb/tools/lldb-vscode/ProgressEvent.h
@@ -0,0 +1,62 @@
+//===-- ProgressEvent.cpp ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "VSCodeForward.h"
+
+#include "llvm/Support/JSON.h"
+
+namespace lldb_vscode {
+
+enum ProgressEventType {
+ progressInvalid,
+ progressStart,
+ progressUpdate,
+ progressEnd
+};
+
+class ProgressEvent {
+public:
+ ProgressEvent() {}
+
+ ProgressEvent(uint64_t progress_id, const char *message, uint64_t completed,
+ uint64_t total);
+
+ llvm::json::Value ToJSON() const;
+
+ /// This operator returns \b true if two event messages
+ /// would result in the same event for the IDE, e.g.
+ /// same rounded percentage.
+ bool operator==(const ProgressEvent &other) const;
+
+ const char *GetEventName() const;
+
+ bool IsValid() const;
+
+ uint64_t GetID() const;
+
+private:
+ uint64_t m_progress_id;
+ const char *m_message;
+ ProgressEventType m_event_type;
+ llvm::Optional<uint32_t> m_percentage;
+};
+
+/// Class that filters out progress event messages that shouldn't be reported
+/// to the IDE, either because they are invalid or because they are too chatty.
+class ProgressEventFilterQueue {
+public:
+ ProgressEventFilterQueue(std::function<void(ProgressEvent)> callback);
+
+ void Push(const ProgressEvent &event);
+
+private:
+ std::function<void(ProgressEvent)> m_callback;
+ std::map<uint64_t, ProgressEvent> m_last_events;
+};
+
+} // namespace lldb_vscode
diff --git a/lldb/tools/lldb-vscode/VSCode.cpp b/lldb/tools/lldb-vscode/VSCode.cpp
index 8dc7d28a25002..875be9a0e17e7 100644
--- a/lldb/tools/lldb-vscode/VSCode.cpp
+++ b/lldb/tools/lldb-vscode/VSCode.cpp
@@ -40,8 +40,10 @@ VSCode::VSCode()
{"swift_catch", "Swift Catch", lldb::eLanguageTypeSwift},
{"swift_throw", "Swift Throw", lldb::eLanguageTypeSwift}}),
focus_tid(LLDB_INVALID_THREAD_ID), sent_terminated_event(false),
- stop_at_entry(false), is_attach(false),
- reverse_request_seq(0), waiting_for_run_in_terminal(false) {
+ stop_at_entry(false), is_attach(false), reverse_request_seq(0),
+ waiting_for_run_in_terminal(false),
+ progress_event_queue(
+ [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }) {
const char *log_file_path = getenv("LLDBVSCODE_LOG");
#if defined(_WIN32)
// Windows opens stdout and stdin in text mode which converts \n to 13,10
@@ -320,51 +322,8 @@ void VSCode::SendOutput(OutputType o, const llvm::StringRef output) {
// };
// }
-void VSCode::SendProgressEvent(uint64_t progress_id, const char *message,
- uint64_t completed, uint64_t total) {
- enum ProgressEventType {
- progressInvalid,
- progressStart,
- progressUpdate,
- progressEnd
- };
- const char *event_name = nullptr;
- ProgressEventType event_type = progressInvalid;
- if (completed == 0) {
- event_type = progressStart;
- event_name = "progressStart";
- } else if (completed == total) {
- event_type = progressEnd;
- event_name = "progressEnd";
- } else if (completed < total) {
- event_type = progressUpdate;
- event_name = "progressUpdate";
- }
- if (event_type == progressInvalid)
- return;
-
- llvm::json::Object event(CreateEventObject(event_name));
- llvm::json::Object body;
- std::string progress_id_str;
- llvm::raw_string_ostream progress_id_strm(progress_id_str);
- progress_id_strm << progress_id;
- progress_id_strm.flush();
- body.try_emplace("progressId", progress_id_str);
- if (event_type == progressStart) {
- EmplaceSafeString(body, "title", message);
- body.try_emplace("cancellable", false);
- }
- auto now = std::chrono::duration<double>(
- std::chrono::system_clock::now().time_since_epoch());
- std::string timestamp(llvm::formatv("{0:f9}", now.count()));
- EmplaceSafeString(body, "timestamp", timestamp);
-
- if (0 < total && total < UINT64_MAX) {
- uint32_t percentage = (uint32_t)(((float)completed / (float)total) * 100.0);
- body.try_emplace("percentage", percentage);
- }
- event.try_emplace("body", std::move(body));
- SendJSON(llvm::json::Value(std::move(event)));
+void VSCode::SendProgressEvent(const ProgressEvent &event) {
+ progress_event_queue.Push(event);
}
void __attribute__((format(printf, 3, 4)))
diff --git a/lldb/tools/lldb-vscode/VSCode.h b/lldb/tools/lldb-vscode/VSCode.h
index 0897e00223817..45250b958d001 100644
--- a/lldb/tools/lldb-vscode/VSCode.h
+++ b/lldb/tools/lldb-vscode/VSCode.h
@@ -49,6 +49,7 @@
#include "ExceptionBreakpoint.h"
#include "FunctionBreakpoint.h"
#include "IOStream.h"
+#include "ProgressEvent.h"
#include "RunInTerminal.h"
#include "SourceBreakpoint.h"
#include "SourceReference.h"
@@ -113,6 +114,7 @@ struct VSCode {
uint32_t reverse_request_seq;
std::map<std::string, RequestCallback> request_handlers;
bool waiting_for_run_in_terminal;
+ ProgressEventFilterQueue progress_event_queue;
// Keep track of the last stop thread index IDs as threads won't go away
// unless we send a "thread" event to indicate the thread exited.
llvm::DenseSet<lldb::tid_t> thread_ids;
@@ -136,8 +138,7 @@ struct VSCode {
void SendOutput(OutputType o, const llvm::StringRef output);
- void SendProgressEvent(uint64_t progress_id, const char *message,
- uint64_t completed, uint64_t total);
+ void SendProgressEvent(const ProgressEvent &event);
void __attribute__((format(printf, 3, 4)))
SendFormattedOutput(OutputType o, const char *format, ...);
diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp
index cf68386f74324..fa623d25834f9 100644
--- a/lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -374,7 +374,8 @@ void ProgressEventThreadFunction() {
const char *message = lldb::SBDebugger::GetProgressFromEvent(
event, progress_id, completed, total, is_debugger_specific);
if (message)
- g_vsc.SendProgressEvent(progress_id, message, completed, total);
+ g_vsc.SendProgressEvent(
+ ProgressEvent(progress_id, message, completed, total));
}
}
}
More information about the lldb-commits
mailing list