Blob Blame History Raw
From a9b1927c15fce3c9945ac249d8e8ddc42028a057 Mon Sep 17 00:00:00 2001
From: Anita Zhang <the.anitazha@gmail.com>
Date: Tue, 2 Feb 2021 01:47:08 -0800
Subject: [PATCH 1/2] parse-util: add permyriad parsing

---
 src/basic/parse-util.c     | 137 ++++++++++++++++++++++++++-----------
 src/basic/parse-util.h     |   3 +
 src/test/test-parse-util.c |  68 ++++++++++++++++++
 3 files changed, 169 insertions(+), 39 deletions(-)

diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 5d4dafe3a5..a0fb2c9d17 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -671,11 +671,11 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
         return 0;
 }
 
-int parse_percent_unbounded(const char *p) {
+static int parse_parts_value_whole(const char *p, const char *symbol) {
         const char *pc, *n;
         int r, v;
 
-        pc = endswith(p, "%");
+        pc = endswith(p, symbol);
         if (!pc)
                 return -EINVAL;
 
@@ -689,6 +689,74 @@ int parse_percent_unbounded(const char *p) {
         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;
 
@@ -700,46 +768,13 @@ int parse_percent(const char *p) {
 }
 
 int parse_permille_unbounded(const char *p) {
-        const char *pc, *pm, *dot, *n;
-        int r, q, v;
+        const char *pm;
 
         pm = endswith(p, "‰");
-        if (pm) {
-                n = strndupa(p, pm - p);
-                r = safe_atoi(n, &v);
-                if (r < 0)
-                        return r;
-                if (v < 0)
-                        return -ERANGE;
-        } else {
-                pc = endswith(p, "%");
-                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;
+        if (pm)
+                return parse_parts_value_whole(p, "‰");
 
-                v = v * 10 + q;
-        }
-
-        return v;
+        return parse_parts_value_with_tenths_place(p, "%");
 }
 
 int parse_permille(const char *p) {
@@ -752,6 +787,30 @@ int parse_permille(const char *p) {
         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;
 
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 81478ed059..3e29291f26 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -136,6 +136,9 @@ 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);
diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c
index 1c969091ef..6e23efe134 100644
--- a/src/test/test-parse-util.c
+++ b/src/test/test-parse-util.c
@@ -790,6 +790,72 @@ static void test_parse_permille_unbounded(void) {
         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;
 
@@ -987,6 +1053,8 @@ int main(int argc, char *argv[]) {
         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();
-- 
2.29.2


From 5fdc5d3384f81888704a0a19db3cb33bce2d8bdb Mon Sep 17 00:00:00 2001
From: Anita Zhang <the.anitazha@gmail.com>
Date: Tue, 2 Feb 2021 14:16:03 -0800
Subject: [PATCH 2/2] oom: rework *MemoryPressureLimit= properties to have
 1/10000 precision

Requested in
https://github.com/systemd/systemd/pull/15206#discussion_r505506657,
preserve the full granularity for memory pressure limits (permyriad)
instead of capping out at percent.
---
 docs/TRANSIENT-SETTINGS.md             |  2 +-
 man/oomd.conf.xml                      |  6 ++---
 man/org.freedesktop.systemd1.xml       | 36 +++++++++++++-------------
 man/systemd.resource-control.xml       |  2 +-
 src/core/cgroup.c                      |  4 +--
 src/core/cgroup.h                      |  2 +-
 src/core/core-varlink.c                |  2 +-
 src/core/dbus-cgroup.c                 | 16 +++++++++---
 src/core/dbus-util.c                   | 29 ---------------------
 src/core/dbus-util.h                   |  1 -
 src/core/load-fragment-gperf.gperf.m4  |  2 +-
 src/core/load-fragment.c               |  6 ++---
 src/oom/oomd-manager.c                 | 24 +++++++++++------
 src/oom/oomd-manager.h                 |  4 +--
 src/oom/oomd-util.c                    |  4 +--
 src/oom/oomd.c                         | 10 +++----
 src/oom/oomd.conf                      |  2 +-
 src/shared/bus-get-properties.c        | 17 ------------
 src/shared/bus-get-properties.h        |  1 -
 src/shared/bus-unit-util.c             | 19 ++++++++++++--
 src/shared/conf-parser.c               |  1 +
 src/shared/conf-parser.h               |  1 +
 test/units/testsuite-56-workload.slice |  2 +-
 test/units/testsuite-56.sh             |  2 +-
 24 files changed, 91 insertions(+), 104 deletions(-)

diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md
index 50b9a42fa1..5037060254 100644
--- a/docs/TRANSIENT-SETTINGS.md
+++ b/docs/TRANSIENT-SETTINGS.md
@@ -272,7 +272,7 @@ All cgroup/resource control settings are available for transient units
 ✓ IPAddressDeny=
 ✓ ManagedOOMSwap=
 ✓ ManagedOOMMemoryPressure=
-✓ ManagedOOMMemoryPressureLimitPercent=
+✓ ManagedOOMMemoryPressureLimit=
 ```
 
 ## Process Killing Settings
diff --git a/man/oomd.conf.xml b/man/oomd.conf.xml
index bb5da87c54..2a12be8cad 100644
--- a/man/oomd.conf.xml
+++ b/man/oomd.conf.xml
@@ -59,10 +59,10 @@
       </varlistentry>
 
       <varlistentry>
-        <term><varname>DefaultMemoryPressureLimitPercent=</varname></term>
+        <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>ManagedOOMMemoryPressureLimitPercent=</varname>.
+        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>,
@@ -78,7 +78,7 @@
 
         <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
-        <varname>DefaultMemoryPressureLimitPercent=</varname> and <varname>ManagedOOMMemoryPressureLimitPercent=</varname>.
+        <varname>DefaultMemoryPressureLimit=</varname> and <varname>ManagedOOMMemoryPressureLimit=</varname>.
         Defaults to 30 seconds when this property is unset or set to 0.</para></listitem>
       </varlistentry>
 
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 78fd0b3378..7809b65062 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -2419,7 +2419,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 s ManagedOOMMemoryPressureLimitPercent = '...';
+      readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -2938,7 +2938,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property ManagedOOMMemoryPressure is not documented!-->
 
-    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+    <!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
 
     <!--property EnvironmentFiles is not documented!-->
 
@@ -3494,7 +3494,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="ManagedOOMMemoryPressureLimitPercent"/>
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
@@ -4146,7 +4146,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 s ManagedOOMMemoryPressureLimitPercent = '...';
+      readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -4693,7 +4693,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <!--property ManagedOOMMemoryPressure is not documented!-->
 
-    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+    <!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
 
     <!--property EnvironmentFiles is not documented!-->
 
@@ -5251,7 +5251,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="ManagedOOMMemoryPressureLimitPercent"/>
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
@@ -5827,7 +5827,7 @@ node /org/freedesktop/systemd1/unit/home_2emount {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s ManagedOOMMemoryPressure = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
-      readonly s ManagedOOMMemoryPressureLimitPercent = '...';
+      readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -6302,7 +6302,7 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <!--property ManagedOOMMemoryPressure is not documented!-->
 
-    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+    <!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
 
     <!--property EnvironmentFiles is not documented!-->
 
@@ -6778,7 +6778,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="ManagedOOMMemoryPressureLimitPercent"/>
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
@@ -7475,7 +7475,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 s ManagedOOMMemoryPressureLimitPercent = '...';
+      readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -7936,7 +7936,7 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <!--property ManagedOOMMemoryPressure is not documented!-->
 
-    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+    <!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
 
     <!--property EnvironmentFiles is not documented!-->
 
@@ -8398,7 +8398,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="ManagedOOMMemoryPressureLimitPercent"/>
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
@@ -8948,7 +8948,7 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s ManagedOOMMemoryPressure = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
-      readonly s ManagedOOMMemoryPressureLimitPercent = '...';
+      readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
   };
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
@@ -9083,7 +9083,7 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
 
     <!--property ManagedOOMMemoryPressure is not documented!-->
 
-    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+    <!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
@@ -9223,7 +9223,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="ManagedOOMMemoryPressureLimitPercent"/>
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
 
     <!--End of Autogenerated section-->
 
@@ -9383,7 +9383,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 s ManagedOOMMemoryPressureLimitPercent = '...';
+      readonly u ManagedOOMMemoryPressureLimitPermyriad = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s KillMode = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -9534,7 +9534,7 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <!--property ManagedOOMMemoryPressure is not documented!-->
 
-    <!--property ManagedOOMMemoryPressureLimitPercent is not documented!-->
+    <!--property ManagedOOMMemoryPressureLimitPermyriad is not documented!-->
 
     <!--property KillMode is not documented!-->
 
@@ -9700,7 +9700,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="ManagedOOMMemoryPressureLimitPercent"/>
+    <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMMemoryPressureLimitPermyriad"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
 
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index 26dedda3fd..4381c4e1b7 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -901,7 +901,7 @@ DeviceAllow=/dev/loop-control
       </varlistentry>
 
       <varlistentry>
-        <term><varname>ManagedOOMMemoryPressureLimitPercent=</varname></term>
+        <term><varname>ManagedOOMMemoryPressureLimit=</varname></term>
 
         <listitem>
           <para>Overrides the default memory pressure limit set by
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 7dc6c20bb7..e2ed0e546e 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -417,7 +417,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 "%sDelegate: %s\n"
                 "%sManagedOOMSwap: %s\n"
                 "%sManagedOOMMemoryPressure: %s\n"
-                "%sManagedOOMMemoryPressureLimitPercent: %d%%\n",
+                "%sManagedOOMMemoryPressureLimit: %" PRIu32 ".%02" PRIu32 "%%\n",
                 prefix, yes_no(c->cpu_accounting),
                 prefix, yes_no(c->io_accounting),
                 prefix, yes_no(c->blockio_accounting),
@@ -450,7 +450,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);
+                prefix, c->moom_mem_pressure_limit_permyriad / 100, c->moom_mem_pressure_limit_permyriad % 100);
 
         if (c->delegate) {
                 _cleanup_free_ char *t = NULL;
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 66f3a63b82..9fbfabbb7e 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -163,7 +163,7 @@ struct CGroupContext {
         /* Settings for systemd-oomd */
         ManagedOOMMode moom_swap;
         ManagedOOMMode moom_mem_pressure;
-        int moom_mem_pressure_limit;
+        uint32_t moom_mem_pressure_limit_permyriad;
 };
 
 /* Used when querying IP accounting data */
diff --git a/src/core/core-varlink.c b/src/core/core-varlink.c
index dd6c11ab4d..17fb9bc83f 100644
--- a/src/core/core-varlink.c
+++ b/src/core/core-varlink.c
@@ -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))));
+                                 JSON_BUILD_PAIR_CONDITION(use_limit, "limit", JSON_BUILD_UNSIGNED(c->moom_mem_pressure_limit_permyriad))));
 }
 
 int manager_varlink_send_managed_oom_update(Unit *u) {
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 37c581fb22..df35ec114d 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -395,7 +395,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("ManagedOOMMemoryPressureLimitPercent", "s", bus_property_get_percent, offsetof(CGroupContext, moom_mem_pressure_limit), 0),
+        SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimitPermyriad", "u", NULL, offsetof(CGroupContext, moom_mem_pressure_limit_permyriad), 0),
         SD_BUS_VTABLE_END
 };
 
@@ -1697,14 +1697,24 @@ int bus_cgroup_set_property(
                 return 1;
         }
 
-        if (streq(name, "ManagedOOMMemoryPressureLimitPercent")) {
+        if (streq(name, "ManagedOOMMemoryPressureLimitPermyriad")) {
+                uint32_t v;
+
                 if (!UNIT_VTABLE(u)->can_set_managed_oom)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set %s for this unit type", name);
 
-                r = bus_set_transient_percent(u, name, &c->moom_mem_pressure_limit, message, flags, error);
+                r = sd_bus_message_read(message, "u", &v);
                 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);
+                }
+
                 if (c->moom_mem_pressure == MANAGED_OOM_KILL)
                         (void) manager_varlink_send_managed_oom_update(u);
 
diff --git a/src/core/dbus-util.c b/src/core/dbus-util.c
index d6223db305..eb03d30cf7 100644
--- a/src/core/dbus-util.c
+++ b/src/core/dbus-util.c
@@ -91,35 +91,6 @@ int bus_set_transient_bool(
         return 1;
 }
 
-int bus_set_transient_percent(
-                Unit *u,
-                const char *name,
-                int *p,
-                sd_bus_message *message,
-                UnitWriteFlags flags,
-                sd_bus_error *error) {
-
-        const char *v;
-        int r;
-
-        assert(p);
-
-        r = sd_bus_message_read(message, "s", &v);
-        if (r < 0)
-                return r;
-
-        r = parse_percent(v);
-        if (r < 0)
-                return r;
-
-        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                *p = r;
-                unit_write_settingf(u, flags, name, "%s=%d%%", name, r);
-        }
-
-        return 1;
-}
-
 int bus_set_transient_usec_internal(
                 Unit *u,
                 const char *name,
diff --git a/src/core/dbus-util.h b/src/core/dbus-util.h
index 4e7c68e843..b68ec38ada 100644
--- a/src/core/dbus-util.h
+++ b/src/core/dbus-util.h
@@ -240,7 +240,6 @@ int bus_set_transient_user_relaxed(Unit *u, const char *name, char **p, sd_bus_m
 int bus_set_transient_path(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_set_transient_string(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_set_transient_bool(Unit *u, const char *name, bool *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
-int bus_set_transient_percent(Unit *u, const char *name, int *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 int bus_set_transient_usec_internal(Unit *u, const char *name, usec_t *p, bool fix_0, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
 static inline int bus_set_transient_usec(Unit *u, const char *name, usec_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error) {
         return bus_set_transient_usec_internal(u, name, p, false, message, flags, error);
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 946862c398..db2a4e28a8 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -226,7 +226,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.ManagedOOMMemoryPressureLimitPercent, config_parse_managed_oom_mem_pressure_limit, 0,                                  offsetof($1, cgroup_context.moom_mem_pressure_limit)
+$1.ManagedOOMMemoryPressureLimit,        config_parse_managed_oom_mem_pressure_limit, 0,                                  offsetof($1, cgroup_context.moom_mem_pressure_limit_permyriad)
 $1.NetClass,                             config_parse_warn_compat,                    DISABLED_LEGACY,                    0'
 )m4_dnl
 Unit.Description,                        config_parse_unit_string_printf,             0,                                  offsetof(Unit, description)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 4964249bf2..e0e9920e06 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3859,7 +3859,7 @@ int config_parse_managed_oom_mem_pressure_limit(
                 const char *rvalue,
                 void *data,
                 void *userdata) {
-        int *limit = data;
+        uint32_t *limit = data;
         UnitType t;
         int r;
 
@@ -3874,9 +3874,9 @@ int config_parse_managed_oom_mem_pressure_limit(
                 return 0;
         }
 
-        r = parse_percent(rvalue);
+        r = parse_permyriad(rvalue);
         if (r < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse limit percent value, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse memory pressure limit value, ignoring: %s", rvalue);
                 return 0;
         }
 
diff --git a/src/oom/oomd-manager.c b/src/oom/oomd-manager.c
index 3efa629002..338935b3ec 100644
--- a/src/oom/oomd-manager.c
+++ b/src/oom/oomd-manager.c
@@ -100,10 +100,10 @@ static int process_managed_oom_reply(
                 limit = m->default_mem_pressure_limit;
 
                 if (streq(reply.property, "ManagedOOMMemoryPressure")) {
-                        if (reply.limit > 100)
+                        if (reply.limit > 10000)
                                 continue;
                         else if (reply.limit != 0) {
-                                ret = store_loadavg_fixed_point((unsigned long) reply.limit, 0, &limit);
+                                ret = store_loadavg_fixed_point((unsigned long) reply.limit / 100, (unsigned long) reply.limit % 100, &limit);
                                 if (ret < 0)
                                         continue;
                         }
@@ -478,8 +478,8 @@ 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, usec_t mem_pressure_usec) {
-        unsigned long l;
+int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec) {
+        unsigned long l, f;
         int r;
 
         assert(m);
@@ -489,8 +489,16 @@ int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressur
         m->swap_used_limit = swap_used_limit != -1 ? swap_used_limit : DEFAULT_SWAP_USED_LIMIT;
         assert(m->swap_used_limit <= 100);
 
-        l = mem_pressure_limit != -1 ? mem_pressure_limit : DEFAULT_MEM_PRESSURE_LIMIT;
-        r = store_loadavg_fixed_point(l, 0, &m->default_mem_pressure_limit);
+        if (mem_pressure_limit_permyriad != -1) {
+                assert(mem_pressure_limit_permyriad <= 10000);
+
+                l = mem_pressure_limit_permyriad / 100;
+                f = mem_pressure_limit_permyriad % 100;
+        } else {
+                l = DEFAULT_MEM_PRESSURE_LIMIT_PERCENT;
+                f = 0;
+        }
+        r = store_loadavg_fixed_point(l, f, &m->default_mem_pressure_limit);
         if (r < 0)
                 return r;
 
@@ -530,12 +538,12 @@ int manager_get_dump_string(Manager *m, char **ret) {
         fprintf(f,
                 "Dry Run: %s\n"
                 "Swap Used Limit: %u%%\n"
-                "Default Memory Pressure Limit: %lu%%\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,
-                LOAD_INT(m->default_mem_pressure_limit),
+                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");
 
diff --git a/src/oom/oomd-manager.h b/src/oom/oomd-manager.h
index ee17abced2..521665e0a8 100644
--- a/src/oom/oomd-manager.h
+++ b/src/oom/oomd-manager.h
@@ -17,7 +17,7 @@
  * Generally 60 or higher might be acceptable for something like system.slice with no memory.high set; processes in
  * system.slice are assumed to be less latency sensitive. */
 #define DEFAULT_MEM_PRESSURE_DURATION_USEC (30 * USEC_PER_SEC)
-#define DEFAULT_MEM_PRESSURE_LIMIT 60
+#define DEFAULT_MEM_PRESSURE_LIMIT_PERCENT 60
 #define DEFAULT_SWAP_USED_LIMIT 90
 
 #define RECLAIM_DURATION_USEC (30 * USEC_PER_SEC)
@@ -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, usec_t mem_pressure_usec);
+int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec);
 
 int manager_get_dump_string(Manager *m, char **ret);
 
diff --git a/src/oom/oomd-util.c b/src/oom/oomd-util.c
index cec656f6fa..fcccddb92e 100644
--- a/src/oom/oomd-util.c
+++ b/src/oom/oomd-util.c
@@ -415,11 +415,11 @@ void oomd_dump_memory_pressure_cgroup_context(const OomdCGroupContext *ctx, FILE
 
         fprintf(f,
                 "%sPath: %s\n"
-                "%s\tMemory Pressure Limit: %lu%%\n"
+                "%s\tMemory Pressure Limit: %lu.%02lu%%\n"
                 "%s\tPressure: Avg10: %lu.%02lu Avg60: %lu.%02lu Avg300: %lu.%02lu Total: %s\n"
                 "%s\tCurrent Memory Usage: %s\n",
                 strempty(prefix), ctx->path,
-                strempty(prefix), LOAD_INT(ctx->mem_pressure_limit),
+                strempty(prefix), LOAD_INT(ctx->mem_pressure_limit), LOAD_FRAC(ctx->mem_pressure_limit),
                 strempty(prefix),
                 LOAD_INT(ctx->memory_pressure.avg10), LOAD_FRAC(ctx->memory_pressure.avg10),
                 LOAD_INT(ctx->memory_pressure.avg60), LOAD_FRAC(ctx->memory_pressure.avg60),
diff --git a/src/oom/oomd.c b/src/oom/oomd.c
index 1fbcf41492..811d211b58 100644
--- a/src/oom/oomd.c
+++ b/src/oom/oomd.c
@@ -18,14 +18,14 @@
 
 static bool arg_dry_run = false;
 static int arg_swap_used_limit = -1;
-static int arg_mem_pressure_limit = -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", "DefaultMemoryPressureLimitPercent", config_parse_percent, 0, &arg_mem_pressure_limit },
-                { "OOM", "DefaultMemoryPressureDurationSec",  config_parse_sec,     0, &arg_mem_pressure_usec  },
+                { "OOM", "SwapUsedLimitPercent",             config_parse_percent,   0, &arg_swap_used_limit              },
+                { "OOM", "DefaultMemoryPressureLimit",       config_parse_permyriad, 0, &arg_mem_pressure_limit_permyriad },
+                { "OOM", "DefaultMemoryPressureDurationSec", config_parse_sec,       0, &arg_mem_pressure_usec            },
                 {}
         };
 
@@ -160,7 +160,7 @@ 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, arg_mem_pressure_usec);
+        r = manager_start(m, arg_dry_run, arg_swap_used_limit, arg_mem_pressure_limit_permyriad, arg_mem_pressure_usec);
         if (r < 0)
                 return log_error_errno(r, "Failed to start up daemon: %m");
 
diff --git a/src/oom/oomd.conf b/src/oom/oomd.conf
index 766cb1717f..bd6a9391c6 100644
--- a/src/oom/oomd.conf
+++ b/src/oom/oomd.conf
@@ -13,5 +13,5 @@
 
 [OOM]
 #SwapUsedLimitPercent=90%
-#DefaultMemoryPressureLimitPercent=60%
+#DefaultMemoryPressureLimit=60%
 #DefaultMemoryPressureDurationSec=30s
diff --git a/src/shared/bus-get-properties.c b/src/shared/bus-get-properties.c
index 32f68d5e6a..a5ce7ef17f 100644
--- a/src/shared/bus-get-properties.c
+++ b/src/shared/bus-get-properties.c
@@ -55,23 +55,6 @@ int bus_property_get_id128(
                 return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
 }
 
-int bus_property_get_percent(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        char pstr[DECIMAL_STR_MAX(int) + 2];
-        int p = *(int*) userdata;
-
-        xsprintf(pstr, "%d%%", p);
-
-        return sd_bus_message_append_basic(reply, 's', pstr);
-}
-
 #if __SIZEOF_SIZE_T__ != 8
 int bus_property_get_size(
                 sd_bus *bus,
diff --git a/src/shared/bus-get-properties.h b/src/shared/bus-get-properties.h
index 9832c0d067..26f3e8588c 100644
--- a/src/shared/bus-get-properties.h
+++ b/src/shared/bus-get-properties.h
@@ -8,7 +8,6 @@
 int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
 int bus_property_set_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error);
 int bus_property_get_id128(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
-int bus_property_get_percent(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
 
 #define bus_property_get_usec ((sd_bus_property_get_t) NULL)
 #define bus_property_set_usec ((sd_bus_property_set_t) NULL)
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 2bab2299fb..f96059c699 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -435,10 +435,25 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
         if (STR_IN_SET(field, "DevicePolicy",
                               "Slice",
                               "ManagedOOMSwap",
-                              "ManagedOOMMemoryPressure",
-                              "ManagedOOMMemoryPressureLimitPercent"))
+                              "ManagedOOMMemoryPressure"))
                 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);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                return 1;
+        }
+
         if (STR_IN_SET(field, "CPUAccounting",
                               "MemoryAccounting",
                               "IOAccounting",
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 35d301d9db..c8c253d603 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -1245,3 +1245,4 @@ int config_parse_vlanprotocol(const char* unit,
 }
 
 DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value");
+DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad, "Failed to parse permyriad value");
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index f115cb23af..988d81e43a 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -148,6 +148,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
 CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
 CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol);
 CONFIG_PARSER_PROTOTYPE(config_parse_percent);
+CONFIG_PARSER_PROTOTYPE(config_parse_permyriad);
 
 typedef enum Disabled {
         DISABLED_CONFIGURATION,
diff --git a/test/units/testsuite-56-workload.slice b/test/units/testsuite-56-workload.slice
index 45b04914c6..8c32b28094 100644
--- a/test/units/testsuite-56-workload.slice
+++ b/test/units/testsuite-56-workload.slice
@@ -7,4 +7,4 @@ MemoryAccounting=true
 IOAccounting=true
 TasksAccounting=true
 ManagedOOMMemoryPressure=kill
-ManagedOOMMemoryPressureLimitPercent=1%
+ManagedOOMMemoryPressureLimit=1%
diff --git a/test/units/testsuite-56.sh b/test/units/testsuite-56.sh
index 4dc9d8c7a8..8b01fe37ed 100755
--- a/test/units/testsuite-56.sh
+++ b/test/units/testsuite-56.sh
@@ -20,7 +20,7 @@ systemctl start testsuite-56-testbloat.service
 
 # Verify systemd-oomd is monitoring the expected units
 oomctl | grep "/testsuite-56-workload.slice"
-oomctl | grep "1%"
+oomctl | grep "1.00%"
 oomctl | grep "Default Memory Pressure Duration: 5s"
 
 # systemd-oomd watches for elevated pressure for 30 seconds before acting.
-- 
2.29.2