Merge pull request #18659 from poettering/permyriadification

use scaling relative to UINT32_MAX instead of percentages/permyriads wherever we can
This commit is contained in:
Yu Watanabe 2021-02-19 14:22:10 +09:00 committed by GitHub
commit 5be5d1f2a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 601 additions and 421 deletions

View File

@ -48,36 +48,38 @@
<variablelist class='config-directives'>
<varlistentry>
<term><varname>SwapUsedLimitPercent=</varname></term>
<term><varname>SwapUsedLimit=</varname></term>
<listitem><para>Sets the limit for swap usage on the system before <command>systemd-oomd</command> will
take action. If the percentage of swap used on the system is more than what is defined here,
<command>systemd-oomd</command> will act on eligible descendant cgroups, starting from the ones with the
highest swap usage to the lowest swap usage. Which cgroups are monitored and what
action gets taken depends on what the unit has configured for <varname>ManagedOOMSwap=</varname>.
Takes a percentage value between 0% and 100%, inclusive. Defaults to 90%.</para></listitem>
<listitem><para>Sets the limit for swap usage on the system before <command>systemd-oomd</command>
will take action. If the fraction of swap used on the system is more than what is defined here,
<command>systemd-oomd</command> will act on eligible descendant control groups, starting from the
ones with the highest swap usage to the lowest swap usage. Which control groups are monitored and
what action gets taken depends on what the unit has configured for
<varname>ManagedOOMSwap=</varname>. Takes a value specified in percent (when suffixed with "%"),
permille ("‰") or permyriad ("‱"), between 0% and 100%, inclusive. Defaults to 90%.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultMemoryPressureLimit=</varname></term>
<listitem><para>Sets the limit for memory pressure on the unit's cgroup before <command>systemd-oomd</command>
will take action. A unit can override this value with <varname>ManagedOOMMemoryPressureLimit=</varname>.
The memory pressure for this property represents the fraction of time in a 10 second window in which all tasks
in the cgroup were delayed. For each monitored cgroup, if the memory pressure on that cgroup exceeds the
limit set for longer than the duration set by <varname>DefaultMemoryPressureDurationSec=</varname>,
<command>systemd-oomd</command> will act on eligible descendant cgroups,
starting from the ones with the most reclaim activity to the least reclaim activity. Which cgroups are
monitored and what action gets taken depends on what the unit has configured for
<varname>ManagedOOMMemoryPressure=</varname>. Takes a percentage value between 0% and 100%, inclusive.
Defaults to 60%.</para></listitem>
<listitem><para>Sets the limit for memory pressure on the unit's control group before
<command>systemd-oomd</command> will take action. A unit can override this value with
<varname>ManagedOOMMemoryPressureLimit=</varname>. The memory pressure for this property represents
the fraction of time in a 10 second window in which all tasks in the control group were delayed. For
each monitored control group, if the memory pressure on that control group exceeds the limit set for
longer than the duration set by <varname>DefaultMemoryPressureDurationSec=</varname>,
<command>systemd-oomd</command> will act on eligible descendant control groups, starting from the
ones with the most reclaim activity to the least reclaim activity. Which control groups are monitored
and what action gets taken depends on what the unit has configured for
<varname>ManagedOOMMemoryPressure=</varname>. Takes a fraction specified in the same way as
<varname>SwapUsedLimit=</varname> above. Defaults to 60%.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultMemoryPressureDurationSec=</varname></term>
<listitem><para>Sets the amount of time a unit's cgroup needs to have exceeded memory pressure limits before
<command>systemd-oomd</command> will take action. Memory pressure limits are defined by
<listitem><para>Sets the amount of time a unit's control group needs to have exceeded memory pressure
limits before <command>systemd-oomd</command> will take action. Memory pressure limits are defined by
<varname>DefaultMemoryPressureLimit=</varname> and <varname>ManagedOOMMemoryPressureLimit=</varname>.
Defaults to 30 seconds when this property is unset or set to 0.</para></listitem>
</varlistentry>

View File

@ -2469,7 +2469,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMMemoryPressure = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
readonly u ManagedOOMMemoryPressureLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMPreference = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@ -2994,7 +2994,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property ManagedOOMMemoryPressure is not documented!-->
<!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
<!--property ManagedOOMMemoryPressureLimit is not documented!-->
<!--property ManagedOOMPreference is not documented!-->
@ -3560,7 +3560,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimit"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
@ -4229,7 +4229,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMMemoryPressure = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
readonly u ManagedOOMMemoryPressureLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMPreference = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@ -4782,7 +4782,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<!--property ManagedOOMMemoryPressure is not documented!-->
<!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
<!--property ManagedOOMMemoryPressureLimit is not documented!-->
<!--property ManagedOOMPreference is not documented!-->
@ -5346,7 +5346,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimit"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
@ -5928,7 +5928,7 @@ node /org/freedesktop/systemd1/unit/home_2emount {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMMemoryPressure = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
readonly u ManagedOOMMemoryPressureLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMPreference = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@ -6409,7 +6409,7 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<!--property ManagedOOMMemoryPressure is not documented!-->
<!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
<!--property ManagedOOMMemoryPressureLimit is not documented!-->
<!--property ManagedOOMPreference is not documented!-->
@ -6891,7 +6891,7 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimit"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
@ -7594,7 +7594,7 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMMemoryPressure = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
readonly u ManagedOOMMemoryPressureLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMPreference = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@ -8061,7 +8061,7 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<!--property ManagedOOMMemoryPressure is not documented!-->
<!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
<!--property ManagedOOMMemoryPressureLimit is not documented!-->
<!--property ManagedOOMPreference is not documented!-->
@ -8529,7 +8529,7 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimit"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
@ -9085,7 +9085,7 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMMemoryPressure = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
readonly u ManagedOOMMemoryPressureLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMPreference = '...';
};
@ -9222,7 +9222,7 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
<!--property ManagedOOMMemoryPressure is not documented!-->
<!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
<!--property ManagedOOMMemoryPressureLimit is not documented!-->
<!--property ManagedOOMPreference is not documented!-->
@ -9364,7 +9364,7 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimit"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
@ -9526,7 +9526,7 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMMemoryPressure = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
readonly u ManagedOOMMemoryPressureLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ManagedOOMPreference = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@ -9679,7 +9679,7 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
<!--property ManagedOOMMemoryPressure is not documented!-->
<!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
<!--property ManagedOOMMemoryPressureLimit is not documented!-->
<!--property ManagedOOMPreference is not documented!-->
@ -9847,7 +9847,7 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressure"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimit"/>
<variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>

View File

