14#include "llvm/ADT/ScopeExit.h"
15#include "llvm/Support/Error.h"
22#include "llvm/Support/LineIterator.h"
25#include <sys/eventfd.h>
42 explicit MemoryMonitorLinux(Callback callback)
43 : MemoryMonitor(std::move(callback)),
44 m_stop_fd(::eventfd(0, EFD_NONBLOCK)) {}
46 ~MemoryMonitorLinux() {
47 if (m_memory_monitor_thread.IsJoinable())
48 m_memory_monitor_thread.Join(
nullptr);
53 void Start()
override {
57 llvm::errorCodeToError(llvm::errnoAsErrorCode()),
58 "failed to create stop file descriptor for memory monitor: {0}");
62 llvm::Expected<HostThread> memory_monitor_thread =
65 if (memory_monitor_thread) {
66 m_memory_monitor_thread = *memory_monitor_thread;
69 "failed to launch host thread: {0}");
73 void Stop()
override {
74 if (m_memory_monitor_thread.IsJoinable()) {
76 ::eventfd_write(m_stop_fd, 1);
77 m_memory_monitor_thread.Join(
nullptr);
83 constexpr size_t pressure_idx = 0;
84 constexpr size_t stop_idx = 1;
85 constexpr size_t fd_count = 2;
86 std::array<pollfd, fd_count> pfds{};
89 pfds[stop_idx].fd = m_stop_fd;
90 pfds[stop_idx].events = POLLIN;
93 pfds[pressure_idx].fd =
94 ::open(
"/proc/pressure/memory", O_RDWR |
O_NONBLOCK);
95 if (pfds[pressure_idx].fd < 0)
97 pfds[pressure_idx].events = POLLPRI;
99 llvm::scope_exit cleanup([&]() { ::close(pfds[pressure_idx].fd); });
102 constexpr llvm::StringRef trigger =
"some 200000 2000000";
103 if (::write(pfds[pressure_idx].fd, trigger.data(), trigger.size() + 1) < 0)
107 constexpr int timeout_infinite = -1;
108 const int n = ::poll(pfds.data(), pfds.size(), timeout_infinite);
111 if (pfds[stop_idx].revents & (POLLIN | POLLERR))
114 const short pressure_revents = pfds[stop_idx].revents;
115 if (pressure_revents & POLLERR)
117 if (pressure_revents & POLLPRI) {
118 if (
const std::optional<bool> is_low_opt = IsLowMemory();
119 is_low_opt && *is_low_opt)
127 static std::optional<bool> IsLowMemory() {
128 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer_or_err =
134 uint64_t mem_total = 0;
135 uint64_t mem_available = 0;
136 const int radix = 10;
137 bool parse_error =
false;
139 for (llvm::line_iterator iter(**buffer_or_err,
true); !iter.is_at_end();
141 llvm::StringRef line = *iter;
142 if (line.consume_front(
"MemTotal:"))
143 parse_error = line.ltrim().consumeInteger(radix, mem_total);
144 else if (line.consume_front(
"MemAvailable:"))
145 parse_error = line.ltrim().consumeInteger(radix, mem_available);
150 if (mem_total && mem_available)
157 if (mem_available == 0)
160 const uint64_t approx_memory_percent = (mem_available * 100) / mem_total;
161 const uint64_t low_memory_percent = 20;
162 return approx_memory_percent < low_memory_percent;
166 HostThread m_memory_monitor_thread;
175 HANDLE low_memory_notification =
176 CreateMemoryResourceNotification(LowMemoryResourceNotification);
177 if (!low_memory_notification)
181 if (WaitForSingleObject(low_memory_notification, g_timeout) ==
189 void Start()
override {
190 llvm::Expected<HostThread> memory_monitor_thread =
193 if (memory_monitor_thread) {
194 m_memory_monitor_thread = *memory_monitor_thread;
197 "failed to launch host thread: {0}");
201 void Stop()
override {
202 if (m_memory_monitor_thread.IsJoinable()) {
204 m_memory_monitor_thread.Join(
nullptr);
209 static constexpr uint32_t g_timeout = 1000;
210 std::atomic<bool> m_done =
false;
211 HostThread m_memory_monitor_thread;
215#if !defined(__APPLE__)
217#if defined(__linux__)
218 return std::make_unique<MemoryMonitorLinux>(std::move(callback));
220 return std::make_unique<MemoryMonitorWindows>(std::move(callback));
static lldb::thread_result_t MonitorThread(const Host::MonitorChildProcessCallback &callback, HANDLE process_handle)
#define LLDB_LOG_ERROR(log, error,...)
MemoryMonitor(Callback callback)
static std::unique_ptr< MemoryMonitor > Create(Callback callback)
std::function< void()> Callback
static llvm::Expected< HostThread > LaunchThread(llvm::StringRef name, std::function< lldb::thread_result_t()> thread_function, size_t min_stack_byte_size=0)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file)