Linux Test Project
 help / color / mirror / Atom feed
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

  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