All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.