From: Tobias Schaffner <tobias.schaffner@siemens.com>
To: Steven Rostedt <rostedt@goodmis.org>,
Gabriele Monaco <gmonaco@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Masami Hiramatsu <mhiramat@kernel.org>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org,
rpm@xenomai.org, jan.kiszka@siemens.com,
Tobias Schaffner <tobias.schaffner@siemens.com>
Subject: [PATCH v2 3/3] rv: collect per-edge dwell time for per-cpu DA/HA monitors
Date: Fri, 11 Sep 2026 14:34:38 +0200 [thread overview]
Message-ID: <20260911123439.463052-4-tobias.schaffner@siemens.com> (raw)
In-Reply-To: <20260911123439.463052-1-tobias.schaffner@siemens.com>
With the core facility in place, hook it into the DA/HA layer so that any
per-CPU automaton monitor also reports how long it lingers in each state.
Pack the automaton state and its entry timestamp into one word so the
transition cmpxchg updates both atomically. This prevents nested events
from attributing dwell time to the wrong edge and requires a native
64-bit cmpxchg.
Account a transition as soon as its state change is committed. An HA
constraint that rejects the transition can therefore reset the monitor
without leaving an accounting window for nested events.
Add a selftest that enables a per-CPU monitor, checks the stats file
appears and is populated under load, and skips cleanly otherwise.
Signed-off-by: Tobias Schaffner <tobias.schaffner@siemens.com>
---
include/linux/rv.h | 9 ++++-
include/rv/da_monitor.h | 16 +++++++--
include/rv/ha_monitor.h | 2 +-
tools/testing/selftests/verification/config | 3 ++
.../verification/test.d/rv_edge_stats.tc | 33 +++++++++++++++++++
5 files changed, 58 insertions(+), 5 deletions(-)
create mode 100644 tools/testing/selftests/verification/test.d/rv_edge_stats.tc
diff --git a/include/linux/rv.h b/include/linux/rv.h
index 541ba404926a..6c5c2fa7dd68 100644
--- a/include/linux/rv.h
+++ b/include/linux/rv.h
@@ -21,12 +21,19 @@
#include <linux/list.h>
#include <linux/types.h>
+/* Edge statistics pack the state and its entry timestamp into one word. */
+#ifdef CONFIG_RV_EDGE_STAT
+#define da_state_t unsigned long
+#else
+#define da_state_t unsigned int
+#endif
+
/*
* Deterministic automaton per-object variables.
*/
struct da_monitor {
bool monitoring;
- unsigned int curr_state;
+ da_state_t curr_state;
};
#ifdef CONFIG_RV_LTL_MONITOR
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index 34b8fba9ecd4..bd7bd422b39a 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -16,6 +16,7 @@
#include <rv/automata.h>
#include <linux/rv.h>
+#include <rv/edge_stat.h>
#include <linux/stringify.h>
#include <linux/bug.h>
#include <linux/sched.h>
@@ -112,7 +113,7 @@ static inline void da_monitor_reset(struct da_monitor *da_mon)
*/
static inline void da_monitor_start(struct da_monitor *da_mon)
{
- da_mon->curr_state = model_get_initial_state();
+ da_mon->curr_state = da_state_entered(model_get_initial_state());
da_monitor_init_hook(da_mon);
/* Pairs with smp_load_acquire in da_monitoring(). */
smp_store_release(&da_mon->monitoring, 1);
@@ -275,6 +276,11 @@ static inline void da_monitor_reset_state_all(void)
*/
static inline int da_monitor_init(void)
{
+ int retval = rv_edge_stats_create(rv_this.root_d);
+
+ if (retval)
+ return retval;
+
da_monitor_reset_state_all();
return 0;
}
@@ -286,6 +292,7 @@ static inline void da_monitor_destroy(void)
{
da_monitor_reset_all();
da_monitor_sync_hook();
+ rv_edge_stats_remove();
}
#ifndef da_implicit_guard
@@ -683,9 +690,11 @@ static inline void da_trace_error(struct da_monitor *da_mon,
static inline bool da_event(struct da_monitor *da_mon, enum events event, da_id_type id)
{
enum states curr_state, next_state;
+ da_state_t old;
- curr_state = READ_ONCE(da_mon->curr_state);
+ old = READ_ONCE(da_mon->curr_state);
for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) {
+ curr_state = da_state_of(old);
next_state = model_get_next_state(curr_state, event);
if (next_state == INVALID_STATE) {
react(curr_state, event);
@@ -693,7 +702,8 @@ static inline bool da_event(struct da_monitor *da_mon, enum events event, da_id_
model_get_event_name(event), id);
return false;
}
- if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) {
+ if (likely(da_state_try_commit(&da_mon->curr_state, &old,
+ next_state, event))) {
if (!da_monitor_event_hook(da_mon, curr_state, event, next_state, id))
return false;
da_trace_event(da_mon, model_get_state_name(curr_state),
diff --git a/include/rv/ha_monitor.h b/include/rv/ha_monitor.h
index 28d3c74cabfc..4def2aac92de 100644
--- a/include/rv/ha_monitor.h
+++ b/include/rv/ha_monitor.h
@@ -312,7 +312,7 @@ static inline void __ha_monitor_timer_callback(struct ha_monitor *ha_mon)
if (unlikely(READ_ONCE(ha_mon_destroying)))
return;
/* Ensure consistent curr_state if we race with da_monitor_reset */
- curr_state = smp_load_acquire(&ha_mon->da_mon.curr_state);
+ curr_state = da_state_of(smp_load_acquire(&ha_mon->da_mon.curr_state));
if (unlikely(!da_monitor_handling_event(&ha_mon->da_mon)))
return;
diff --git a/tools/testing/selftests/verification/config b/tools/testing/selftests/verification/config
index 43072c1c38f4..caf3a96ac8b4 100644
--- a/tools/testing/selftests/verification/config
+++ b/tools/testing/selftests/verification/config
@@ -1 +1,4 @@
CONFIG_RV=y
+CONFIG_PREEMPT_TRACER=y
+CONFIG_RV_MON_WIP=y
+CONFIG_RV_EDGE_STAT=y
diff --git a/tools/testing/selftests/verification/test.d/rv_edge_stats.tc b/tools/testing/selftests/verification/test.d/rv_edge_stats.tc
new file mode 100644
index 000000000000..616bb0b5166e
--- /dev/null
+++ b/tools/testing/selftests/verification/test.d/rv_edge_stats.tc
@@ -0,0 +1,33 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+# description: Test per-edge dwell-time statistics (stats)
+
+MON=wip
+
+check_requires "$MON:monitor"
+
+# The "stats" file is created on enable; if it is still missing the kernel was
+# built without CONFIG_RV_EDGE_STAT, so skip.
+echo 1 > "monitors/$MON/enable"
+if [ ! -e "monitors/$MON/stats" ]; then
+ echo 0 > "monitors/$MON/enable"
+ echo "CONFIG_RV_EDGE_STAT is not enabled."
+ exit_unsupported
+fi
+
+# The first line is the column header; the body has one line per (cpu, edge).
+head -n1 "monitors/$MON/stats" | grep -q "^# cpu edge label count sum_ns max_ns"
+[ "$(grep -cvE '^#' "monitors/$MON/stats")" -gt 0 ]
+
+# Drive some scheduler activity so the automaton records transitions.
+for _ in 1 2 3 4 5 6 7 8 9 10; do
+ (true) &
+ wait
+done
+
+# At least one edge must now show a non-zero count. Do not require a non-zero
+# dwell: a coarse local_clock() may legitimately return the same value twice.
+grep -vE '^#' "monitors/$MON/stats" | \
+ awk '$4 > 0 && $5 >= $6 { hit = 1 } END { exit !hit }'
+
+echo 0 > "monitors/$MON/enable"
--
2.43.0
next prev parent reply other threads:[~2026-09-11 12:35 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-11 12:34 [PATCH v2 0/3] rv: per-edge dwell-time statistics for per-cpu monitors Tobias Schaffner
2026-09-11 12:34 ` [PATCH v2 1/3] rv: add per-edge dwell-time statistics primitive Tobias Schaffner
2026-09-24 7:21 ` Gabriele Monaco
2026-09-11 12:34 ` [PATCH v2 2/3] rv: add per-monitor edge-stat facility and stats file Tobias Schaffner
2026-09-24 7:47 ` Gabriele Monaco
2026-09-11 12:34 ` Tobias Schaffner [this message]
2026-09-24 7:18 ` [PATCH v2 3/3] rv: collect per-edge dwell time for per-cpu DA/HA monitors Gabriele Monaco
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=20260911123439.463052-4-tobias.schaffner@siemens.com \
--to=tobias.schaffner@siemens.com \
--cc=corbet@lwn.net \
--cc=gmonaco@redhat.com \
--cc=jan.kiszka@siemens.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mhiramat@kernel.org \
--cc=rostedt@goodmis.org \
--cc=rpm@xenomai.org \
--cc=skhan@linuxfoundation.org \
/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