@ -77,7 +77,13 @@ uint64_t physical_memory(void) {
}
uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
uint64_t p, m, ps, r;
uint64_t p, m, ps;
/* Shortcut two special cases */
if (v == 0)
return 0;
if (v == max)
return physical_memory();
assert(max > 0);
@ -90,17 +96,16 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
p = physical_memory() / ps;
assert(p > 0);
m = p * v;
if (m / p != v)
if (v > UINT64_MAX / p)
return UINT64_MAX;
m = p * v;
m /= max;
r = m * ps;
if (r / ps != m)
if (m > UINT64_MAX / ps)
return UINT64_MAX;
return r;
return m * ps;
}
uint64_t system_tasks_max(void) {
@ -138,6 +143,12 @@ uint64_t system_tasks_max(void) {
uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
uint64_t t, m;
/* Shortcut two special cases */
if (v == 0)
return 0;
if (v == max)
return system_tasks_max();
assert(max > 0);
/* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
@ -146,9 +157,9 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
t = system_tasks_max();
assert(t > 0);
m = t * v;
if (m / t != v) /* overflow? */
if (v > UINT64_MAX / t) /* overflow? */
return UINT64_MAX;
m = t * v;
return m / max;
}

View File

@ -176,6 +176,8 @@ basic_sources = files('''
path-lookup.h
path-util.c
path-util.h
percent-util.c
percent-util.h
prioq.c
prioq.h
proc-cmdline.c

View File

@ -627,146 +627,6 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
return 0;
}
static int parse_parts_value_whole(const char *p, const char *symbol) {
const char *pc, *n;
int r, v;
pc = endswith(p, symbol);
if (!pc)
return -EINVAL;
n = strndupa(p, pc - p);
r = safe_atoi(n, &v);
if (r < 0)
return r;
if (v < 0)
return -ERANGE;
return v;
}
static int parse_parts_value_with_tenths_place(const char *p, const char *symbol) {
const char *pc, *dot, *n;
int r, q, v;
pc = endswith(p, symbol);
if (!pc)
return -EINVAL;
dot = memchr(p, '.', pc - p);
if (dot) {
if (dot + 2 != pc)
return -EINVAL;
if (dot[1] < '0' || dot[1] > '9')
return -EINVAL;
q = dot[1] - '0';
n = strndupa(p, dot - p);
} else {
q = 0;
n = strndupa(p, pc - p);
}
r = safe_atoi(n, &v);
if (r < 0)
return r;
if (v < 0)
return -ERANGE;
if (v > (INT_MAX - q) / 10)
return -ERANGE;
v = v * 10 + q;
return v;
}
static int parse_parts_value_with_hundredths_place(const char *p, const char *symbol) {
const char *pc, *dot, *n;
int r, q, v;
pc = endswith(p, symbol);
if (!pc)
return -EINVAL;
dot = memchr(p, '.', pc - p);
if (dot) {
if (dot + 3 != pc)
return -EINVAL;
if (dot[1] < '0' || dot[1] > '9' || dot[2] < '0' || dot[2] > '9')
return -EINVAL;
q = (dot[1] - '0') * 10 + (dot[2] - '0');
n = strndupa(p, dot - p);
} else {
q = 0;
n = strndupa(p, pc - p);
}
r = safe_atoi(n, &v);
if (r < 0)
return r;
if (v < 0)
return -ERANGE;
if (v > (INT_MAX - q) / 100)
return -ERANGE;
v = v * 100 + q;
return v;
}
int parse_percent_unbounded(const char *p) {
return parse_parts_value_whole(p, "%");
}
int parse_percent(const char *p) {
int v;
v = parse_percent_unbounded(p);
if (v > 100)
return -ERANGE;
return v;
}
int parse_permille_unbounded(const char *p) {
const char *pm;
pm = endswith(p, "");
if (pm)
return parse_parts_value_whole(p, "");
return parse_parts_value_with_tenths_place(p, "%");
}
int parse_permille(const char *p) {
int v;
v = parse_permille_unbounded(p);
if (v > 1000)
return -ERANGE;
return v;
}
int parse_permyriad_unbounded(const char *p) {
const char *pm;
pm = endswith(p, "");
if (pm)
return parse_parts_value_whole(p, "");
pm = endswith(p, "");
if (pm)
return parse_parts_value_with_tenths_place(p, "");
return parse_parts_value_with_hundredths_place(p, "%");
}
int parse_permyriad(const char *p) {
int v;
v = parse_permyriad_unbounded(p);
if (v > 10000)
return -ERANGE;
return v;
}
int parse_nice(const char *p, int *ret) {
int n, r;

View File

@ -127,15 +127,6 @@ int safe_atod(const char *s, double *ret_d);
int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
int parse_percent_unbounded(const char *p);
int parse_percent(const char *p);
int parse_permille_unbounded(const char *p);
int parse_permille(const char *p);
int parse_permyriad_unbounded(const char *p);
int parse_permyriad(const char *p);
int parse_nice(const char *p, int *ret);
int parse_ip_port(const char *s, uint16_t *ret);

157
src/basic/percent-util.c Normal file
View File

@ -0,0 +1,157 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "percent-util.h"
#include "string-util.h"
#include "parse-util.h"
static int parse_parts_value_whole(const char *p, const char *symbol) {
const char *pc, *n;
int r, v;
pc = endswith(p, symbol);
if (!pc)
return -EINVAL;
n = strndupa(p, pc - p);
r = safe_atoi(n, &v);
if (r < 0)
return r;
if (v < 0)
return -ERANGE;
return v;
}
static int parse_parts_value_with_tenths_place(const char *p, const char *symbol) {
const char *pc, *dot, *n;
int r, q, v;
pc = endswith(p, symbol);
if (!pc)
return -EINVAL;
dot = memchr(p, '.', pc - p);
if (dot) {
if (dot + 2 != pc)
return -EINVAL;
if (dot[1] < '0' || dot[1] > '9')
return -EINVAL;
q = dot[1] - '0';
n = strndupa(p, dot - p);
} else {
q = 0;
n = strndupa(p, pc - p);
}
r = safe_atoi(n, &v);
if (r < 0)
return r;
if (v < 0)
return -ERANGE;
if (v > (INT_MAX - q) / 10)
return -ERANGE;
v = v * 10 + q;
return v;
}
static int parse_parts_value_with_hundredths_place(const char *p, const char *symbol) {
const char *pc, *dot, *n;
int r, q, v;
pc = endswith(p, symbol);
if (!pc)
return -EINVAL;
dot = memchr(p, '.', pc - p);
if (dot) {
if (dot + 3 == pc) {
/* Support two places after the dot */
if (dot[1] < '0' || dot[1] > '9' || dot[2] < '0' || dot[2] > '9')
return -EINVAL;
q = (dot[1] - '0') * 10 + (dot[2] - '0');
} else if (dot + 2 == pc) {
/* Support one place after the dot */
if (dot[1] < '0' || dot[1] > '9')
return -EINVAL;
q = (dot[1] - '0') * 10;
} else
/* We do not support zero or more than two places */
return -EINVAL;
n = strndupa(p, dot - p);
} else {
q = 0;
n = strndupa(p, pc - p);
}
r = safe_atoi(n, &v);
if (r < 0)
return r;
if (v < 0)
return -ERANGE;
if (v > (INT_MAX - q) / 100)
return -ERANGE;
v = v * 100 + q;
return v;
}
int parse_percent_unbounded(const char *p) {
return parse_parts_value_whole(p, "%");
}
int parse_percent(const char *p) {
int v;
v = parse_percent_unbounded(p);
if (v > 100)
return -ERANGE;
return v;
}
int parse_permille_unbounded(const char *p) {
const char *pm;
pm = endswith(p, "");
if (pm)
return parse_parts_value_whole(p, "");
return parse_parts_value_with_tenths_place(p, "%");
}
int parse_permille(const char *p) {
int v;
v = parse_permille_unbounded(p);
if (v > 1000)
return -ERANGE;
return v;
}
int parse_permyriad_unbounded(const char *p) {
const char *pm;
pm = endswith(p, "");
if (pm)
return parse_parts_value_whole(p, "");
pm = endswith(p, "");
if (pm)
return parse_parts_value_with_tenths_place(p, "");
return parse_parts_value_with_hundredths_place(p, "%");
}
int parse_permyriad(const char *p) {
int v;
v = parse_permyriad_unbounded(p);
if (v > 10000)
return -ERANGE;
return v;
}

64
src/basic/percent-util.h Normal file
View File

@ -0,0 +1,64 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <errno.h>
#include <inttypes.h>
#include "macro.h"
int parse_percent_unbounded(const char *p);
int parse_percent(const char *p);
int parse_permille_unbounded(const char *p);
int parse_permille(const char *p);
int parse_permyriad_unbounded(const char *p);
int parse_permyriad(const char *p);
/* Some macro-like helpers that convert a percent/permille/permyriad value (as parsed by parse_percent()) to
* a value relative to 100% == 2^32-1. Rounds to closest. */
static inline uint32_t UINT32_SCALE_FROM_PERCENT(int percent) {
assert_cc(INT_MAX <= UINT32_MAX);
return (uint32_t) (((uint64_t) percent * UINT32_MAX + 50) / 100U);
}
static inline uint32_t UINT32_SCALE_FROM_PERMILLE(int permille) {
return (uint32_t) (((uint64_t) permille * UINT32_MAX + 500) / 1000U);
}
static inline uint32_t UINT32_SCALE_FROM_PERMYRIAD(int permyriad) {
return (uint32_t) (((uint64_t) permyriad * UINT32_MAX + 5000) / 10000U);
}
static inline int UINT32_SCALE_TO_PERCENT(uint32_t scale) {
uint32_t u;
u = (uint32_t) ((((uint64_t) scale) * 100U + UINT32_MAX/2) / UINT32_MAX);
if (u > INT_MAX)
return -ERANGE;
return (int) u;
}
static inline int UINT32_SCALE_TO_PERMILLE(uint32_t scale) {
uint32_t u;
u = (uint32_t) ((((uint64_t) scale) * 1000U + UINT32_MAX/2) / UINT32_MAX);
if (u > INT_MAX)
return -ERANGE;
return (int) u;
}
static inline int UINT32_SCALE_TO_PERMYRIAD(uint32_t scale) {
uint32_t u;
u = (uint32_t) ((((uint64_t) scale) * 10000U + UINT32_MAX/2) / UINT32_MAX);
if (u > INT_MAX)
return -ERANGE;
return (int) u;
}
#define PERMYRIAD_AS_PERCENT_FORMAT_STR "%i.%02i%%"
#define PERMYRIAD_AS_PERCENT_FORMAT_VAL(x) ((x)/100), ((x)%100)

View File

@ -21,6 +21,7 @@
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "percent-util.h"
#include "process-util.h"
#include "procfs-util.h"
#include "special.h"
@ -418,7 +419,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
"%sDelegate: %s\n"
"%sManagedOOMSwap: %s\n"
"%sManagedOOMMemoryPressure: %s\n"
"%sManagedOOMMemoryPressureLimit: %" PRIu32 ".%02" PRIu32 "%%\n"
"%sManagedOOMMemoryPressureLimit: " PERMYRIAD_AS_PERCENT_FORMAT_STR "\n"
"%sManagedOOMPreference: %s%%\n",
prefix, yes_no(c->cpu_accounting),
prefix, yes_no(c->io_accounting),
@ -452,7 +453,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
prefix, yes_no(c->delegate),
prefix, managed_oom_mode_to_string(c->moom_swap),
prefix, managed_oom_mode_to_string(c->moom_mem_pressure),
prefix, c->moom_mem_pressure_limit_permyriad / 100, c->moom_mem_pressure_limit_permyriad % 100,
prefix, PERMYRIAD_AS_PERCENT_FORMAT_VAL(UINT32_SCALE_TO_PERMYRIAD(c->moom_mem_pressure_limit)),
prefix, managed_oom_preference_to_string(c->moom_preference));
if (c->delegate) {

View File

@ -163,7 +163,7 @@ struct CGroupContext {
/* Settings for systemd-oomd */
ManagedOOMMode moom_swap;
ManagedOOMMode moom_mem_pressure;
uint32_t moom_mem_pressure_limit_permyriad;
uint32_t moom_mem_pressure_limit; /* Normalized to 2^32-1 == 100% */
ManagedOOMPreference moom_preference;
};

View File

@ -83,7 +83,7 @@ static int build_managed_oom_json_array_element(Unit *u, const char *property, J
JSON_BUILD_PAIR("mode", JSON_BUILD_STRING(mode)),
JSON_BUILD_PAIR("path", JSON_BUILD_STRING(u->cgroup_path)),
JSON_BUILD_PAIR("property", JSON_BUILD_STRING(property)),
JSON_BUILD_PAIR_CONDITION(use_limit, "limit", JSON_BUILD_UNSIGNED(c->moom_mem_pressure_limit_permyriad))));
JSON_BUILD_PAIR_CONDITION(use_limit, "limit", JSON_BUILD_UNSIGNED(c->moom_mem_pressure_limit))));
}
int manager_varlink_send_managed_oom_update(Unit *u) {

View File

@ -16,6 +16,7 @@
#include "fileio.h"
#include "limits-util.h"
#include "path-util.h"
#include "percent-util.h"
BUS_DEFINE_PROPERTY_GET(bus_property_get_tasks_max, "t", TasksMax, tasks_max_resolve);
@ -395,7 +396,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("DisableControllers", "as", property_get_cgroup_mask, offsetof(CGroupContext, disable_controllers), 0),
SD_BUS_PROPERTY("ManagedOOMSwap", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_swap), 0),
SD_BUS_PROPERTY("ManagedOOMMemoryPressure", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_mem_pressure), 0),
SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimitPermyriad", "u", NULL, offsetof(CGroupContext, moom_mem_pressure_limit_permyriad), 0),
SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimit", "u", NULL, offsetof(CGroupContext, moom_mem_pressure_limit), 0),
SD_BUS_PROPERTY("ManagedOOMPreference", "s", property_get_managed_oom_preference, offsetof(CGroupContext, moom_preference), 0),
SD_BUS_VTABLE_END
};
@ -704,10 +705,10 @@ static int bus_cgroup_set_boolean(
/* Prepare to chop off suffix */ \
assert_se(endswith(name, "Scale")); \
\
uint32_t scaled = DIV_ROUND_UP((uint64_t) raw * 1000, (uint64_t) UINT32_MAX); \
unit_write_settingf(u, flags, name, "%.*s=%" PRIu32 ".%" PRIu32 "%%", \
int scaled = UINT32_SCALE_TO_PERMYRIAD(raw); \
unit_write_settingf(u, flags, name, "%.*s=" PERMYRIAD_AS_PERCENT_FORMAT_STR, \
(int)(strlen(name) - strlen("Scale")), name, \
scaled / 10, scaled % 10); \
PERMYRIAD_AS_PERCENT_FORMAT_VAL(scaled)); \
} \
\
return 1; \
@ -1698,7 +1699,7 @@ int bus_cgroup_set_property(
return 1;
}
if (streq(name, "ManagedOOMMemoryPressureLimitPermyriad")) {
if (streq(name, "ManagedOOMMemoryPressureLimit")) {
uint32_t v;
if (!UNIT_VTABLE(u)->can_set_managed_oom)
@ -1708,12 +1709,11 @@ int bus_cgroup_set_property(
if (r < 0)
return r;
if (v > 10000)
return -ERANGE;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->moom_mem_pressure_limit_permyriad = v;
unit_write_settingf(u, flags, name, "ManagedOOMMemoryPressureLimit=%" PRIu32 ".%02" PRIu32 "%%", v / 100, v % 100);
c->moom_mem_pressure_limit = v;
unit_write_settingf(u, flags, name,
"ManagedOOMMemoryPressureLimit=" PERMYRIAD_AS_PERCENT_FORMAT_STR,
PERMYRIAD_AS_PERCENT_FORMAT_VAL(UINT32_SCALE_TO_PERMYRIAD(v)));
}
if (c->moom_mem_pressure == MANAGED_OOM_KILL)

View File

@ -229,7 +229,7 @@ $1.IPIngressFilterPath, config_parse_ip_filter_bpf_progs,
$1.IPEgressFilterPath, config_parse_ip_filter_bpf_progs, 0, offsetof($1, cgroup_context.ip_filters_egress)
$1.ManagedOOMSwap, config_parse_managed_oom_mode, 0, offsetof($1, cgroup_context.moom_swap)
$1.ManagedOOMMemoryPressure, config_parse_managed_oom_mode, 0, offsetof($1, cgroup_context.moom_mem_pressure)
$1.ManagedOOMMemoryPressureLimit, config_parse_managed_oom_mem_pressure_limit, 0, offsetof($1, cgroup_context.moom_mem_pressure_limit_permyriad)
$1.ManagedOOMMemoryPressureLimit, config_parse_managed_oom_mem_pressure_limit, 0, offsetof($1, cgroup_context.moom_mem_pressure_limit)
$1.ManagedOOMPreference, config_parse_managed_oom_preference, 0, offsetof($1, cgroup_context.moom_preference)
$1.NetClass, config_parse_warn_compat, DISABLED_LEGACY, 0'
)m4_dnl

View File

@ -46,6 +46,7 @@
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "percent-util.h"
#include "process-util.h"
#if HAVE_SECCOMP
#include "seccomp-util.h"
@ -3593,13 +3594,13 @@ int config_parse_cpu_quota(
return 0;
}
r = parse_permille_unbounded(rvalue);
r = parse_permyriad_unbounded(rvalue);
if (r <= 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue);
return 0;
}
c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 1000U;
c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 10000U;
return 0;
}
@ -3664,7 +3665,7 @@ int config_parse_memory_limit(
bytes = CGROUP_LIMIT_MIN;
else if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
r = parse_permille(rvalue);
r = parse_permyriad(rvalue);
if (r < 0) {
r = parse_size(rvalue, 1024, &bytes);
if (r < 0) {
@ -3672,7 +3673,7 @@ int config_parse_memory_limit(
return 0;
}
} else
bytes = physical_memory_scale(r, 1000U);
bytes = physical_memory_scale(r, 10000U);
if (bytes >= UINT64_MAX ||
(bytes <= 0 && !STR_IN_SET(lvalue, "MemorySwapMax", "MemoryLow", "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin"))) {
@ -3734,9 +3735,9 @@ int config_parse_tasks_max(
return 0;
}
r = parse_permille(rvalue);
r = parse_permyriad(rvalue);
if (r >= 0)
*tasks_max = (TasksMax) { r, 1000U }; /* r‰ */
*tasks_max = (TasksMax) { r, 10000U }; /* r‱ */
else {
r = safe_atou64(rvalue, &v);
if (r < 0) {
@ -3842,6 +3843,7 @@ int config_parse_managed_oom_mode(
const char *rvalue,
void *data,
void *userdata) {
ManagedOOMMode *mode = data, m;
UnitType t;
@ -3861,6 +3863,7 @@ int config_parse_managed_oom_mode(
log_syntax(unit, LOG_WARNING, filename, line, m, "Invalid syntax, ignoring: %s", rvalue);
return 0;
}
*mode = m;
return 0;
}
@ -3876,6 +3879,7 @@ int config_parse_managed_oom_mem_pressure_limit(
const char *rvalue,
void *data,
void *userdata) {
uint32_t *limit = data;
UnitType t;
int r;
@ -3897,7 +3901,8 @@ int config_parse_managed_oom_mem_pressure_limit(
return 0;
}
*limit = r;
/* Normalize to 2^32-1 == 100% */
*limit = UINT32_SCALE_FROM_PERMYRIAD(r);
return 0;
}

View File

@ -1256,8 +1256,8 @@ static int bump_rlimit_memlock(struct rlimit *saved_rlimit) {
* must be unsigned, hence this is a given, but let's make this clear here. */
assert_cc(RLIM_INFINITY > 0);
mm = physical_memory() / 8; /* Let's scale how much we allow to be locked by the amount of physical
* RAM. We allow an eighth to be locked by us, just to pick a value. */
mm = physical_memory_scale(1, 8); /* Let's scale how much we allow to be locked by the amount of physical
* RAM. We allow an eighth to be locked by us, just to pick a value. */
new_rlimit = (struct rlimit) {
.rlim_cur = MAX3(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_cur, mm),

View File

@ -26,6 +26,7 @@
#include "parse-argument.h"
#include "parse-util.h"
#include "path-util.h"
#include "percent-util.h"
#include "pkcs11-util.h"
#include "pretty-print.h"
#include "process-util.h"
@ -1567,7 +1568,7 @@ static int resize_home(int argc, char *argv[], void *userdata) {
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
if (arg_disk_size_relative != UINT64_MAX ||
(argc > 2 && parse_percent(argv[2]) >= 0))
(argc > 2 && parse_permyriad(argv[2]) >= 0))
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Relative disk size specification currently not supported when resizing.");
@ -2653,7 +2654,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
r = parse_permille(optarg);
r = parse_permyriad(optarg);
if (r < 0) {
r = parse_size(optarg, 1024, &arg_disk_size);
if (r < 0)
@ -2670,7 +2671,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_disk_size_relative = UINT64_MAX;
} else {
/* Normalize to UINT32_MAX == 100% */
arg_disk_size_relative = (uint64_t) r * UINT32_MAX / 1000U;
arg_disk_size_relative = UINT32_SCALE_FROM_PERMYRIAD(r);
r = drop_from_identity("diskSize");
if (r < 0)

View File

@ -22,6 +22,7 @@
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
#include "percent-util.h"
#include "process-util.h"
#include "service-util.h"
#include "signal-util.h"

View File

@ -19,11 +19,12 @@
#include "label.h"
#include "limits-util.h"
#include "logind-dbus.h"
#include "logind-user.h"
#include "logind-user-dbus.h"
#include "logind-user.h"
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
#include "percent-util.h"
#include "rm-rf.h"
#include "serialize.h"
#include "special.h"
@ -907,9 +908,9 @@ int config_parse_tmpfs_size(
assert(data);
/* First, try to parse as percentage */
r = parse_permille(rvalue);
if (r > 0 && r < 1000)
*sz = physical_memory_scale(r, 1000U);
r = parse_permyriad(rvalue);
if (r > 0)
*sz = physical_memory_scale(r, 10000U);
else {
uint64_t k;

View File

@ -34,6 +34,7 @@
#include "pam-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "percent-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "socket-util.h"
@ -334,9 +335,9 @@ static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, co
return PAM_SUCCESS;
}
r = parse_permille(limit);
r = parse_permyriad(limit);
if (r >= 0) {
r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", UINT32_SCALE_FROM_PERMYRIAD(r));
if (r < 0)
return pam_bus_log_create_error(handle, r);

View File

@ -5,6 +5,7 @@
#include "extract-word.h"
#include "fileio.h"
#include "parse-util.h"
#include "percent-util.h"
#include "tc-util.h"
#include "time-util.h"
@ -57,17 +58,17 @@ int tc_time_to_tick(usec_t t, uint32_t *ret) {
return 0;
}
int parse_tc_percent(const char *s, uint32_t *percent) {
int parse_tc_percent(const char *s, uint32_t *ret_fraction) {
int r;
assert(s);
assert(percent);
assert(ret_fraction);
r = parse_permille(s);
r = parse_permyriad(s);
if (r < 0)
return r;
*percent = (double) r / 1000 * UINT32_MAX;
*ret_fraction = (double) r / 10000 * UINT32_MAX;
return 0;
}

View File

@ -10,12 +10,13 @@
#include "oomd-manager-bus.h"
#include "oomd-manager.h"
#include "path-util.h"
#include "percent-util.h"
typedef struct ManagedOOMReply {
ManagedOOMMode mode;
char *path;
char *property;
unsigned limit;
uint32_t limit;
} ManagedOOMReply;
static void managed_oom_reply_destroy(ManagedOOMReply *reply) {
@ -52,10 +53,10 @@ static int process_managed_oom_reply(
assert(m);
static const JsonDispatch dispatch_table[] = {
{ "mode", JSON_VARIANT_STRING, managed_oom_mode, offsetof(ManagedOOMReply, mode), JSON_MANDATORY },
{ "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, path), JSON_MANDATORY },
{ "property", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, property), JSON_MANDATORY },
{ "limit", JSON_VARIANT_UNSIGNED, json_dispatch_unsigned, offsetof(ManagedOOMReply, limit), 0 },
{ "mode", JSON_VARIANT_STRING, managed_oom_mode, offsetof(ManagedOOMReply, mode), JSON_MANDATORY },
{ "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, path), JSON_MANDATORY },
{ "property", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, property), JSON_MANDATORY },
{ "limit", JSON_VARIANT_UNSIGNED, json_dispatch_uint32, offsetof(ManagedOOMReply, limit), 0 },
{},
};
@ -86,7 +87,8 @@ static int process_managed_oom_reply(
if (ret == -ENOMEM) {
r = ret;
goto finish;
} else if (ret < 0)
}
if (ret < 0)
continue;
monitor_hm = streq(reply.property, "ManagedOOMSwap") ?
@ -99,14 +101,15 @@ static int process_managed_oom_reply(
limit = m->default_mem_pressure_limit;
if (streq(reply.property, "ManagedOOMMemoryPressure")) {
if (reply.limit > 10000)
if (streq(reply.property, "ManagedOOMMemoryPressure") && reply.limit > 0) {
int permyriad = UINT32_SCALE_TO_PERMYRIAD(reply.limit);
ret = store_loadavg_fixed_point(
(unsigned long) permyriad / 100,
(unsigned long) permyriad % 100,
&limit);
if (ret < 0)
continue;
else if (reply.limit != 0) {
ret = store_loadavg_fixed_point((unsigned long) reply.limit / 100, (unsigned long) reply.limit % 100, &limit);
if (ret < 0)
continue;
}
}
ret = oomd_insert_cgroup_context(NULL, monitor_hm, empty_to_root(reply.path));
@ -348,11 +351,11 @@ static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, vo
}
}
if (oomd_swap_free_below(&m->system_context, (100 - m->swap_used_limit))) {
if (oomd_swap_free_below(&m->system_context, 10000 - m->swap_used_limit_permyriad)) {
_cleanup_hashmap_free_ Hashmap *candidates = NULL;
log_notice("Swap used (%"PRIu64") / total (%"PRIu64") is more than %u%%",
m->system_context.swap_used, m->system_context.swap_total, m->swap_used_limit);
log_notice("Swap used (%"PRIu64") / total (%"PRIu64") is more than " PERMYRIAD_AS_PERCENT_FORMAT_STR,
m->system_context.swap_used, m->system_context.swap_total, PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad));
r = get_monitored_cgroup_contexts_candidates(m->monitored_swap_cgroup_contexts, &candidates);
if (r == -ENOMEM)
@ -478,7 +481,13 @@ static int manager_connect_bus(Manager *m) {
return 0;
}
int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec) {
int manager_start(
Manager *m,
bool dry_run,
int swap_used_limit_permyriad,
int mem_pressure_limit_permyriad,
usec_t mem_pressure_usec) {
unsigned long l, f;
int r;
@ -486,10 +495,10 @@ int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressur
m->dry_run = dry_run;
m->swap_used_limit = swap_used_limit != -1 ? swap_used_limit : DEFAULT_SWAP_USED_LIMIT;
assert(m->swap_used_limit <= 100);
m->swap_used_limit_permyriad = swap_used_limit_permyriad >= 0 ? swap_used_limit_permyriad : DEFAULT_SWAP_USED_LIMIT_PERCENT * 100;
assert(m->swap_used_limit_permyriad <= 10000);
if (mem_pressure_limit_permyriad != -1) {
if (mem_pressure_limit_permyriad >= 0) {
assert(mem_pressure_limit_permyriad <= 10000);
l = mem_pressure_limit_permyriad / 100;
@ -537,12 +546,12 @@ int manager_get_dump_string(Manager *m, char **ret) {
fprintf(f,
"Dry Run: %s\n"
"Swap Used Limit: %u%%\n"
"Swap Used Limit: " PERMYRIAD_AS_PERCENT_FORMAT_STR "\n"
"Default Memory Pressure Limit: %lu.%02lu%%\n"
"Default Memory Pressure Duration: %s\n"
"System Context:\n",
yes_no(m->dry_run),
m->swap_used_limit,
PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad),
LOAD_INT(m->default_mem_pressure_limit), LOAD_FRAC(m->default_mem_pressure_limit),
format_timespan(buf, sizeof(buf), m->default_mem_pressure_duration_usec, USEC_PER_SEC));
oomd_dump_system_context(&m->system_context, f, "\t");

View File

@ -18,7 +18,7 @@
* system.slice are assumed to be less latency sensitive. */
#define DEFAULT_MEM_PRESSURE_DURATION_USEC (30 * USEC_PER_SEC)
#define DEFAULT_MEM_PRESSURE_LIMIT_PERCENT 60
#define DEFAULT_SWAP_USED_LIMIT 90
#define DEFAULT_SWAP_USED_LIMIT_PERCENT 90
#define RECLAIM_DURATION_USEC (30 * USEC_PER_SEC)
#define POST_ACTION_DELAY_USEC (15 * USEC_PER_SEC)
@ -32,7 +32,7 @@ struct Manager {
Hashmap *polkit_registry;
bool dry_run;
unsigned swap_used_limit;
int swap_used_limit_permyriad;
loadavg_t default_mem_pressure_limit;
usec_t default_mem_pressure_duration_usec;
@ -56,7 +56,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
int manager_new(Manager **ret);
int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec);
int manager_start(Manager *m, bool dry_run, int swap_used_limit_permyriad, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec);
int manager_get_dump_string(Manager *m, char **ret);

View File

@ -134,13 +134,13 @@ bool oomd_memory_reclaim(Hashmap *h) {
return pgscan_of > last_pgscan_of;
}
bool oomd_swap_free_below(const OomdSystemContext *ctx, uint64_t threshold_percent) {
bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad) {
uint64_t swap_threshold;
assert(ctx);
assert(threshold_percent <= 100);
assert(threshold_permyriad <= 10000);
swap_threshold = ctx->swap_total * threshold_percent / ((uint64_t) 100);
swap_threshold = ctx->swap_total * threshold_permyriad / (uint64_t) 10000;
return (ctx->swap_total - ctx->swap_used) < swap_threshold;
}

View File

@ -61,8 +61,8 @@ int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret);
* current sum is higher than the last interval's sum (there was some reclaim activity). */
bool oomd_memory_reclaim(Hashmap *h);
/* Returns true if the amount of swap free is below the percentage of swap specified by `threshold_percent`. */
bool oomd_swap_free_below(const OomdSystemContext *ctx, uint64_t threshold_percent);
/* Returns true if the amount of swap free is below the permyriad of swap specified by `threshold_permyriad`. */
bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad);
/* The compare functions will sort from largest to smallest, putting all the contexts with "avoid" at the end
* (after the smallest values). */

View File

@ -17,13 +17,13 @@
#include "signal-util.h"
static bool arg_dry_run = false;
static int arg_swap_used_limit = -1;
static int arg_swap_used_limit_permyriad = -1;
static int arg_mem_pressure_limit_permyriad = -1;
static usec_t arg_mem_pressure_usec = 0;
static int parse_config(void) {
static const ConfigTableItem items[] = {
{ "OOM", "SwapUsedLimitPercent", config_parse_percent, 0, &arg_swap_used_limit },
{ "OOM", "SwapUsedLimit", config_parse_permyriad, 0, &arg_swap_used_limit_permyriad },
{ "OOM", "DefaultMemoryPressureLimit", config_parse_permyriad, 0, &arg_mem_pressure_limit_permyriad },
{ "OOM", "DefaultMemoryPressureDurationSec", config_parse_sec, 0, &arg_mem_pressure_usec },
{}
@ -159,7 +159,12 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to create manager: %m");
r = manager_start(m, arg_dry_run, arg_swap_used_limit, arg_mem_pressure_limit_permyriad, arg_mem_pressure_usec);
r = manager_start(
m,
arg_dry_run,
arg_swap_used_limit_permyriad,
arg_mem_pressure_limit_permyriad,
arg_mem_pressure_usec);
if (r < 0)
return log_error_errno(r, "Failed to start up daemon: %m");

View File

@ -13,6 +13,6 @@
# See oomd.conf(5) for details
[OOM]
#SwapUsedLimitPercent=90%
#SwapUsedLimit=90%
#DefaultMemoryPressureLimit=60%
#DefaultMemoryPressureDurationSec=30s

View File

@ -302,19 +302,19 @@ static void test_oomd_swap_free_below(void) {
.swap_total = 20971512 * 1024U,
.swap_used = 20971440 * 1024U,
};
assert_se(oomd_swap_free_below(&ctx, 20) == true);
assert_se(oomd_swap_free_below(&ctx, 2000) == true);
ctx = (OomdSystemContext) {
.swap_total = 20971512 * 1024U,
.swap_used = 3310136 * 1024U,
};
assert_se(oomd_swap_free_below(&ctx, 20) == false);
assert_se(oomd_swap_free_below(&ctx, 2000) == false);
ctx = (OomdSystemContext) {
.swap_total = 0,
.swap_used = 0,
};
assert_se(oomd_swap_free_below(&ctx, 20) == false);
assert_se(oomd_swap_free_below(&ctx, 2000) == false);
}
static void test_oomd_sort_cgroups(void) {

View File

@ -28,6 +28,7 @@
#include "numa-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "percent-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#if HAVE_SECCOMP
@ -440,15 +441,12 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return bus_append_string(m, field, eq);
if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
char *n;
r = parse_permyriad(eq);
if (r < 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
n = strjoina(field, "Permyriad");
r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) r);
/* Pass around scaled to 2^32-1 == 100% */
r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
if (r < 0)
return bus_log_create_error(r);
@ -539,7 +537,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return 1;
}
r = parse_permille(eq);
r = parse_permyriad(eq);
if (r >= 0) {
char *n;
@ -548,7 +546,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
* size can be determined server-side. */
n = strjoina(field, "Scale");
r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
if (r < 0)
return bus_log_create_error(r);
@ -565,14 +563,14 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
if (isempty(eq))
r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
else {
r = parse_permille_unbounded(eq);
r = parse_permyriad_unbounded(eq);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
"CPU quota too small.");
if (r < 0)
return log_error_errno(r, "CPU quota '%s' invalid.", eq);
r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 1000U));
r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U));
}
if (r < 0)

View File

@ -22,6 +22,7 @@
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "percent-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "sd-id128.h"

View File

@ -547,6 +547,8 @@ tests += [
[['src/test/test-bus-util.c']],
[['src/test/test-percent-util.c']],
[['src/test/test-sd-hwdb.c']],
[['src/test/test-sd-path.c']],

View File

@ -718,144 +718,6 @@ static void test_safe_atod(void) {
assert_se(r == -EINVAL);
}
static void test_parse_percent(void) {
assert_se(parse_percent("") == -EINVAL);
assert_se(parse_percent("foo") == -EINVAL);
assert_se(parse_percent("0") == -EINVAL);
assert_se(parse_percent("50") == -EINVAL);
assert_se(parse_percent("100") == -EINVAL);
assert_se(parse_percent("-1") == -EINVAL);
assert_se(parse_percent("0%") == 0);
assert_se(parse_percent("55%") == 55);
assert_se(parse_percent("100%") == 100);
assert_se(parse_percent("-7%") == -ERANGE);
assert_se(parse_percent("107%") == -ERANGE);
assert_se(parse_percent("%") == -EINVAL);
assert_se(parse_percent("%%") == -EINVAL);
assert_se(parse_percent("%1") == -EINVAL);
assert_se(parse_percent("1%%") == -EINVAL);
assert_se(parse_percent("3.2%") == -EINVAL);
}
static void test_parse_percent_unbounded(void) {
assert_se(parse_percent_unbounded("101%") == 101);
assert_se(parse_percent_unbounded("400%") == 400);
}
static void test_parse_permille(void) {
assert_se(parse_permille("") == -EINVAL);
assert_se(parse_permille("foo") == -EINVAL);
assert_se(parse_permille("0") == -EINVAL);
assert_se(parse_permille("50") == -EINVAL);
assert_se(parse_permille("100") == -EINVAL);
assert_se(parse_permille("-1") == -EINVAL);
assert_se(parse_permille("0‰") == 0);
assert_se(parse_permille("555‰") == 555);
assert_se(parse_permille("1000‰") == 1000);
assert_se(parse_permille("-7‰") == -ERANGE);
assert_se(parse_permille("1007‰") == -ERANGE);
assert_se(parse_permille("") == -EINVAL);
assert_se(parse_permille("‰‰") == -EINVAL);
assert_se(parse_permille("‰1") == -EINVAL);
assert_se(parse_permille("1‰‰") == -EINVAL);
assert_se(parse_permille("3.2‰") == -EINVAL);
assert_se(parse_permille("0%") == 0);
assert_se(parse_permille("55%") == 550);
assert_se(parse_permille("55.5%") == 555);
assert_se(parse_permille("100%") == 1000);
assert_se(parse_permille("-7%") == -ERANGE);
assert_se(parse_permille("107%") == -ERANGE);
assert_se(parse_permille("%") == -EINVAL);
assert_se(parse_permille("%%") == -EINVAL);
assert_se(parse_permille("%1") == -EINVAL);
assert_se(parse_permille("1%%") == -EINVAL);
assert_se(parse_permille("3.21%") == -EINVAL);
}
static void test_parse_permille_unbounded(void) {
assert_se(parse_permille_unbounded("1001‰") == 1001);
assert_se(parse_permille_unbounded("4000‰") == 4000);
assert_se(parse_permille_unbounded("2147483647‰") == 2147483647);
assert_se(parse_permille_unbounded("2147483648‰") == -ERANGE);
assert_se(parse_permille_unbounded("4294967295‰") == -ERANGE);
assert_se(parse_permille_unbounded("4294967296‰") == -ERANGE);
assert_se(parse_permille_unbounded("101%") == 1010);
assert_se(parse_permille_unbounded("400%") == 4000);
assert_se(parse_permille_unbounded("214748364.7%") == 2147483647);
assert_se(parse_permille_unbounded("214748364.8%") == -ERANGE);
assert_se(parse_permille_unbounded("429496729.5%") == -ERANGE);
assert_se(parse_permille_unbounded("429496729.6%") == -ERANGE);
}
static void test_parse_permyriad(void) {
assert_se(parse_permyriad("") == -EINVAL);
assert_se(parse_permyriad("foo") == -EINVAL);
assert_se(parse_permyriad("0") == -EINVAL);
assert_se(parse_permyriad("50") == -EINVAL);
assert_se(parse_permyriad("100") == -EINVAL);
assert_se(parse_permyriad("-1") == -EINVAL);
assert_se(parse_permyriad("0‱") == 0);
assert_se(parse_permyriad("555‱") == 555);
assert_se(parse_permyriad("1000‱") == 1000);
assert_se(parse_permyriad("-7‱") == -ERANGE);
assert_se(parse_permyriad("10007‱") == -ERANGE);
assert_se(parse_permyriad("") == -EINVAL);
assert_se(parse_permyriad("‱‱") == -EINVAL);
assert_se(parse_permyriad("‱1") == -EINVAL);
assert_se(parse_permyriad("1‱‱") == -EINVAL);
assert_se(parse_permyriad("3.2‱") == -EINVAL);
assert_se(parse_permyriad("0‰") == 0);
assert_se(parse_permyriad("555.5‰") == 5555);
assert_se(parse_permyriad("1000.0‰") == 10000);
assert_se(parse_permyriad("-7‰") == -ERANGE);
assert_se(parse_permyriad("1007‰") == -ERANGE);
assert_se(parse_permyriad("") == -EINVAL);
assert_se(parse_permyriad("‰‰") == -EINVAL);
assert_se(parse_permyriad("‰1") == -EINVAL);
assert_se(parse_permyriad("1‰‰") == -EINVAL);
assert_se(parse_permyriad("3.22‰") == -EINVAL);
assert_se(parse_permyriad("0%") == 0);
assert_se(parse_permyriad("55%") == 5500);
assert_se(parse_permyriad("55.53%") == 5553);
assert_se(parse_permyriad("100%") == 10000);
assert_se(parse_permyriad("-7%") == -ERANGE);
assert_se(parse_permyriad("107%") == -ERANGE);
assert_se(parse_permyriad("%") == -EINVAL);
assert_se(parse_permyriad("%%") == -EINVAL);
assert_se(parse_permyriad("%1") == -EINVAL);
assert_se(parse_permyriad("1%%") == -EINVAL);
assert_se(parse_permyriad("3.212%") == -EINVAL);
}
static void test_parse_permyriad_unbounded(void) {
assert_se(parse_permyriad_unbounded("1001‱") == 1001);
assert_se(parse_permyriad_unbounded("4000‱") == 4000);
assert_se(parse_permyriad_unbounded("2147483647‱") == 2147483647);
assert_se(parse_permyriad_unbounded("2147483648‱") == -ERANGE);
assert_se(parse_permyriad_unbounded("4294967295‱") == -ERANGE);
assert_se(parse_permyriad_unbounded("4294967296‱") == -ERANGE);
assert_se(parse_permyriad_unbounded("101‰") == 1010);
assert_se(parse_permyriad_unbounded("400‰") == 4000);
assert_se(parse_permyriad_unbounded("214748364.7‰") == 2147483647);
assert_se(parse_permyriad_unbounded("214748364.8‰") == -ERANGE);
assert_se(parse_permyriad_unbounded("429496729.5‰") == -ERANGE);
assert_se(parse_permyriad_unbounded("429496729.6‰") == -ERANGE);
assert_se(parse_permyriad_unbounded("99%") == 9900);
assert_se(parse_permyriad_unbounded("40%") == 4000);
assert_se(parse_permyriad_unbounded("21474836.47%") == 2147483647);
assert_se(parse_permyriad_unbounded("21474836.48%") == -ERANGE);
assert_se(parse_permyriad_unbounded("42949672.95%") == -ERANGE);
assert_se(parse_permyriad_unbounded("42949672.96%") == -ERANGE);
}
static void test_parse_nice(void) {
int n;
@ -1049,12 +911,6 @@ int main(int argc, char *argv[]) {
test_safe_atoi64();
test_safe_atoux64();
test_safe_atod();
test_parse_percent();
test_parse_percent_unbounded();
test_parse_permille();
test_parse_permille_unbounded();
test_parse_permyriad();
test_parse_permyriad_unbounded();
test_parse_nice();
test_parse_dev();
test_parse_errno();

View File

@ -0,0 +1,211 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "percent-util.h"
#include "tests.h"
#include "time-util.h"
static void test_parse_percent(void) {
assert_se(parse_percent("") == -EINVAL);
assert_se(parse_percent("foo") == -EINVAL);
assert_se(parse_percent("0") == -EINVAL);
assert_se(parse_percent("0.1") == -EINVAL);
assert_se(parse_percent("50") == -EINVAL);
assert_se(parse_percent("100") == -EINVAL);
assert_se(parse_percent("-1") == -EINVAL);
assert_se(parse_percent("0%") == 0);
assert_se(parse_percent("55%") == 55);
assert_se(parse_percent("100%") == 100);
assert_se(parse_percent("-7%") == -ERANGE);
assert_se(parse_percent("107%") == -ERANGE);
assert_se(parse_percent("%") == -EINVAL);
assert_se(parse_percent("%%") == -EINVAL);
assert_se(parse_percent("%1") == -EINVAL);
assert_se(parse_percent("1%%") == -EINVAL);
assert_se(parse_percent("3.2%") == -EINVAL);
}
static void test_parse_percent_unbounded(void) {
assert_se(parse_percent_unbounded("101%") == 101);
assert_se(parse_percent_unbounded("400%") == 400);
}
static void test_parse_permille(void) {
assert_se(parse_permille("") == -EINVAL);
assert_se(parse_permille("foo") == -EINVAL);
assert_se(parse_permille("0") == -EINVAL);
assert_se(parse_permille("50") == -EINVAL);
assert_se(parse_permille("100") == -EINVAL);
assert_se(parse_permille("-1") == -EINVAL);
assert_se(parse_permille("0.1") == -EINVAL);
assert_se(parse_permille("5%") == 50);
assert_se(parse_permille("5.5%") == 55);
assert_se(parse_permille("5.12%") == -EINVAL);
assert_se(parse_permille("0‰") == 0);
assert_se(parse_permille("555‰") == 555);
assert_se(parse_permille("1000‰") == 1000);
assert_se(parse_permille("-7‰") == -ERANGE);
assert_se(parse_permille("1007‰") == -ERANGE);
assert_se(parse_permille("") == -EINVAL);
assert_se(parse_permille("‰‰") == -EINVAL);
assert_se(parse_permille("‰1") == -EINVAL);
assert_se(parse_permille("1‰‰") == -EINVAL);
assert_se(parse_permille("3.2‰") == -EINVAL);
assert_se(parse_permille("0.1‰") == -EINVAL);
assert_se(parse_permille("0%") == 0);
assert_se(parse_permille("55%") == 550);
assert_se(parse_permille("55.5%") == 555);
assert_se(parse_permille("100%") == 1000);
assert_se(parse_permille("-7%") == -ERANGE);
assert_se(parse_permille("107%") == -ERANGE);
assert_se(parse_permille("%") == -EINVAL);
assert_se(parse_permille("%%") == -EINVAL);
assert_se(parse_permille("%1") == -EINVAL);
assert_se(parse_permille("1%%") == -EINVAL);
assert_se(parse_permille("3.21%") == -EINVAL);
assert_se(parse_permille("0.1%") == 1);
}
static void test_parse_permille_unbounded(void) {
assert_se(parse_permille_unbounded("1001‰") == 1001);
assert_se(parse_permille_unbounded("4000‰") == 4000);
assert_se(parse_permille_unbounded("2147483647‰") == 2147483647);
assert_se(parse_permille_unbounded("2147483648‰") == -ERANGE);
assert_se(parse_permille_unbounded("4294967295‰") == -ERANGE);
assert_se(parse_permille_unbounded("4294967296‰") == -ERANGE);
assert_se(parse_permille_unbounded("101%") == 1010);
assert_se(parse_permille_unbounded("400%") == 4000);
assert_se(parse_permille_unbounded("214748364.7%") == 2147483647);
assert_se(parse_permille_unbounded("214748364.8%") == -ERANGE);
assert_se(parse_permille_unbounded("429496729.5%") == -ERANGE);
assert_se(parse_permille_unbounded("429496729.6%") == -ERANGE);
}
static void test_parse_permyriad(void) {
assert_se(parse_permyriad("") == -EINVAL);
assert_se(parse_permyriad("foo") == -EINVAL);
assert_se(parse_permyriad("0") == -EINVAL);
assert_se(parse_permyriad("50") == -EINVAL);
assert_se(parse_permyriad("100") == -EINVAL);
assert_se(parse_permyriad("-1") == -EINVAL);
assert_se(parse_permyriad("0‱") == 0);
assert_se(parse_permyriad("555‱") == 555);
assert_se(parse_permyriad("1000‱") == 1000);
assert_se(parse_permyriad("-7‱") == -ERANGE);
assert_se(parse_permyriad("10007‱") == -ERANGE);
assert_se(parse_permyriad("") == -EINVAL);
assert_se(parse_permyriad("‱‱") == -EINVAL);
assert_se(parse_permyriad("‱1") == -EINVAL);
assert_se(parse_permyriad("1‱‱") == -EINVAL);
assert_se(parse_permyriad("3.2‱") == -EINVAL);
assert_se(parse_permyriad("0‰") == 0);
assert_se(parse_permyriad("555.5‰") == 5555);
assert_se(parse_permyriad("1000.0‰") == 10000);
assert_se(parse_permyriad("-7‰") == -ERANGE);
assert_se(parse_permyriad("1007‰") == -ERANGE);
assert_se(parse_permyriad("") == -EINVAL);
assert_se(parse_permyriad("‰‰") == -EINVAL);
assert_se(parse_permyriad("‰1") == -EINVAL);
assert_se(parse_permyriad("1‰‰") == -EINVAL);
assert_se(parse_permyriad("3.22‰") == -EINVAL);
assert_se(parse_permyriad("0%") == 0);
assert_se(parse_permyriad("55%") == 5500);
assert_se(parse_permyriad("55.5%") == 5550);
assert_se(parse_permyriad("55.50%") == 5550);
assert_se(parse_permyriad("55.53%") == 5553);
assert_se(parse_permyriad("100%") == 10000);
assert_se(parse_permyriad("-7%") == -ERANGE);
assert_se(parse_permyriad("107%") == -ERANGE);
assert_se(parse_permyriad("%") == -EINVAL);
assert_se(parse_permyriad("%%") == -EINVAL);
assert_se(parse_permyriad("%1") == -EINVAL);
assert_se(parse_permyriad("1%%") == -EINVAL);
assert_se(parse_permyriad("3.212%") == -EINVAL);
}
static void test_parse_permyriad_unbounded(void) {
assert_se(parse_permyriad_unbounded("1001‱") == 1001);
assert_se(parse_permyriad_unbounded("4000‱") == 4000);
assert_se(parse_permyriad_unbounded("2147483647‱") == 2147483647);
assert_se(parse_permyriad_unbounded("2147483648‱") == -ERANGE);
assert_se(parse_permyriad_unbounded("4294967295‱") == -ERANGE);
assert_se(parse_permyriad_unbounded("4294967296‱") == -ERANGE);
assert_se(parse_permyriad_unbounded("101‰") == 1010);
assert_se(parse_permyriad_unbounded("400‰") == 4000);
assert_se(parse_permyriad_unbounded("214748364.7‰") == 2147483647);
assert_se(parse_permyriad_unbounded("214748364.8‰") == -ERANGE);
assert_se(parse_permyriad_unbounded("429496729.5‰") == -ERANGE);
assert_se(parse_permyriad_unbounded("429496729.6‰") == -ERANGE);
assert_se(parse_permyriad_unbounded("99%") == 9900);
assert_se(parse_permyriad_unbounded("40%") == 4000);
assert_se(parse_permyriad_unbounded("21474836.47%") == 2147483647);
assert_se(parse_permyriad_unbounded("21474836.48%") == -ERANGE);
assert_se(parse_permyriad_unbounded("42949672.95%") == -ERANGE);
assert_se(parse_permyriad_unbounded("42949672.96%") == -ERANGE);
}
static void test_scale(void) {
/* Check some fixed values */
assert_se(UINT32_SCALE_FROM_PERCENT(0) == 0);
assert_se(UINT32_SCALE_FROM_PERCENT(50) == UINT32_MAX/2+1);
assert_se(UINT32_SCALE_FROM_PERCENT(100) == UINT32_MAX);
assert_se(UINT32_SCALE_FROM_PERMILLE(0) == 0);
assert_se(UINT32_SCALE_FROM_PERMILLE(500) == UINT32_MAX/2+1);
assert_se(UINT32_SCALE_FROM_PERMILLE(1000) == UINT32_MAX);
assert_se(UINT32_SCALE_FROM_PERMYRIAD(0) == 0);
assert_se(UINT32_SCALE_FROM_PERMYRIAD(5000) == UINT32_MAX/2+1);
assert_se(UINT32_SCALE_FROM_PERMYRIAD(10000) == UINT32_MAX);
/* Make sure there's no numeric noise on the 0%…100% scale when converting from percent and back. */
for (int percent = 0; percent <= 100; percent++) {
log_debug("%i%% → %" PRIu32 " → %i%%",
percent,
UINT32_SCALE_FROM_PERCENT(percent),
UINT32_SCALE_TO_PERCENT(UINT32_SCALE_FROM_PERCENT(percent)));
assert_se(UINT32_SCALE_TO_PERCENT(UINT32_SCALE_FROM_PERCENT(percent)) == percent);
}
/* Make sure there's no numeric noise on the 0‰…1000‰ scale when converting from permille and back. */
for (int permille = 0; permille <= 1000; permille++) {
log_debug("%i‰ → %" PRIu32 " → %i‰",
permille,
UINT32_SCALE_FROM_PERMILLE(permille),
UINT32_SCALE_TO_PERMILLE(UINT32_SCALE_FROM_PERMILLE(permille)));
assert_se(UINT32_SCALE_TO_PERMILLE(UINT32_SCALE_FROM_PERMILLE(permille)) == permille);
}
/* Make sure there's no numeric noise on the 0‱…10000‱ scale when converting from permyriad and back. */
for (int permyriad = 0; permyriad <= 10000; permyriad++) {
log_debug("%i‱ → %" PRIu32 " → %i‱",
permyriad,
UINT32_SCALE_FROM_PERMYRIAD(permyriad),
UINT32_SCALE_TO_PERMYRIAD(UINT32_SCALE_FROM_PERMYRIAD(permyriad)));
assert_se(UINT32_SCALE_TO_PERMYRIAD(UINT32_SCALE_FROM_PERMYRIAD(permyriad)) == permyriad);
}
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_parse_percent();
test_parse_percent_unbounded();
test_parse_permille();
test_parse_permille_unbounded();
test_parse_permyriad();
test_parse_permyriad_unbounded();
test_scale();
return 0;
}