llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) <details> <summary>Changes</summary> This implements a memory monitor for macOS & Linux, and registers a callback that invokes SBDebugger::MemoryPressureDetected() when a low memory event is detected. --- Full diff: https://github.com/llvm/llvm-project/pull/129332.diff 4 Files Affected: - (modified) lldb/tools/lldb-dap/CMakeLists.txt (+1) - (added) lldb/tools/lldb-dap/MemoryMonitor.cpp (+114) - (added) lldb/tools/lldb-dap/MemoryMonitor.h (+41) - (modified) lldb/tools/lldb-dap/lldb-dap.cpp (+15-2) ``````````diff diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 8b3c520ec4360..8db377e31c3c6 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -36,6 +36,7 @@ add_lldb_tool(lldb-dap RunInTerminal.cpp SourceBreakpoint.cpp Watchpoint.cpp + MemoryMonitor.cpp Handler/ResponseHandler.cpp Handler/AttachRequestHandler.cpp diff --git a/lldb/tools/lldb-dap/MemoryMonitor.cpp b/lldb/tools/lldb-dap/MemoryMonitor.cpp new file mode 100644 index 0000000000000..da3da42fe9b0f --- /dev/null +++ b/lldb/tools/lldb-dap/MemoryMonitor.cpp @@ -0,0 +1,114 @@ +//===-- 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 "MemoryMonitor.h" +#include "llvm/ADT/ScopeExit.h" +#include <atomic> +#include <cstdio> +#include <cstring> +#include <thread> + +#if defined(__APPLE__) +#include <dispatch/dispatch.h> +#endif + +#if defined(__linux__) +#include <fcntl.h> +#include <poll.h> +#include <unistd.h> +#endif + +using namespace lldb_dap; + +#if defined(__APPLE__) +class MemoryMonitorDarwin : public MemoryMonitor { + using MemoryMonitor::MemoryMonitor; + void Start() override { + m_memory_pressure_source = dispatch_source_create( + DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, + 0, // system-wide monitoring + DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL, + dispatch_get_main_queue()); + + 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(); + } + }); + } + + void Stop() override { dispatch_source_cancel(m_memory_pressure_source); } + +private: + dispatch_source_t m_memory_pressure_source; +}; +#endif + +#if defined(__linux__) +static void MonitorThread(std::atomic<bool> &done, + MemoryMonitor::Callback callback) { + 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 (!done) { + int n = poll(&fds, 1, 1000); + if (n > 0) { + if (fds.revents & POLLERR) + return; + if (fds.revents & POLLPRI) + callback(); + } + } +} + +class MemoryMonitorLinux : public MemoryMonitor { +public: + using MemoryMonitor::MemoryMonitor; + + void Start() override { + m_memory_pressure_thread = + std::thread(MonitorThread, std::ref(m_done), m_callback); + } + + void Stop() override { + if (m_memory_pressure_thread.joinable()) { + m_done = true; + m_memory_pressure_thread.join(); + } + } + +private: + std::atomic<bool> m_done = false; + std::thread m_memory_pressure_thread; +}; +#endif + +std::unique_ptr<MemoryMonitor> MemoryMonitor::Create(Callback callback) { +#if defined(__APPLE__) + return std::make_unique<MemoryMonitorDarwin>(callback); +#endif + +#if defined(__linux__) + return std::make_unique<MemoryMonitorLinux>(callback); +#endif + + return nullptr; +} diff --git a/lldb/tools/lldb-dap/MemoryMonitor.h b/lldb/tools/lldb-dap/MemoryMonitor.h new file mode 100644 index 0000000000000..e07c3bde9e85c --- /dev/null +++ b/lldb/tools/lldb-dap/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_TOOLS_LLDB_DAP_WATCHPOINT_H +#define LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H + +#include <functional> +#include <memory> + +namespace lldb_dap { + +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_dap + +#endif diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index d005eccfae903..41405df548da2 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -9,7 +9,9 @@ #include "DAP.h" #include "EventHelper.h" #include "Handler/RequestHandler.h" +#include "MemoryMonitor.h" #include "RunInTerminal.h" +#include "lldb/API/SBDebugger.h" #include "lldb/API/SBStream.h" #include "lldb/Host/Config.h" #include "lldb/Host/File.h" @@ -504,9 +506,20 @@ 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<MemoryMonitor> memory_monitor = MemoryMonitor::Create( + []() { 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 : `````````` </details> https://github.com/llvm/llvm-project/pull/129332 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits