Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
memory_pressure.h
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#ifndef DT_SYSTEM_MEMORY_PRESSURE_H
20#define DT_SYSTEM_MEMORY_PRESSURE_H
21
22/* Kernel memory pressure, as Linux PSI ("pressure stall information") reports it.
23 *
24 * A budget planned at startup and a floor on available RAM both answer "how much memory is
25 * left". Neither sees a system that still has memory available on paper but spends its time
26 * reclaiming it: swap full, other applications' pages evicted and faulted straight back in.
27 * That stall is what systemd-oomd watches, and it kills on it long before available RAM runs
28 * out. This reads the same counters, so the caches can give memory back first. */
29
30#include <stdint.h>
31
32#ifdef __cplusplus
33extern "C" {
34#endif
35
36#define DT_MEMORY_PRESSURE_MAX_LEVELS 16
37
38/* Cumulative time, in microseconds, during which every non-idle task was stalled on memory --
39 * the `total` of PSI's "full" line -- for each level that can come under pressure on our
40 * behalf: [0] the whole system (/proc/pressure/memory), then each cgroup v2 from the process's
41 * own up to the top of the hierarchy. Returns the number of levels written, 0 where the platform
42 * has no PSI.
43 *
44 * The counters only grow, so the share of a window is the difference of two reads divided by
45 * the window's length. The levels come in the same order for as long as the process stays in
46 * the same cgroup. Stateless: every call reads the kernel. */
48
49/* A watcher on the kernel's own triggers: descriptors, thread and stop channel, all of it platform
50 * detail nobody above this file has to spell. */
52
53/* Have the kernel wake us instead of polling: arm a PSI trigger -- `stall_us` of full stall within
54 * any `window_us` -- on every level that accepts one from this process, and call `stalled(user)`
55 * each time the kernel raises one. That is the whole system, and each cgroup above the process
56 * that it may write to: under systemd its own scope and app.slice, since the session's
57 * user@.service belongs to root. Unprivileged triggers need a window that is a multiple of 2 s;
58 * the kernel refuses the others.
59 *
60 * `stalled` runs on the watcher's own thread, so it owns nothing of the caller's and must take
61 * whatever guards what it touches. NULL where the platform has no PSI triggers or where no level
62 * accepted one -- a working configuration, not an error: whatever the caller measures for itself
63 * still runs, just not while nothing else of it does. */
65 void (*stalled)(void *user), void *user);
66
67/* Join the thread, release everything the watcher holds, and clear the caller's handle -- which is
68 * why it takes its address: a watcher that has been stopped is a pointer nobody may use again, and
69 * the one place that knows it is gone is the one that freed it. Nothing `stalled` touches may go
70 * away before this returns. NULL-safe, like every function here, and a no-op on a handle that is
71 * already NULL. */
73
74/* How many levels the watcher was armed on -- what a caller has to log; 0 for NULL. */
76
77#ifdef __cplusplus
78}
79#endif
80
81#endif // DT_SYSTEM_MEMORY_PRESSURE_H
82
83// clang-format off
84// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
85// vim: shiftwidth=2 expandtab tabstop=2 cindent
86// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
87// clang-format on
#define max_levels
int dt_memory_pressure_watch_levels(const dt_memory_pressure_watch_t *watch)
int dt_memory_pressure_read_full_stall(uint64_t *total_us, int max_levels)
void dt_memory_pressure_watch_stop(dt_memory_pressure_watch_t **watch)
dt_memory_pressure_watch_t * dt_memory_pressure_watch_start(uint64_t stall_us, uint64_t window_us, void(*stalled)(void *user), void *user)
unsigned __int64 uint64_t
Definition strptime.c:75
void(* stalled)(void *user)