From: Samir Mulani <samir@linux.ibm.com>
To: ltp@lists.linux.it
Cc: Samir Mulani <samir@linux.ibm.com>
Subject: [LTP] [PATCH v1 3/4] sched/psi: Add psi_proc_format01 test
Date: Sat, 24 Oct 2026 04:30:43 +0200 [thread overview]
Message-ID: <20261024023044.80055-4-samir@linux.ibm.com> (raw)
In-Reply-To: <20261024023044.80055-1-samir@linux.ibm.com>
Add a test case to verify the format and values in /proc/pressure/{cpu,memory,io}.
The test checks that:
- Each file has valid "some" and "full" lines with avg10, avg60, avg300,
and total fields.
- Averages are valid percentages between 0.00 and 100.00.
- Total stall times do not decrease over time.
- /proc/pressure/cpu reports "full" lines as 0.00 (per Linux 5.13+ behavior).
This test does not generate heavy system load and only validates interface
parsing. It reports TCONF if PSI is disabled.
Signed-off-by: Samir Mulani <samir@linux.ibm.com>
---
runtest/sched | 1 +
testcases/kernel/sched/psi/.gitignore | 1 +
.../kernel/sched/psi/psi_proc_format01.c | 191 ++++++++++++++++++
3 files changed, 193 insertions(+)
create mode 100644 testcases/kernel/sched/psi/psi_proc_format01.c
diff --git a/runtest/sched b/runtest/sched
index b6dc478a0..0651fafd9 100644
--- a/runtest/sched
+++ b/runtest/sched
@@ -23,3 +23,4 @@ sched_football sched_football
psi_invalid_trigger01 psi_invalid_trigger01
psi_multiple_trigger01 psi_multiple_trigger01
+psi_proc_format01 psi_proc_format01
diff --git a/testcases/kernel/sched/psi/.gitignore b/testcases/kernel/sched/psi/.gitignore
index 23a5e6567..8d1083ff2 100644
--- a/testcases/kernel/sched/psi/.gitignore
+++ b/testcases/kernel/sched/psi/.gitignore
@@ -1,2 +1,3 @@
/psi_invalid_trigger01
/psi_multiple_trigger01
+/psi_proc_format01
diff --git a/testcases/kernel/sched/psi/psi_proc_format01.c b/testcases/kernel/sched/psi/psi_proc_format01.c
new file mode 100644
index 000000000..7467e13d5
--- /dev/null
+++ b/testcases/kernel/sched/psi/psi_proc_format01.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 IBM Corp.
+ * Author: Samir Mulani <samir@linux.ibm.com>
+ */
+
+/*\
+ * Verify the format of the PSI files in /proc/pressure/.
+ *
+ * - /proc/pressure/{cpu,memory,io} have two lines labelled "some" and "full",
+ * each one carrying avg10, avg60, avg300 and total.
+ * - The averages are percentages, so they have to be between 0 and 100.
+ * - The totals never decrease between two consecutive reads.
+ * - The "full" line of /proc/pressure/cpu is always zero, the full stall
+ * state is undefined at the system level and is reported as zero for
+ * backward compatibility since Linux 5.13.
+ *
+ * The accounting of the counters under load is tested by psi_accounting01.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "tst_test.h"
+#include "tst_safe_stdio.h"
+
+#define PSI_CPU "/proc/pressure/cpu"
+#define PSI_MEM "/proc/pressure/memory"
+#define PSI_IO "/proc/pressure/io"
+
+struct psi_line {
+ char label[8];
+ double avg10;
+ double avg60;
+ double avg300;
+ unsigned long long total;
+};
+
+struct psi_snap {
+ struct psi_line some;
+ struct psi_line full;
+};
+
+#define PSI_LINE "%7s avg10=%lf avg60=%lf avg300=%lf total=%llu"
+
+static const char *const paths[] = {PSI_CPU, PSI_MEM, PSI_IO};
+
+/* Returns 0 if both lines were parsed, -1 otherwise */
+static int read_psi(const char *path, struct psi_snap *snap)
+{
+ FILE *fp = SAFE_FOPEN(path, "r");
+ int ret;
+
+ ret = fscanf(fp, PSI_LINE " " PSI_LINE,
+ snap->some.label, &snap->some.avg10, &snap->some.avg60,
+ &snap->some.avg300, &snap->some.total,
+ snap->full.label, &snap->full.avg10, &snap->full.avg60,
+ &snap->full.avg300, &snap->full.total);
+
+ SAFE_FCLOSE(fp);
+
+ if (ret != 10) {
+ tst_res(TFAIL, "%s: parsed %d/10 values", path, ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int avg_valid(double avg)
+{
+ /* A NaN fails both comparisons */
+ return avg >= 0.0 && avg <= 100.0;
+}
+
+static int line_valid(const char *path, const struct psi_line *line,
+ const char *label)
+{
+ if (strcmp(line->label, label)) {
+ tst_res(TFAIL, "%s: label is '%s', expected '%s'",
+ path, line->label, label);
+ return 0;
+ }
+
+ if (!avg_valid(line->avg10) || !avg_valid(line->avg60) ||
+ !avg_valid(line->avg300)) {
+ tst_res(TFAIL, "%s: '%s' averages out of range: %.2f %.2f %.2f",
+ path, label, line->avg10, line->avg60, line->avg300);
+ return 0;
+ }
+
+ return 1;
+}
+
+static void verify_format(unsigned int n)
+{
+ struct psi_snap snap;
+
+ if (read_psi(paths[n], &snap))
+ return;
+
+ if (line_valid(paths[n], &snap.some, "some") &&
+ line_valid(paths[n], &snap.full, "full"))
+ tst_res(TPASS, "%s has the expected format", paths[n]);
+}
+
+static void verify_monotonic(unsigned int n)
+{
+ struct psi_snap first, second;
+ int i;
+
+ if (read_psi(paths[n], &first))
+ return;
+
+ for (i = 0; i < 10; i++) {
+ usleep(10000);
+
+ if (read_psi(paths[n], &second))
+ return;
+
+ if (second.some.total < first.some.total ||
+ second.full.total < first.full.total) {
+ tst_res(TFAIL,
+ "%s: a total decreased: some %llu -> %llu, full %llu -> %llu",
+ paths[n], first.some.total, second.some.total,
+ first.full.total, second.full.total);
+ return;
+ }
+
+ first = second;
+ }
+
+ tst_res(TPASS, "%s totals never decrease", paths[n]);
+}
+
+static void verify_cpu_full_zero(void)
+{
+ struct psi_snap snap;
+
+ if (read_psi(PSI_CPU, &snap))
+ return;
+
+ if (snap.full.total || snap.full.avg10 || snap.full.avg60 ||
+ snap.full.avg300)
+ tst_res(TFAIL, "%s full line is not zero: avg10=%.2f total=%llu",
+ PSI_CPU, snap.full.avg10, snap.full.total);
+ else
+ tst_res(TPASS, "%s full line is zero", PSI_CPU);
+}
+
+static void run(unsigned int n)
+{
+ if (n < ARRAY_SIZE(paths))
+ verify_format(n);
+ else if (n < 2 * ARRAY_SIZE(paths))
+ verify_monotonic(n - ARRAY_SIZE(paths));
+ else
+ verify_cpu_full_zero();
+}
+
+static void setup(void)
+{
+ char buf[64];
+ int fd;
+
+ if (access(PSI_CPU, F_OK))
+ tst_brk(TCONF, "%s not available (CONFIG_PSI not set)", PSI_CPU);
+
+ fd = SAFE_OPEN(PSI_CPU, O_RDONLY);
+
+ /* psi=0 on the kernel command line makes the interface return EOPNOTSUPP */
+ if (read(fd, buf, sizeof(buf)) < 0) {
+ if (errno == EOPNOTSUPP)
+ tst_brk(TCONF, "PSI is disabled (psi=0 on kernel command line)");
+
+ tst_brk(TBROK | TERRNO, "read(%s) failed", PSI_CPU);
+ }
+
+ SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+ .tcnt = 2 * ARRAY_SIZE(paths) + 1,
+ .test = run,
+ .setup = setup,
+ .min_kver = "5.13",
+ .needs_kconfigs = (const char *const[]) {
+ "CONFIG_PSI=y",
+ NULL
+ },
+};
--
2.53.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
next prev parent reply other threads:[~2026-10-23 13:45 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-24 2:30 [LTP] [PATCH v1 0/4] sched/psi: Add tests for PSI interface Samir Mulani
2026-10-24 2:30 ` [LTP] [PATCH v1 1/4] sched/psi: Add psi_invalid_trigger01 test Samir Mulani
2026-10-23 17:55 ` [LTP] " linuxtestproject.agent
2026-10-24 2:30 ` [LTP] [PATCH v1 2/4] sched/psi: Add psi_multiple_trigger01 test Samir Mulani
2026-10-24 2:30 ` Samir Mulani [this message]
2026-10-24 2:30 ` [LTP] [PATCH v1 4/4] sched/psi: Add psi_accounting01 test Samir Mulani
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261024023044.80055-4-samir@linux.ibm.com \
--to=samir@linux.ibm.com \
--cc=ltp@lists.linux.it \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox