]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
61ff7397 AZ |
2 | #pragma once |
3 | ||
4 | #include <stdbool.h> | |
5 | ||
59331b8e | 6 | #include "cgroup-util.h" |
61ff7397 AZ |
7 | #include "hashmap.h" |
8 | #include "psi-util.h" | |
9 | ||
10 | #define GROWING_SIZE_PERCENTILE 80 | |
11 | ||
12 | extern const struct hash_ops oomd_cgroup_ctx_hash_ops; | |
13 | ||
14 | typedef struct OomdCGroupContext OomdCGroupContext; | |
15 | typedef struct OomdSystemContext OomdSystemContext; | |
16 | ||
17 | typedef int (oomd_compare_t)(OomdCGroupContext * const *, OomdCGroupContext * const *); | |
18 | ||
19 | struct OomdCGroupContext { | |
20 | char *path; | |
21 | ||
22 | ResourcePressure memory_pressure; | |
23 | ||
24 | uint64_t current_memory_usage; | |
25 | ||
26 | uint64_t memory_min; | |
27 | uint64_t memory_low; | |
28 | uint64_t swap_usage; | |
29 | ||
30 | uint64_t last_pgscan; | |
31 | uint64_t pgscan; | |
32 | ||
59331b8e AZ |
33 | ManagedOOMPreference preference; |
34 | ||
61ff7397 AZ |
35 | /* These are only used by oomd_pressure_above for acting on high memory pressure. */ |
36 | loadavg_t mem_pressure_limit; | |
c20aa7b1 | 37 | usec_t mem_pressure_duration_usec; |
61ff7397 AZ |
38 | usec_t last_hit_mem_pressure_limit; |
39 | }; | |
40 | ||
41 | struct OomdSystemContext { | |
42 | uint64_t swap_total; | |
43 | uint64_t swap_used; | |
44 | }; | |
45 | ||
46 | OomdCGroupContext *oomd_cgroup_context_free(OomdCGroupContext *ctx); | |
47 | DEFINE_TRIVIAL_CLEANUP_FUNC(OomdCGroupContext*, oomd_cgroup_context_free); | |
48 | ||
49 | /* All hashmaps used with these functions are expected to be of the form | |
50 | * key: cgroup paths -> value: OomdCGroupContext. */ | |
51 | ||
52 | /* Scans all the OomdCGroupContexts in `h` and returns 1 and a set of pointers to those OomdCGroupContexts in `ret` | |
53 | * if any of them have exceeded their supplied memory pressure limits for the `duration` length of time. | |
54 | * `last_hit_mem_pressure_limit` is updated accordingly for each entry when the limit is exceeded, and when it returns | |
55 | * below the limit. | |
56 | * Returns 0 and sets `ret` to an empty set if no entries exceeded limits for `duration`. | |
57 | * Returns -ENOMEM for allocation errors. */ | |
58 | int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret); | |
59 | ||
60 | /* Sum up current OomdCGroupContexts' pgscan values and last interval's pgscan values in `h`. Returns true if the | |
61 | * current sum is higher than the last interval's sum (there was some reclaim activity). */ | |
62 | bool oomd_memory_reclaim(Hashmap *h); | |
63 | ||
64 | /* Returns true if the amount of swap free is below the percentage of swap specified by `threshold_percent`. */ | |
65 | bool oomd_swap_free_below(const OomdSystemContext *ctx, uint64_t threshold_percent); | |
66 | ||
59331b8e AZ |
67 | /* The compare functions will sort from largest to smallest, putting all the contexts with "avoid" at the end |
68 | * (after the smallest values). */ | |
1f76411b AZ |
69 | static inline int compare_pgscan_and_memory_usage(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) { |
70 | int r; | |
71 | ||
61ff7397 AZ |
72 | assert(c1); |
73 | assert(c2); | |
74 | ||
59331b8e AZ |
75 | r = CMP((*c1)->preference, (*c2)->preference); |
76 | if (r != 0) | |
77 | return r; | |
78 | ||
1f76411b AZ |
79 | r = CMP((*c2)->pgscan, (*c1)->pgscan); |
80 | if (r != 0) | |
81 | return r; | |
82 | ||
83 | return CMP((*c2)->current_memory_usage, (*c1)->current_memory_usage); | |
61ff7397 AZ |
84 | } |
85 | ||
86 | static inline int compare_swap_usage(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) { | |
59331b8e AZ |
87 | int r; |
88 | ||
61ff7397 AZ |
89 | assert(c1); |
90 | assert(c2); | |
91 | ||
59331b8e AZ |
92 | r = CMP((*c1)->preference, (*c2)->preference); |
93 | if (r != 0) | |
94 | return r; | |
95 | ||
95ca39f0 | 96 | return CMP((*c2)->swap_usage, (*c1)->swap_usage); |
61ff7397 AZ |
97 | } |
98 | ||
99 | /* Get an array of OomdCGroupContexts from `h`, qsorted from largest to smallest values according to `compare_func`. | |
100 | * If `prefix` is not NULL, only include OomdCGroupContexts whose paths start with prefix. Otherwise all paths are sorted. | |
101 | * Returns the number of sorted items; negative on error. */ | |
102 | int oomd_sort_cgroup_contexts(Hashmap *h, oomd_compare_t compare_func, const char *prefix, OomdCGroupContext ***ret); | |
103 | ||
104 | /* Returns a negative value on error, 0 if no processes were killed, or 1 if processes were killed. */ | |
105 | int oomd_cgroup_kill(const char *path, bool recurse, bool dry_run); | |
106 | ||
107 | /* The following oomd_kill_by_* functions return 1 if processes were killed, or negative otherwise. */ | |
108 | /* If `prefix` is supplied, only cgroups whose paths start with `prefix` are eligible candidates. Otherwise, | |
109 | * everything in `h` is a candidate. */ | |
110 | int oomd_kill_by_pgscan(Hashmap *h, const char *prefix, bool dry_run); | |
111 | int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run); | |
112 | ||
113 | int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret); | |
114 | int oomd_system_context_acquire(const char *proc_swaps_path, OomdSystemContext *ret); | |
115 | ||
116 | /* Get the OomdCGroupContext of `path` and insert it into `new_h`. The key for the inserted context will be `path`. | |
117 | * | |
118 | * `old_h` is used to get data used to calculate prior interval information. `old_h` can be NULL in which case there | |
119 | * was no prior data to reference. */ | |
120 | int oomd_insert_cgroup_context(Hashmap *old_h, Hashmap *new_h, const char *path); | |
5c616ecf AZ |
121 | |
122 | void oomd_dump_swap_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix); | |
123 | void oomd_dump_memory_pressure_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix); | |
124 | void oomd_dump_system_context(const OomdSystemContext *ctx, FILE *f, const char *prefix); |