* [PATCH v5] selftests/cgroup: add PSI pressure trigger and validation tests
@ 2026-09-02 4:07 Tao Cui
2026-09-02 18:47 ` Michal Koutný
0 siblings, 1 reply; 3+ messages in thread
From: Tao Cui @ 2026-09-02 4:07 UTC (permalink / raw)
To: Michal Koutny, Suren Baghdasaryan
Cc: Tejun Heo, Johannes Weiner, Shuah Khan, cgroups, linux-kselftest,
linux-kernel, Ziyang Men, Tao Cui, cui.tao
From: Tao Cui <cuitao@kylinos.cn>
The cgroup selftests have no PSI coverage. Add test_psi.c: per-resource
trigger smoke tests (one trigger per fd, IRQ full-only), a
cgroup.pressure hide/show toggle test, and a CPU-pressure trigger test
using over-subscription. Skips when PSI is disabled or a resource is
absent.
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
Changes since v4 (Suren Baghdasaryan review):
- Report pressure_open() errors with ksft_perror() instead of a raw
fprintf.
- Create the test cgroup in FIXTURE_SETUP() so that setup and teardown
are symmetric, and drop the per-test creation and the NULL guard in
the teardown.
- Factor the identical bodies of proc_trigger_io/memory/cpu into
test_psi_write(); the helper takes _metadata so that its ASSERTs
attribute to the calling test, following the seccomp selftests
precedent.
- Drop the now-unneeded NULL init of self->cg and the stale stdbool.h
include left over from the restructuring.
Changes since v3 (Suren Baghdasaryan review):
- Convert to the kselftest harness: each case is a TEST_F(psi, ...)
with the cgroup root/PSI availability checks in FIXTURE_SETUP() and
the teardown (kill hogs, destroy cgroup) in FIXTURE_TEARDOWN(),
which also removes the "ret"/"created" bookkeeping.
- A trigger that does not fire within the poll timeout is now a FAIL
instead of a SKIP: ncpus+1 hogs with a 1usec threshold must stall,
so a timeout indicates a real problem.
- Treat a poll() timeout and a poll() error uniformly via ASSERT.
- Check sysconf(_SC_NPROCESSORS_ONLN) only for -1 and report
strerror(errno); declare variables one per line; for(;;) {}.
- Make hog_cpu() die with the runner via PR_SET_PDEATHSIG so an
interrupted run does not leave orphaned hogs pinning every CPU.
Changes since v2 (Suren Baghdasaryan, Michal Koutny review):
- Restructure the trigger test into per-resource cases (io, memory, cpu,
irq) so a failure points at the specific resource; irq is skipped when
/proc/pressure/irq is absent.
- Spawn the CPU hogs with cg_run_nowait() instead of open-coding fork(),
and arm the trigger with a 2s window so unprivileged users can set it.
- Address the remaining review comments on cleanup and robustness:
guard teardown with a "created" flag, use cg_read_strcmp() instead of
atoi(), report strerror() on errors, and fix the unused-parameter and
sign-compare nits.
Changes since v1 (Michal Koutny, sashiko review):
- Keep trigger tests smoke-level; switch the firing test from memory to
CPU pressure; drop churn_memory().
- Keep the runner out of the cgroup; add PSI/IRQ skip-guards and a
.gitignore entry.
v1: https://lore.kernel.org/all/20260724025826.504586-1-cui.tao@linux.dev/
v2: https://lore.kernel.org/all/20260728083742.2359320-1-cui.tao@linux.dev/
v3: https://lore.kernel.org/all/20260813133723.1663605-1-cui.tao@linux.dev/
v4: https://lore.kernel.org/all/20260824085913.546741-1-cui.tao@linux.dev/
---
tools/testing/selftests/cgroup/.gitignore | 1 +
tools/testing/selftests/cgroup/Makefile | 2 +
tools/testing/selftests/cgroup/config | 1 +
tools/testing/selftests/cgroup/test_psi.c | 191 ++++++++++++++++++++++
4 files changed, 195 insertions(+)
create mode 100644 tools/testing/selftests/cgroup/test_psi.c
diff --git a/tools/testing/selftests/cgroup/.gitignore b/tools/testing/selftests/cgroup/.gitignore
index 952e4448bf07..ce2b907c57ea 100644
--- a/tools/testing/selftests/cgroup/.gitignore
+++ b/tools/testing/selftests/cgroup/.gitignore
@@ -8,5 +8,6 @@ test_kill
test_kmem
test_memcontrol
test_pids
+test_psi
test_zswap
wait_inotify
diff --git a/tools/testing/selftests/cgroup/Makefile b/tools/testing/selftests/cgroup/Makefile
index e01584c2189a..a8c69e37332a 100644
--- a/tools/testing/selftests/cgroup/Makefile
+++ b/tools/testing/selftests/cgroup/Makefile
@@ -16,6 +16,7 @@ TEST_GEN_PROGS += test_kill
TEST_GEN_PROGS += test_kmem
TEST_GEN_PROGS += test_memcontrol
TEST_GEN_PROGS += test_pids
+TEST_GEN_PROGS += test_psi
TEST_GEN_PROGS += test_zswap
LOCAL_HDRS += $(selfdir)/clone3/clone3_selftests.h $(selfdir)/pidfd/pidfd.h
@@ -32,4 +33,5 @@ $(OUTPUT)/test_kill: $(LIBCGROUP_O)
$(OUTPUT)/test_kmem: $(LIBCGROUP_O)
$(OUTPUT)/test_memcontrol: $(LIBCGROUP_O)
$(OUTPUT)/test_pids: $(LIBCGROUP_O)
+$(OUTPUT)/test_psi: $(LIBCGROUP_O)
$(OUTPUT)/test_zswap: $(LIBCGROUP_O)
diff --git a/tools/testing/selftests/cgroup/config b/tools/testing/selftests/cgroup/config
index 39f979690dd3..8a3ef479e83d 100644
--- a/tools/testing/selftests/cgroup/config
+++ b/tools/testing/selftests/cgroup/config
@@ -4,3 +4,4 @@ CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_SCHED=y
CONFIG_MEMCG=y
CONFIG_PAGE_COUNTER=y
+CONFIG_PSI=y
diff --git a/tools/testing/selftests/cgroup/test_psi.c b/tools/testing/selftests/cgroup/test_psi.c
new file mode 100644
index 000000000000..281abfaf09d6
--- /dev/null
+++ b/tools/testing/selftests/cgroup/test_psi.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/prctl.h>
+#include <linux/limits.h>
+
+#include "../kselftest_harness.h"
+#include "cgroup_util.h"
+
+#define PSI_POLL_TIMEOUT_MS 5000
+
+/* PSI triggers are written with a trailing NUL the kernel parser expects. */
+static ssize_t write_trigger(int fd, const char *trigger)
+{
+ return write(fd, trigger, strlen(trigger) + 1);
+}
+
+static int pressure_open(const char *resource)
+{
+ char path[PATH_MAX];
+ int fd;
+
+ snprintf(path, sizeof(path), "/proc/pressure/%s", resource);
+ fd = open(path, O_RDWR);
+ if (fd < 0)
+ ksft_perror(path);
+ return fd;
+}
+
+FIXTURE(psi)
+{
+ char root[PATH_MAX];
+ char *cg;
+};
+
+FIXTURE_SETUP(psi)
+{
+ int psi_fd;
+
+ if (cg_find_unified_root(self->root, sizeof(self->root), NULL))
+ SKIP(return, "cgroup v2 isn't mounted");
+
+ /* PSI must be enabled (CONFIG_PSI=y, not disabled on the cmdline). */
+ psi_fd = open("/proc/pressure/memory", O_RDONLY);
+ if (psi_fd < 0)
+ SKIP(return, "PSI unavailable (CONFIG_PSI=n or psi=0)");
+ close(psi_fd);
+
+ self->cg = cg_name(self->root, "psi_trigger_test");
+ if (!self->cg)
+ SKIP(return, "failed to allocate cgroup name");
+ if (cg_create(self->cg))
+ SKIP(return, "failed to create cgroup: %s", strerror(errno));
+}
+
+FIXTURE_TEARDOWN(psi)
+{
+ cg_killall(self->cg);
+ cg_destroy(self->cg);
+ free(self->cg);
+}
+
+/*
+ * /proc/pressure/<resource> accepts exactly one trigger per file
+ * descriptor. Verify that a "some" trigger arms and that a second
+ * trigger on the same fd is rejected with EBUSY.
+ */
+static void test_psi_write(struct __test_metadata *_metadata,
+ const char *filename)
+{
+ int fd;
+
+ fd = pressure_open(filename);
+ ASSERT_GE(fd, 0);
+ ASSERT_GT(write_trigger(fd, "some 150000 2000000"), 0);
+ ASSERT_EQ(-1, write_trigger(fd, "full 150000 2000000"));
+ ASSERT_EQ(EBUSY, errno);
+ close(fd);
+}
+
+TEST_F(psi, proc_trigger_io)
+{
+ test_psi_write(_metadata, "io");
+}
+
+TEST_F(psi, proc_trigger_memory)
+{
+ test_psi_write(_metadata, "memory");
+}
+
+TEST_F(psi, proc_trigger_cpu)
+{
+ test_psi_write(_metadata, "cpu");
+}
+
+/*
+ * irq only tracks "full", so a "some" trigger must be rejected while a
+ * "full" trigger arms. irq is optional -- it only exists with IRQ-time
+ * accounting -- so a missing /proc/pressure/irq is SKIP, not FAIL.
+ */
+TEST_F(psi, proc_trigger_irq)
+{
+ int fd;
+
+ fd = pressure_open("irq");
+ if (fd < 0)
+ SKIP(return, "/proc/pressure/irq unavailable");
+
+ ASSERT_EQ(-1, write_trigger(fd, "some 150000 2000000"));
+ ASSERT_GT(write_trigger(fd, "full 150000 2000000"), 0);
+ close(fd);
+}
+
+/*
+ * cgroup.pressure gates visibility of the per-resource *.pressure files
+ * inside a cgroup: writing 0 hides them, writing 1 shows them again.
+ * Drive one hide/show cycle and check that memory.pressure appears and
+ * disappears along with it.
+ */
+TEST_F(psi, cgroup_pressure_toggle)
+{
+ char buf[BUF_SIZE];
+
+ ASSERT_EQ(0, cg_write(self->cg, "cgroup.pressure", "0"));
+ ASSERT_EQ(0, cg_read_strcmp(self->cg, "cgroup.pressure", "0\n"));
+ ASSERT_LT(cg_read(self->cg, "memory.pressure", buf, sizeof(buf)), 0);
+
+ ASSERT_EQ(0, cg_write(self->cg, "cgroup.pressure", "1"));
+ ASSERT_EQ(0, cg_read_strcmp(self->cg, "cgroup.pressure", "1\n"));
+ ASSERT_GE(cg_read(self->cg, "memory.pressure", buf, sizeof(buf)), 0);
+}
+
+/*
+ * A child that burns CPU forever; stopped by cg_killall() on teardown.
+ * It also dies with the runner, so an interrupted run (e.g. Ctrl-C
+ * during poll()) does not leave orphaned hogs pinning every CPU.
+ */
+static int hog_cpu(const char *cgroup, void *arg)
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL);
+ for (;;) {}
+ return 0;
+}
+
+/*
+ * Arm a "some" trigger on a cgroup's cpu.pressure, oversubscribe the
+ * cgroup with more spinning hogs than there are CPUs, and check that the
+ * trigger fires once the cgroup stalls on CPU.
+ */
+TEST_F(psi, cgroup_trigger_fire)
+{
+ char *cpupress;
+ struct pollfd pfd = { .events = POLLPRI };
+ long ncpus;
+ int fd;
+ int i;
+
+ cpupress = cg_control(self->cg, "cpu.pressure");
+ ASSERT_NE(NULL, cpupress);
+ fd = open(cpupress, O_RDWR);
+ free(cpupress);
+ ASSERT_GE(fd, 0);
+ pfd.fd = fd;
+
+ /*
+ * 1usec threshold over a 2s window: any CPU stall fires it. The 2s
+ * window is the smallest unprivileged users are allowed to arm.
+ */
+ ASSERT_GT(write_trigger(fd, "some 1 2000000"), 0);
+
+ ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+ if (ncpus == -1)
+ TH_LOG("sysconf(_SC_NPROCESSORS_ONLN): %s", strerror(errno));
+ ASSERT_NE(-1, ncpus);
+
+ /* ncpus+1 hogs guarantee CPU contention inside the cgroup. */
+ for (i = 0; i < ncpus + 1; i++)
+ ASSERT_GE(cg_run_nowait(self->cg, hog_cpu, NULL), 0);
+
+ ASSERT_EQ(1, poll(&pfd, 1, PSI_POLL_TIMEOUT_MS));
+ ASSERT_NE(0, pfd.revents & POLLPRI);
+ close(fd);
+}
+
+TEST_HARNESS_MAIN
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v5] selftests/cgroup: add PSI pressure trigger and validation tests
2026-09-02 4:07 [PATCH v5] selftests/cgroup: add PSI pressure trigger and validation tests Tao Cui
@ 2026-09-02 18:47 ` Michal Koutný
2026-09-03 7:24 ` Tao Cui
0 siblings, 1 reply; 3+ messages in thread
From: Michal Koutný @ 2026-09-02 18:47 UTC (permalink / raw)
To: Tao Cui
Cc: Suren Baghdasaryan, Tejun Heo, Johannes Weiner, Shuah Khan,
cgroups, linux-kselftest, linux-kernel, Ziyang Men, Tao Cui
[-- Attachment #1: Type: text/plain, Size: 3525 bytes --]
Hello Tao.
On Wed, Sep 02, 2026 at 12:07:25PM +0800, Tao Cui <cui.tao@linux.dev> wrote:
> +/* PSI triggers are written with a trailing NUL the kernel parser expects. */
> +static ssize_t write_trigger(int fd, const char *trigger)
> +{
> + return write(fd, trigger, strlen(trigger) + 1);
> +}
Hyrum's law. It all works for me: NUL, \n or just write(2) the exact
length of the string.
For conventionality, I'd prefer the simple literals and plain strlen() +
0. (I reckon cg_write() cannot be used because of FD access.)
> +
> +static int pressure_open(const char *resource)
> +{
> + char path[PATH_MAX];
> + int fd;
> +
> + snprintf(path, sizeof(path), "/proc/pressure/%s", resource);
> + fd = open(path, O_RDWR);
> + if (fd < 0)
> + ksft_perror(path);
This outputs:
| # /proc/pressure/irq: No such file or directory (2)
| # SKIP /proc/pressure/irq unavailable
I.e. similar message is printed twice.
Since strace is a companion of cgroup selftests, I'd keep this helper
silent.
> + return fd;
> +}
> +
> +FIXTURE(psi)
> +{
> + char root[PATH_MAX];
> + char *cg;
> +};
> +
> +FIXTURE_SETUP(psi)
> +{
> + int psi_fd;
> +
> + if (cg_find_unified_root(self->root, sizeof(self->root), NULL))
> + SKIP(return, "cgroup v2 isn't mounted");
> +
> + /* PSI must be enabled (CONFIG_PSI=y, not disabled on the cmdline). */
> + psi_fd = open("/proc/pressure/memory", O_RDONLY);
> + if (psi_fd < 0)
> + SKIP(return, "PSI unavailable (CONFIG_PSI=n or psi=0)");
> + close(psi_fd);
> +
> + self->cg = cg_name(self->root, "psi_trigger_test");
> + if (!self->cg)
> + SKIP(return, "failed to allocate cgroup name");
> + if (cg_create(self->cg))
> + SKIP(return, "failed to create cgroup: %s", strerror(errno));
Why are these two SKIPs (not failures)?
> +TEST_F(psi, cgroup_trigger_fire)
> +{
> + char *cpupress;
> + struct pollfd pfd = { .events = POLLPRI };
> + long ncpus;
> + int fd;
> + int i;
> +
> + cpupress = cg_control(self->cg, "cpu.pressure");
> + ASSERT_NE(NULL, cpupress);
> + fd = open(cpupress, O_RDWR);
> + free(cpupress);
> + ASSERT_GE(fd, 0);
> + pfd.fd = fd;
> +
> + /*
> + * 1usec threshold over a 2s window: any CPU stall fires it. The 2s
> + * window is the smallest unprivileged users are allowed to arm.
> + */
> + ASSERT_GT(write_trigger(fd, "some 1 2000000"), 0);
The selftest rarely can be run as unprivileged user (even test cgroup
creation needs privileges), so this comment is irrelevant. (But it's
fine to test with that value.)
On the more abstract level -- I was playing with this and thinking about
a value that'd test both sides, i.e. false triggers as well as false
non-triggers. I'd find that to be the half of the window and the number
of tasks should be then (3*ncpus + 1) / 2.
Or perhaps test two thresholds, one tiny like you did and one maximum
(whole window) with same amount tasks but expect trigger, no trigger
respectively.
> +
> + ncpus = sysconf(_SC_NPROCESSORS_ONLN);
> + if (ncpus == -1)
> + TH_LOG("sysconf(_SC_NPROCESSORS_ONLN): %s", strerror(errno));
> + ASSERT_NE(-1, ncpus);
Same as messages from pressure_open() above. Simply assert.
> +
> + /* ncpus+1 hogs guarantee CPU contention inside the cgroup. */
> + for (i = 0; i < ncpus + 1; i++)
> + ASSERT_GE(cg_run_nowait(self->cg, hog_cpu, NULL), 0);
> +
> + ASSERT_EQ(1, poll(&pfd, 1, PSI_POLL_TIMEOUT_MS));
> + ASSERT_NE(0, pfd.revents & POLLPRI);
> + close(fd);
> +}
> +
> +TEST_HARNESS_MAIN
All in all, this looks so much better than the initial version, well
done. Just a few polishing touches.
Michal
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v5] selftests/cgroup: add PSI pressure trigger and validation tests
2026-09-02 18:47 ` Michal Koutný
@ 2026-09-03 7:24 ` Tao Cui
0 siblings, 0 replies; 3+ messages in thread
From: Tao Cui @ 2026-09-03 7:24 UTC (permalink / raw)
To: Michal Koutný, Suren Baghdasaryan
Cc: cui.tao, Tejun Heo, Johannes Weiner, Shuah Khan, cgroups,
linux-kselftest, linux-kernel, Ziyang Men, Tao Cui
Hello Michal, Suren,
在 2026/9/3 02:47, Michal Koutný 写道:
> Hello Tao.
>
> On Wed, Sep 02, 2026 at 12:07:25PM +0800, Tao Cui <cui.tao@linux.dev> wrote:
>> +/* PSI triggers are written with a trailing NUL the kernel parser expects. */
>> +static ssize_t write_trigger(int fd, const char *trigger)
>> +{
>> + return write(fd, trigger, strlen(trigger) + 1);
>> +}
>
> Hyrum's law. It all works for me: NUL, \n or just write(2) the exact
> length of the string.
> For conventionality, I'd prefer the simple literals and plain strlen() +
> 0. (I reckon cg_write() cannot be used because of FD access.)
>
Your Hyrum's law point made me look at the parser, and I'm glad it
did, because the behavior is more subtle than "all of them work".
psi_write() does
buf[buf_size - 1] = '\0';
i.e. it overwrites the last byte of whatever was written. With a plain
strlen()-sized write that eats the last digit: "some 150000 2000000"
silently arms a 200000us window when privileged, and fails with EINVAL
for unprivileged users (200000 is not a multiple of the 2s minimum). I
reproduced both on 7.0.0-28 here. I suspect your runs succeeded
because a truncated window still makes a valid trigger for root, so
nothing looked off.
I went with your \n variant instead: the newline gets clobbered, the
payload stays intact, and it is the conventional procfile form. So the
reliance on the undocumented NUL is gone, even though not quite via
strlen()+0.
Two follow-ups this suggests, if there is interest (I'm not pushing
either within this series):
- psi.rst says nothing about the terminator while sysfs documents its
(append, not clobber) behavior explicitly; a sentence in psi.rst
would at least make the convention discoverable.
- kernfs and sysfs both append the NUL after the written data, so the
user bytes survive. psi_write() could do the same with
buf_size = min(nbytes, sizeof(buf) - 1) and buf[buf_size] = '\0'.
Terminator-terminated writes keep their exact meaning, and a bare
strlen() write would parse in full instead of losing its last digit.
That would be the more principled fix, but it is a behavior change
for unterminated writes, so it needs a call from the PSI maintainers.
>> +
>> +static int pressure_open(const char *resource)
>> +{
>> + char path[PATH_MAX];
>> + int fd;
>> +
>> + snprintf(path, sizeof(path), "/proc/pressure/%s", resource);
>> + fd = open(path, O_RDWR);
>> + if (fd < 0)
>> + ksft_perror(path);
>
> This outputs:
> | # /proc/pressure/irq: No such file or directory (2)
> | # SKIP /proc/pressure/irq unavailable
>
> I.e. similar message is printed twice.
> Since strace is a companion of cgroup selftests, I'd keep this helper
> silent.
>
Agreed, the helper is silent now. The duplicate was my own doing: I
added the print in v5 on Suren's v4 request (it replaced a raw
fprintf) without noticing the SKIP message right below it already
carries the reason, so removing it satisfies both comments.
>> + return fd;
>> +}
>> +
>> +FIXTURE(psi)
>> +{
>> + char root[PATH_MAX];
>> + char *cg;
>> +};
>> +
>> +FIXTURE_SETUP(psi)
>> +{
>> + int psi_fd;
>> +
>> + if (cg_find_unified_root(self->root, sizeof(self->root), NULL))
>> + SKIP(return, "cgroup v2 isn't mounted");
>> +
>> + /* PSI must be enabled (CONFIG_PSI=y, not disabled on the cmdline). */
>> + psi_fd = open("/proc/pressure/memory", O_RDONLY);
>> + if (psi_fd < 0)
>> + SKIP(return, "PSI unavailable (CONFIG_PSI=n or psi=0)");
>> + close(psi_fd);
>> +
>> + self->cg = cg_name(self->root, "psi_trigger_test");
>> + if (!self->cg)
>> + SKIP(return, "failed to allocate cgroup name");
>> + if (cg_create(self->cg))
>> + SKIP(return, "failed to create cgroup: %s", strerror(errno));
>
> Why are these two SKIPs (not failures)?
>
You're right, they are not environment problems. They are ASSERTs in
FIXTURE_SETUP() now, so a run without privileges fails loudly instead
of vanishing into skips.
>> +TEST_F(psi, cgroup_trigger_fire)
>> +{
>> + char *cpupress;
>> + struct pollfd pfd = { .events = POLLPRI };
>> + long ncpus;
>> + int fd;
>> + int i;
>> +
>> + cpupress = cg_control(self->cg, "cpu.pressure");
>> + ASSERT_NE(NULL, cpupress);
>> + fd = open(cpupress, O_RDWR);
>> + free(cpupress);
>> + ASSERT_GE(fd, 0);
>> + pfd.fd = fd;
>> +
>> + /*
>> + * 1usec threshold over a 2s window: any CPU stall fires it. The 2s
>> + * window is the smallest unprivileged users are allowed to arm.
>> + */
>> + ASSERT_GT(write_trigger(fd, "some 1 2000000"), 0);
>
> The selftest rarely can be run as unprivileged user (even test cgroup
> creation needs privileges), so this comment is irrelevant. (But it's
> fine to test with that value.)
>
Dropped.
> On the more abstract level -- I was playing with this and thinking about
> a value that'd test both sides, i.e. false triggers as well as false
> non-triggers. I'd find that to be the half of the window and the number
> of tasks should be then (3*ncpus + 1) / 2.
> Or perhaps test two thresholds, one tiny like you did and one maximum
> (whole window) with same amount tasks but expect trigger, no trigger
> respectively.
>
I tried both of your variants before picking one. The half-window
threshold with (3*ncpus+1)/2 hogs fired reliably, and the two-threshold
variant also held up on the negative side: with the threshold equal to
the whole window, ncpus+1 hogs never fired it (measured cpu.pressure
"some" stays around 2-17% under that oversubscription, so the margin
is comfortable rather than borderline). I kept the existing tiny-
threshold test and added cgroup_trigger_no_fire for the whole-window
side, which matches your second variant and keeps the hog setup shared.
>
>> +
>> + ncpus = sysconf(_SC_NPROCESSORS_ONLN);
>> + if (ncpus == -1)
>> + TH_LOG("sysconf(_SC_NPROCESSORS_ONLN): %s", strerror(errno));
>> + ASSERT_NE(-1, ncpus);
>
> Same as messages from pressure_open() above. Simply assert.
>
>> +
>> + /* ncpus+1 hogs guarantee CPU contention inside the cgroup. */
>> + for (i = 0; i < ncpus + 1; i++)
>> + ASSERT_GE(cg_run_nowait(self->cg, hog_cpu, NULL), 0);
>> +
>> + ASSERT_EQ(1, poll(&pfd, 1, PSI_POLL_TIMEOUT_MS));
>> + ASSERT_NE(0, pfd.revents & POLLPRI);
>> + close(fd);
>> +}
>> +
>> +TEST_HARNESS_MAIN
>
> All in all, this looks so much better than the initial version, well
> done. Just a few polishing touches.
>
All 7 tests pass on a 2-CPU and a 16-CPU machine.
Thank you both, this series learned a lot from you: Suren walked me
through the harness conversion and the reporting details, and you kept
the semantics honest, which is what surfaced the parser behavior. The
test is in a much better shape than what I started with, and the
parser finding above came out of your push on both directions of the
trigger.
Thanks
Tao
> Michal
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-03 7:24 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02 4:07 [PATCH v5] selftests/cgroup: add PSI pressure trigger and validation tests Tao Cui
2026-09-02 18:47 ` Michal Koutný
2026-09-03 7:24 ` Tao Cui
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox