/* The compare functions will sort from largest to smallest, putting all the contexts with "avoid" at the end
* (after the smallest values). */
-static inline int compare_pgscan_and_memory_usage(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) {
+static inline int compare_pgscan_rate_and_memory_usage(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) {
+ uint64_t last1, last2;
int r;
assert(c1);
if (r != 0)
return r;
- r = CMP((*c2)->pgscan, (*c1)->pgscan);
+ /* If last_pgscan > pgscan, assume the cgroup was recreated and reset last_pgscan to zero. */
+ last2 = (*c2)->last_pgscan;
+ if ((*c2)->last_pgscan > (*c2)->pgscan) {
+ log_info("Last pgscan %" PRIu64 "greater than current pgscan %" PRIu64 "for %s. Using last pgscan of zero.",
+ (*c2)->last_pgscan, (*c2)->pgscan, (*c2)->path);
+ last2 = 0;
+ }
+
+ last1 = (*c1)->last_pgscan;
+ if ((*c1)->last_pgscan > (*c1)->pgscan) {
+ log_info("Last pgscan %" PRIu64 "greater than current pgscan %" PRIu64 "for %s. Using last pgscan of zero.",
+ (*c1)->last_pgscan, (*c1)->pgscan, (*c1)->path);
+ last1 = 0;
+ }
+
+ r = CMP((*c2)->pgscan - last2, (*c1)->pgscan - last1);
if (r != 0)
return r;
/* The following oomd_kill_by_* functions return 1 if processes were killed, or negative otherwise. */
/* If `prefix` is supplied, only cgroups whose paths start with `prefix` are eligible candidates. Otherwise,
* everything in `h` is a candidate. */
-int oomd_kill_by_pgscan(Hashmap *h, const char *prefix, bool dry_run);
+int oomd_kill_by_pgscan_rate(Hashmap *h, const char *prefix, bool dry_run);
int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run);
int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret);
"/herp.slice/derp.scope",
"/herp.slice/derp.scope/sheep.service",
"/zupa.slice",
+ "/boop.slice",
"/omitted.slice",
"/avoid.slice");
- OomdCGroupContext ctx[6] = {
+ OomdCGroupContext ctx[7] = {
{ .path = paths[0],
.swap_usage = 20,
- .pgscan = 60,
+ .last_pgscan = 0,
+ .pgscan = 33,
.current_memory_usage = 10 },
{ .path = paths[1],
.swap_usage = 60,
- .pgscan = 40,
+ .last_pgscan = 33,
+ .pgscan = 1,
.current_memory_usage = 20 },
{ .path = paths[2],
.swap_usage = 40,
- .pgscan = 40,
+ .last_pgscan = 1,
+ .pgscan = 33,
.current_memory_usage = 40 },
{ .path = paths[3],
.swap_usage = 10,
- .pgscan = 80,
+ .last_pgscan = 33,
+ .pgscan = 2,
.current_memory_usage = 10 },
{ .path = paths[4],
+ .swap_usage = 11,
+ .last_pgscan = 33,
+ .pgscan = 33,
+ .current_memory_usage = 10 },
+ { .path = paths[5],
.swap_usage = 90,
- .pgscan = 100,
+ .last_pgscan = 0,
+ .pgscan = UINT64_MAX,
.preference = MANAGED_OOM_PREFERENCE_OMIT },
- { .path = paths[5],
+ { .path = paths[6],
.swap_usage = 99,
- .pgscan = 200,
+ .last_pgscan = 0,
+ .pgscan = UINT64_MAX,
.preference = MANAGED_OOM_PREFERENCE_AVOID },
};
assert_se(hashmap_put(h, "/herp.slice/derp.scope", &ctx[1]) >= 0);
assert_se(hashmap_put(h, "/herp.slice/derp.scope/sheep.service", &ctx[2]) >= 0);
assert_se(hashmap_put(h, "/zupa.slice", &ctx[3]) >= 0);
- assert_se(hashmap_put(h, "/omitted.slice", &ctx[4]) >= 0);
- assert_se(hashmap_put(h, "/avoid.slice", &ctx[5]) >= 0);
+ assert_se(hashmap_put(h, "/boop.slice", &ctx[4]) >= 0);
+ assert_se(hashmap_put(h, "/omitted.slice", &ctx[5]) >= 0);
+ assert_se(hashmap_put(h, "/avoid.slice", &ctx[6]) >= 0);
- assert_se(oomd_sort_cgroup_contexts(h, compare_swap_usage, NULL, &sorted_cgroups) == 5);
+ assert_se(oomd_sort_cgroup_contexts(h, compare_swap_usage, NULL, &sorted_cgroups) == 6);
assert_se(sorted_cgroups[0] == &ctx[1]);
assert_se(sorted_cgroups[1] == &ctx[2]);
assert_se(sorted_cgroups[2] == &ctx[0]);
- assert_se(sorted_cgroups[3] == &ctx[3]);
- assert_se(sorted_cgroups[4] == &ctx[5]);
+ assert_se(sorted_cgroups[3] == &ctx[4]);
+ assert_se(sorted_cgroups[4] == &ctx[3]);
+ assert_se(sorted_cgroups[5] == &ctx[6]);
sorted_cgroups = mfree(sorted_cgroups);
- assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan_and_memory_usage, NULL, &sorted_cgroups) == 5);
- assert_se(sorted_cgroups[0] == &ctx[3]);
- assert_se(sorted_cgroups[1] == &ctx[0]);
- assert_se(sorted_cgroups[2] == &ctx[2]);
+ assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan_rate_and_memory_usage, NULL, &sorted_cgroups) == 6);
+ assert_se(sorted_cgroups[0] == &ctx[0]);
+ assert_se(sorted_cgroups[1] == &ctx[2]);
+ assert_se(sorted_cgroups[2] == &ctx[3]);
assert_se(sorted_cgroups[3] == &ctx[1]);
- assert_se(sorted_cgroups[4] == &ctx[5]);
+ assert_se(sorted_cgroups[4] == &ctx[4]);
+ assert_se(sorted_cgroups[5] == &ctx[6]);
sorted_cgroups = mfree(sorted_cgroups);
- assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan_and_memory_usage, "/herp.slice/derp.scope", &sorted_cgroups) == 2);
+ assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan_rate_and_memory_usage, "/herp.slice/derp.scope", &sorted_cgroups) == 2);
assert_se(sorted_cgroups[0] == &ctx[2]);
assert_se(sorted_cgroups[1] == &ctx[1]);
assert_se(sorted_cgroups[2] == 0);
assert_se(sorted_cgroups[3] == 0);
assert_se(sorted_cgroups[4] == 0);
assert_se(sorted_cgroups[5] == 0);
+ assert_se(sorted_cgroups[6] == 0);
sorted_cgroups = mfree(sorted_cgroups);
}