* [LTP] [PATCH v19] thermal: add new test group
@ 2026-05-06 11:24 Piotr Kubaj
2026-05-06 14:16 ` [LTP] " linuxtestproject.agent
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Piotr Kubaj @ 2026-05-06 11:24 UTC (permalink / raw)
To: ltp; +Cc: helena.anna.dubel, tomasz.ossowski, rafael.j.wysocki,
daniel.niestepski
Currently consists of only one test for the CPU package thermal sensor
interface for Intel platforms.
It works by checking the initial count of thermal interrupts. Then it
decreases the threshold for sending a thermal interrupt to just above
the current temperature and runs a workload on the CPU. Finally, it
restores the original thermal threshold and checks whether the number
of thermal interrupts increased.
Signed-off-by: Piotr Kubaj <piotr.kubaj@intel.com>
---
Correct year in the Makefile.
runtest/thermal | 3 +
testcases/kernel/Makefile | 1 +
testcases/kernel/thermal/.gitignore | 1 +
testcases/kernel/thermal/Makefile | 9 +
.../kernel/thermal/thermal_interrupt_events.c | 242 ++++++++++++++++++
5 files changed, 256 insertions(+)
create mode 100644 runtest/thermal
create mode 100644 testcases/kernel/thermal/.gitignore
create mode 100644 testcases/kernel/thermal/Makefile
create mode 100644 testcases/kernel/thermal/thermal_interrupt_events.c
diff --git a/runtest/thermal b/runtest/thermal
new file mode 100644
index 000000000..57e3d29f8
--- /dev/null
+++ b/runtest/thermal
@@ -0,0 +1,3 @@
+# Thermal driver API
+# https://docs.kernel.org/driver-api/thermal/
+thermal_interrupt_events thermal_interrupt_events
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index 98fd45a9d..ac816e4e8 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -36,6 +36,7 @@ SUBDIRS += connectors \
sched \
security \
sound \
+ thermal \
tracing \
uevents \
watchqueue \
diff --git a/testcases/kernel/thermal/.gitignore b/testcases/kernel/thermal/.gitignore
new file mode 100644
index 000000000..1090bdad8
--- /dev/null
+++ b/testcases/kernel/thermal/.gitignore
@@ -0,0 +1 @@
+thermal_interrupt_events
diff --git a/testcases/kernel/thermal/Makefile b/testcases/kernel/thermal/Makefile
new file mode 100644
index 000000000..eda3a64f1
--- /dev/null
+++ b/testcases/kernel/thermal/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026, Intel Corporation. All rights reserved.
+# Author:Piotr Kubaj <piotr.kubaj@intel.com>
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/thermal/thermal_interrupt_events.c b/testcases/kernel/thermal/thermal_interrupt_events.c
new file mode 100644
index 000000000..1f24c3ae4
--- /dev/null
+++ b/testcases/kernel/thermal/thermal_interrupt_events.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Intel - http://www.intel.com/
+ */
+
+/*\
+ * Tests the CPU package thermal sensor interface for Intel platforms.
+
+ * Works by checking the initial count of thermal interrupts. Then it
+ * decreases the threshold for sending a thermal interrupt to just above
+ * the current temperature and runs a workload on the CPU. Finally, it restores
+ * the original thermal threshold and checks whether the number of thermal
+ * interrupts increased.
+ */
+
+#include <ctype.h>
+#include <inttypes.h>
+#include "tst_safe_stdio.h"
+#include "tst_test.h"
+#include "tst_timer_test.h"
+
+#define TEST_RUNTIME 3
+#define RUNTIME 30
+#define SLEEP 10
+#define TEMP_INCREMENT 10
+
+static bool x86_pkg_temp_tz_found, *x86_pkg_temp_tz;
+static char temp_path[PATH_MAX], trip_path[PATH_MAX];
+static int nproc, temp_high, temp, *trip_orig, tz_counter;
+static uint64_t *interrupt_init, *interrupt_later;
+
+static void read_interrupts(uint64_t *interrupts)
+{
+ bool interrupts_found = false;
+ char line[8192];
+
+ memset(interrupts, 0, nproc * sizeof(*interrupts));
+ FILE *fp = SAFE_FOPEN("/proc/interrupts", "r");
+
+ while (fgets(line, sizeof(line), fp)) {
+ if (!strstr(line, "Thermal event interrupts"))
+ continue;
+
+ interrupts_found = true;
+ char *ptr = strchr(line, ':');
+
+ for (int i = 0; i < nproc; i++) {
+ char *endptr;
+
+ while (*ptr && !isdigit(*ptr))
+ ptr++;
+
+ errno = 0;
+
+ interrupts[i] = strtoull(ptr, &endptr, 10);
+
+ if (ptr == endptr)
+ tst_brk(TBROK, "CPU %d: interrupt not found", i);
+
+ if (errno == ERANGE)
+ tst_brk(TBROK, "CPU %d: interrupt out of range", i);
+
+ ptr = endptr;
+ tst_res(TDEBUG, "interrupts[%d]: %" PRIu64, i, interrupts[i]);
+ }
+ break;
+ }
+ SAFE_FCLOSE(fp);
+ if (!interrupts_found)
+ tst_brk(TCONF, "No Thermal event interrupts line in /proc/interrupts");
+}
+
+static void setup(void)
+{
+ char line[8192];
+
+ nproc = tst_ncpus();
+ tst_set_runtime(nproc * TEST_RUNTIME);
+
+ tst_res(TDEBUG, "Number of logical cores: %d", nproc);
+ interrupt_init = SAFE_CALLOC(nproc, sizeof(uint64_t));
+ interrupt_later = SAFE_CALLOC(nproc, sizeof(uint64_t));
+
+ DIR *dir = SAFE_OPENDIR("/sys/class/thermal/");
+ struct dirent *entry;
+
+ while ((entry = SAFE_READDIR(dir))) {
+ if ((!strncmp(entry->d_name, "thermal_zone", sizeof("thermal_zone") - 1)))
+ tz_counter++;
+ }
+ SAFE_CLOSEDIR(dir);
+ tst_res(TDEBUG, "Found %d thermal zone(s)", tz_counter);
+
+ x86_pkg_temp_tz = SAFE_CALLOC(tz_counter, sizeof(bool));
+ trip_orig = SAFE_CALLOC(tz_counter, sizeof(int));
+
+ for (int i = 0; i < tz_counter; i++) {
+ char path[PATH_MAX];
+
+ snprintf(path, PATH_MAX, "/sys/class/thermal/thermal_zone%d/type", i);
+ tst_res(TDEBUG, "Checking whether %s is x86_pkg_temp", path);
+
+ SAFE_FILE_SCANF(path, "%8191s", line);
+ if (strstr(line, "x86_pkg_temp")) {
+ tst_res(TDEBUG, "Thermal zone %d uses x86_pkg_temp", i);
+ x86_pkg_temp_tz[i] = true;
+ x86_pkg_temp_tz_found = true;
+ snprintf(trip_path, PATH_MAX, "/sys/class/thermal/thermal_zone%d/trip_point_1_temp", i);
+ SAFE_ACCESS(trip_path, R_OK | W_OK);
+ SAFE_FILE_SCANF(trip_path, "%d", &trip_orig[i]);
+ }
+ }
+
+ if (!x86_pkg_temp_tz_found)
+ tst_brk(TCONF, "No thermal zone uses x86_pkg_temp");
+}
+
+static void cpu_workload(double run_time)
+{
+ tst_timer_start(CLOCK_MONOTONIC);
+ int num = 2;
+
+ while (!tst_timer_expired_ms(run_time * 1000)) {
+ for (int i = 2; i * i <= num; i++) {
+ if (num % i == 0)
+ break;
+ }
+ num++;
+ SAFE_FILE_SCANF(temp_path, "%d", &temp);
+
+ if (temp > temp_high)
+ break;
+ }
+}
+
+static void test_zone(int i)
+{
+ int sleep_time = SLEEP;
+ double run_time = RUNTIME;
+
+ snprintf(temp_path, PATH_MAX, "/sys/class/thermal/thermal_zone%d/temp", i);
+ tst_res(TINFO, "Testing %s", temp_path);
+ SAFE_FILE_SCANF(temp_path, "%d", &temp);
+ if (temp < 0)
+ tst_brk(TBROK, "Unexpected zone temperature value %d", temp);
+
+ tst_res(TDEBUG, "Current temperature for %s: %d", temp_path, temp);
+
+ temp_high = temp + TEMP_INCREMENT;
+
+ snprintf(trip_path, PATH_MAX, "/sys/class/thermal/thermal_zone%d/trip_point_1_temp", i);
+
+ tst_res(TDEBUG, "Setting new trip_point_1_temp value: %d", temp_high);
+ SAFE_FILE_PRINTF(trip_path, "%d", temp_high);
+
+ while (sleep_time > 0) {
+ tst_res(TDEBUG, "Running for %f seconds, then sleeping for %d seconds", run_time, sleep_time);
+
+ for (int j = 0; j < nproc; j++) {
+ if (!SAFE_FORK()) {
+ cpu_workload(run_time);
+ exit(0);
+ }
+ }
+
+ tst_reap_children();
+
+ SAFE_FILE_SCANF(temp_path, "%d", &temp);
+ tst_res(TDEBUG, "Temperature for %s after a test: %d", temp_path, temp);
+
+ if (temp > temp_high)
+ break;
+ sleep(sleep_time--);
+ run_time -= 3;
+ }
+}
+
+static void cleanup(void)
+{
+ if (x86_pkg_temp_tz_found) {
+ for (int i = 0; i < tz_counter; i++) {
+ if (x86_pkg_temp_tz[i]) {
+ snprintf(trip_path, PATH_MAX, "/sys/class/thermal/thermal_zone%d/trip_point_1_temp", i);
+ SAFE_FILE_PRINTF(trip_path, "%d", trip_orig[i]);
+ }
+ }
+ }
+
+ free(x86_pkg_temp_tz);
+ free(interrupt_init);
+ free(interrupt_later);
+ free(trip_orig);
+}
+
+static void run(void)
+{
+ for (int i = 0; i < tz_counter; i++) {
+ if (x86_pkg_temp_tz[i]) {
+ read_interrupts(interrupt_init);
+ test_zone(i);
+ read_interrupts(interrupt_later);
+
+ bool interrupt_increased = false;
+ for (int j = 0; j < nproc; j++) {
+ if (interrupt_later[j] > interrupt_init[j]) {
+ interrupt_increased = true;
+ tst_res(TINFO, "CPU %d interrupt counter: %" PRIu64 " (previous: %" PRIu64 ")",
+ j, interrupt_later[j], interrupt_init[j]);
+ }
+ }
+
+ if (!interrupt_increased)
+ tst_res(TFAIL, "No thermal interrupt increase detected");
+ else if (temp <= temp_high)
+ tst_res(TFAIL, "Thermal interrupts increased but temperature did not rise as expected");
+ else
+ tst_res(TPASS, "x86 package thermal interrupt triggered");
+ }
+ }
+}
+
+static struct tst_test test = {
+ .cleanup = cleanup,
+ .forks_child = 1,
+ .needs_kconfigs = (const char *const []) {
+ "CONFIG_X86_PKG_TEMP_THERMAL",
+ NULL
+ },
+ .min_runtime = 5,
+ .needs_root = 1,
+ .setup = setup,
+ .supported_archs = (const char *const []) {
+ "x86",
+ "x86_64",
+ NULL
+ },
+ .tags = (const struct tst_tag[]) {
+ {"linux-git", "9635c586a559ba0e45b2bfbff79c937ddbaf1a62"},
+ {}
+ },
+ .test_all = run
+};
--
2.47.3
---------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Spolka oswiadcza, ze posiada status duzego przedsiebiorcy w rozumieniu ustawy z dnia 8 marca 2013 r. o przeciwdzialaniu nadmiernym opoznieniom w transakcjach handlowych.
Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by others is strictly prohibited.
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [LTP] thermal: add new test group
2026-05-06 11:24 [LTP] [PATCH v19] thermal: add new test group Piotr Kubaj
@ 2026-05-06 14:16 ` linuxtestproject.agent
2026-05-06 14:23 ` Andrea Cervesato via ltp
2026-05-11 7:51 ` [LTP] [PATCH v19] " Petr Vorel
2026-05-12 9:56 ` Cyril Hrubis
2 siblings, 1 reply; 7+ messages in thread
From: linuxtestproject.agent @ 2026-05-06 14:16 UTC (permalink / raw)
To: Piotr Kubaj; +Cc: ltp
Hi Piotr,
On Wed, 6 May 2026 13:24:21 +0200, Piotr Kubaj wrote:
> [PATCH] thermal: add new test group
> +/*\
> + * Tests the CPU package thermal sensor interface for Intel platforms.
> +
> + * Works by checking the initial count of thermal interrupts. Then it
The blank line separating the two paragraphs must carry the " *" prefix,
i.e. " *" on its own, not an empty line.
> + if (temp > temp_high)
> + break;
> + sleep(sleep_time--);
> + run_time -= 3;
sleep() for synchronisation is not allowed (LTP ground rule G2). Replace
with a polling loop using tst_timer_start()/tst_timer_expired_ms(), or
remove the sleep and let the workload loop duration do the pacing.
---
Note:
Our agent completed the review of the patch.
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v19] thermal: add new test group
2026-05-06 11:24 [LTP] [PATCH v19] thermal: add new test group Piotr Kubaj
2026-05-06 14:16 ` [LTP] " linuxtestproject.agent
@ 2026-05-11 7:51 ` Petr Vorel
2026-05-12 9:56 ` Cyril Hrubis
2 siblings, 0 replies; 7+ messages in thread
From: Petr Vorel @ 2026-05-11 7:51 UTC (permalink / raw)
To: Piotr Kubaj
Cc: helena.anna.dubel, tomasz.ossowski, rafael.j.wysocki, ltp,
daniel.niestepski
Hi Piotr,
> Currently consists of only one test for the CPU package thermal sensor
> interface for Intel platforms.
> It works by checking the initial count of thermal interrupts. Then it
> decreases the threshold for sending a thermal interrupt to just above
> the current temperature and runs a workload on the CPU. Finally, it
> restores the original thermal threshold and checks whether the number
> of thermal interrupts increased.
Reviewed-by: Petr Vorel <pvorel@suse.cz>
While I consider this ready and Andrea already acked this (I really want to get
this merged before LTP new release in the end of May), let's wait for Cyril's
ack (you're on his TODO list).
Thanks for your work and patience.
Kind regards,
Petr
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v19] thermal: add new test group
2026-05-06 11:24 [LTP] [PATCH v19] thermal: add new test group Piotr Kubaj
2026-05-06 14:16 ` [LTP] " linuxtestproject.agent
2026-05-11 7:51 ` [LTP] [PATCH v19] " Petr Vorel
@ 2026-05-12 9:56 ` Cyril Hrubis
2026-05-13 10:54 ` Petr Vorel
2 siblings, 1 reply; 7+ messages in thread
From: Cyril Hrubis @ 2026-05-12 9:56 UTC (permalink / raw)
To: Piotr Kubaj
Cc: daniel.niestepski, tomasz.ossowski, helena.anna.dubel,
rafael.j.wysocki, ltp
Hi!
> +static void setup(void)
> +{
> + char line[8192];
> +
> + nproc = tst_ncpus();
> + tst_set_runtime(nproc * TEST_RUNTIME);
The last thing that I do not think is correct is this part. We are
setting the runtime here based on the number of CPUs and not based on
the number of actuall test iterations.
I guess that we need to:
Turn the x86_pkg_temp_tz_found into a counter and collect the number
of thermal zones found and set the runtime at the end of the setup
with the counter instead.
And at the same time the TEST_RUNTIME appears to be significantly
smaller than the actual runtime.
The upper bound for the runtime is a sum of all possible iterations,
if we simplify it a bit it would be roughly ((RUNTIME+SLEEPTIME) *
(SLEEPTIME/2))
As we are doing SLEEPTIME iterations with SLEEPTIME and RUNTIME
getting smaller in each of them so it will average out to SLEEPTIME/2
iterations with full (RUNTIME+SLEEPTIME)
So I guess that we need:
#define TEST_RUNTIME ((RUNTIME+SLEEPTIME) * (SLEEPTIME/2))
The rest looks good to me.
With the runtime calculation fixed:
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [LTP] [PATCH v19] thermal: add new test group
2026-05-12 9:56 ` Cyril Hrubis
@ 2026-05-13 10:54 ` Petr Vorel
2026-05-13 12:06 ` Cyril Hrubis
0 siblings, 1 reply; 7+ messages in thread
From: Petr Vorel @ 2026-05-13 10:54 UTC (permalink / raw)
To: Cyril Hrubis
Cc: helena.anna.dubel, tomasz.ossowski, rafael.j.wysocki,
daniel.niestepski, ltp
> Hi!
> > +static void setup(void)
> > +{
> > + char line[8192];
> > +
> > + nproc = tst_ncpus();
> > + tst_set_runtime(nproc * TEST_RUNTIME);
> The last thing that I do not think is correct is this part. We are
> setting the runtime here based on the number of CPUs and not based on
> the number of actuall test iterations.
> I guess that we need to:
> Turn the x86_pkg_temp_tz_found into a counter and collect the number
> of thermal zones found and set the runtime at the end of the setup
> with the counter instead.
> And at the same time the TEST_RUNTIME appears to be significantly
> smaller than the actual runtime.
> The upper bound for the runtime is a sum of all possible iterations,
> if we simplify it a bit it would be roughly ((RUNTIME+SLEEPTIME) *
> (SLEEPTIME/2))
> As we are doing SLEEPTIME iterations with SLEEPTIME and RUNTIME
> getting smaller in each of them so it will average out to SLEEPTIME/2
> iterations with full (RUNTIME+SLEEPTIME)
> So I guess that we need:
> #define TEST_RUNTIME ((RUNTIME+SLEEPTIME) * (SLEEPTIME/2))
And other thing which is on my machine broken is to run with more iterations, it
randomly fails or get stuck after first iteration:
./thermal_interrupt_events -i3
thermal_interrupt_events.c:207: TINFO: CPU 23 interrupt counter: 23 (previous: 21)
thermal_interrupt_events.c:217: TPASS: x86 package thermal interrupt triggered
thermal_interrupt_events.c:142: TINFO: Testing /sys/class/thermal/thermal_zone9/temp
thermal_interrupt_events.c:213: TFAIL: No thermal interrupt increase detected
Kind regards,
Petr
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [LTP] [PATCH v19] thermal: add new test group
2026-05-13 10:54 ` Petr Vorel
@ 2026-05-13 12:06 ` Cyril Hrubis
0 siblings, 0 replies; 7+ messages in thread
From: Cyril Hrubis @ 2026-05-13 12:06 UTC (permalink / raw)
To: Petr Vorel
Cc: helena.anna.dubel, tomasz.ossowski, rafael.j.wysocki,
daniel.niestepski, ltp
Hi!
> And other thing which is on my machine broken is to run with more iterations, it
> randomly fails or get stuck after first iteration:
>
> ./thermal_interrupt_events -i3
> thermal_interrupt_events.c:207: TINFO: CPU 23 interrupt counter: 23 (previous: 21)
> thermal_interrupt_events.c:217: TPASS: x86 package thermal interrupt triggered
> thermal_interrupt_events.c:142: TINFO: Testing /sys/class/thermal/thermal_zone9/temp
> thermal_interrupt_events.c:213: TFAIL: No thermal interrupt increase detected
That may as well be because the CPU heatsink accumulated too much heat
and cannot increase it further. Interacting with the physical world
outside is a bit tricky. The test may need a cooldown period
(e.g. sleep(300)) at the end of the test iteration.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-05-13 12:06 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-06 11:24 [LTP] [PATCH v19] thermal: add new test group Piotr Kubaj
2026-05-06 14:16 ` [LTP] " linuxtestproject.agent
2026-05-06 14:23 ` Andrea Cervesato via ltp
2026-05-11 7:51 ` [LTP] [PATCH v19] " Petr Vorel
2026-05-12 9:56 ` Cyril Hrubis
2026-05-13 10:54 ` Petr Vorel
2026-05-13 12:06 ` Cyril Hrubis
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.