[Lldb-commits] [lldb] 6c4febe - [lldb-dap] Implement a MemoryMonitor (#129332)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Mar 5 08:49:53 PST 2025
Author: Jonas Devlieghere
Date: 2025-03-05T08:49:49-08:00
New Revision: 6c4febee2992d206e95e2ed2294fe216739af1cb
URL: https://github.com/llvm/llvm-project/commit/6c4febee2992d206e95e2ed2294fe216739af1cb
DIFF: https://github.com/llvm/llvm-project/commit/6c4febee2992d206e95e2ed2294fe216739af1cb.diff
LOG: [lldb-dap] Implement a MemoryMonitor (#129332)
This implements a memory monitor for macOS, Linux and Windows. It
registers a callback that invokes `SBDebugger::MemoryPressureDetected`
when a low memory event is detected. This is motivated by the new
server mode, where the lldb-dap process will live across multiple
debug sessions and will use more memory due to caching.
Added:
lldb/include/lldb/Host/MemoryMonitor.h
lldb/source/Host/common/MemoryMonitor.cpp
lldb/source/Host/macosx/objcxx/MemoryMonitorMacOSX.mm
Modified:
lldb/source/Host/CMakeLists.txt
lldb/source/Host/macosx/objcxx/CMakeLists.txt
lldb/tools/lldb-dap/lldb-dap.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/Host/MemoryMonitor.h b/lldb/include/lldb/Host/MemoryMonitor.h
new file mode 100644
index 0000000000000..504f5f9cba96b
--- /dev/null
+++ b/lldb/include/lldb/Host/MemoryMonitor.h
@@ -0,0 +1,41 @@
+//===-- MemoryMonitor.h ---------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_HOST_MEMORYMONITOR_H
+#define LLDB_HOST_MEMORYMONITOR_H
+
+#include <functional>
+#include <memory>
+
+namespace lldb_private {
+
+class MemoryMonitor {
+public:
+ using Callback = std::function<void()>;
+
+ MemoryMonitor(Callback callback) : m_callback(callback) {}
+ virtual ~MemoryMonitor() = default;
+
+ /// MemoryMonitor is not copyable.
+ /// @{
+ MemoryMonitor(const MemoryMonitor &) = delete;
+ MemoryMonitor &operator=(const MemoryMonitor &) = delete;
+ /// @}
+
+ static std::unique_ptr<MemoryMonitor> Create(Callback callback);
+
+ virtual void Start() = 0;
+ virtual void Stop() = 0;
+
+protected:
+ Callback m_callback;
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index cdfb6184f2219..f4be151756b3b 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -27,6 +27,7 @@ add_host_subdirectory(common
common/LockFileBase.cpp
common/LZMA.cpp
common/MainLoopBase.cpp
+ common/MemoryMonitor.cpp
common/MonitoringProcessLauncher.cpp
common/NativeProcessProtocol.cpp
common/NativeRegisterContext.cpp
@@ -136,7 +137,7 @@ else()
elseif (CMAKE_SYSTEM_NAME MATCHES "AIX")
add_host_subdirectory(aix
aix/HostInfoAIX.cpp
- )
+ )
endif()
endif()
diff --git a/lldb/source/Host/common/MemoryMonitor.cpp b/lldb/source/Host/common/MemoryMonitor.cpp
new file mode 100644
index 0000000000000..932fa9c43a22c
--- /dev/null
+++ b/lldb/source/Host/common/MemoryMonitor.cpp
@@ -0,0 +1,109 @@
+//===-- MemoryMonitor.cpp -------------------------------------------------===//
+//
+// 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 "lldb/Host/MemoryMonitor.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/Error.h"
+#include <atomic>
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
+
+#if defined(__linux__)
+#include <fcntl.h>
+#include <poll.h>
+#include <unistd.h>
+#endif
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+using namespace lldb_private;
+
+class MemoryMonitorPoll : public MemoryMonitor {
+public:
+ using MemoryMonitor::MemoryMonitor;
+
+ lldb::thread_result_t MonitorThread() {
+#if defined(__linux__)
+ struct pollfd fds;
+ fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);
+ if (fds.fd < 0)
+ return {};
+ fds.events = POLLPRI;
+
+ auto cleanup = llvm::make_scope_exit([&]() { close(fds.fd); });
+
+ // Detect a 50ms stall in a 2 second time window.
+ const char trig[] = "some 50000 2000000";
+ if (write(fds.fd, trig, strlen(trig) + 1) < 0)
+ return {};
+
+ while (!m_done) {
+ int n = poll(&fds, 1, g_timeout);
+ if (n > 0) {
+ if (fds.revents & POLLERR)
+ return {};
+ if (fds.revents & POLLPRI)
+ m_callback();
+ }
+ }
+#endif
+
+#if defined(_WIN32)
+ HANDLE low_memory_notification =
+ CreateMemoryResourceNotification(LowMemoryResourceNotification);
+ if (!low_memory_notification)
+ return {};
+
+ while (!m_done) {
+ if (WaitForSingleObject(low_memory_notification, g_timeout) ==
+ WAIT_OBJECT_0) {
+ m_callback();
+ }
+ }
+#endif
+
+ return {};
+ }
+
+ void Start() override {
+ llvm::Expected<HostThread> memory_monitor_thread =
+ ThreadLauncher::LaunchThread("lldb.debugger.memory-monitor",
+ [this] { return MonitorThread(); });
+ if (memory_monitor_thread) {
+ m_memory_monitor_thread = *memory_monitor_thread;
+ } else {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Host), memory_monitor_thread.takeError(),
+ "failed to launch host thread: {0}");
+ }
+ }
+
+ void Stop() override {
+ if (m_memory_monitor_thread.IsJoinable()) {
+ m_done = true;
+ m_memory_monitor_thread.Join(nullptr);
+ }
+ }
+
+private:
+ static constexpr uint32_t g_timeout = 1000;
+ std::atomic<bool> m_done = false;
+ HostThread m_memory_monitor_thread;
+};
+
+#if !defined(__APPLE__)
+std::unique_ptr<MemoryMonitor> MemoryMonitor::Create(Callback callback) {
+ return std::make_unique<MemoryMonitorPoll>(callback);
+}
+#endif
diff --git a/lldb/source/Host/macosx/objcxx/CMakeLists.txt b/lldb/source/Host/macosx/objcxx/CMakeLists.txt
index 1e693bed12ce1..cda8269ca9efd 100644
--- a/lldb/source/Host/macosx/objcxx/CMakeLists.txt
+++ b/lldb/source/Host/macosx/objcxx/CMakeLists.txt
@@ -6,6 +6,7 @@ add_lldb_library(lldbHostMacOSXObjCXX NO_PLUGIN_DEPENDENCIES
Host.mm
HostInfoMacOSX.mm
HostThreadMacOSX.mm
+ MemoryMonitorMacOSX.mm
LINK_LIBS
lldbUtility
diff --git a/lldb/source/Host/macosx/objcxx/MemoryMonitorMacOSX.mm b/lldb/source/Host/macosx/objcxx/MemoryMonitorMacOSX.mm
new file mode 100644
index 0000000000000..cb6c2457df1e3
--- /dev/null
+++ b/lldb/source/Host/macosx/objcxx/MemoryMonitorMacOSX.mm
@@ -0,0 +1,51 @@
+//===-- MemoryMonitorMacOSX.mm --------------------------------------------===//
+//
+// 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 "lldb/Host/MemoryMonitor.h"
+#include <cassert>
+#include <dispatch/dispatch.h>
+
+using namespace lldb_private;
+
+class MemoryMonitorMacOSX : public MemoryMonitor {
+ using MemoryMonitor::MemoryMonitor;
+ void Start() override {
+ m_memory_pressure_source = dispatch_source_create(
+ DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0,
+ DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL,
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
+
+ if (!m_memory_pressure_source)
+ return;
+
+ dispatch_source_set_event_handler(m_memory_pressure_source, ^{
+ dispatch_source_memorypressure_flags_t pressureLevel =
+ dispatch_source_get_data(m_memory_pressure_source);
+ if (pressureLevel &
+ (DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL)) {
+ m_callback();
+ }
+ });
+ dispatch_activate(m_memory_pressure_source);
+ printf("Started\n");
+ }
+
+ void Stop() override {
+ if (m_memory_pressure_source) {
+ dispatch_source_cancel(m_memory_pressure_source);
+ dispatch_release(m_memory_pressure_source);
+ }
+ }
+
+private:
+ dispatch_source_t m_memory_pressure_source;
+};
+
+std::unique_ptr<MemoryMonitor> MemoryMonitor::Create(Callback callback) {
+ return std::make_unique<MemoryMonitorMacOSX>(callback);
+}
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index d005eccfae903..a5d9978e30248 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -10,11 +10,13 @@
#include "EventHelper.h"
#include "Handler/RequestHandler.h"
#include "RunInTerminal.h"
+#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBStream.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/File.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Host/MainLoopBase.h"
+#include "lldb/Host/MemoryMonitor.h"
#include "lldb/Host/Socket.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/UriParser.h"
@@ -504,9 +506,24 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
+ // Create a memory monitor. This can return nullptr if the host platform is
+ // not supported.
+ std::unique_ptr<lldb_private::MemoryMonitor> memory_monitor =
+ lldb_private::MemoryMonitor::Create([&]() {
+ if (log)
+ *log << "memory pressure detected\n";
+ lldb::SBDebugger::MemoryPressureDetected();
+ });
+
+ if (memory_monitor)
+ memory_monitor->Start();
+
// Terminate the debugger before the C++ destructor chain kicks in.
- auto terminate_debugger =
- llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); });
+ auto terminate_debugger = llvm::make_scope_exit([&] {
+ if (memory_monitor)
+ memory_monitor->Stop();
+ lldb::SBDebugger::Terminate();
+ });
std::vector<std::string> pre_init_commands;
for (const std::string &arg :
More information about the lldb-commits
mailing list