From: Karl Mehltretter <kmehltretter@gmail.com>
To: Steven Rostedt <rostedt@goodmis.org>,
Gabriele Monaco <gmonaco@redhat.com>
Cc: Karl Mehltretter <kmehltretter@gmail.com>,
Masami Hiramatsu <mhiramat@kernel.org>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
Thomas Gleixner <tglx@kernel.org>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
Clark Williams <clrkwllms@kernel.org>,
Ingo Molnar <mingo@redhat.com>,
Peter Zijlstra <peterz@infradead.org>,
Andy Lutomirski <luto@kernel.org>,
Juri Lelli <juri.lelli@redhat.com>,
Vincent Guittot <vincent.guittot@linaro.org>,
Dietmar Eggemann <dietmar.eggemann@arm.com>,
Ben Segall <bsegall@google.com>, Mel Gorman <mgorman@suse.de>,
Valentin Schneider <vschneid@redhat.com>,
K Prateek Nayak <kprateek.nayak@amd.com>,
Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Randy Dunlap <rdunlap@infradead.org>,
linux-trace-kernel@vger.kernel.org,
linux-rt-devel@lists.linux.dev, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [RFC PATCH 1/9] tracing/irq: Add generic IRQ context boundary events
Date: Thu, 22 Oct 2026 07:07:04 +0200 [thread overview]
Message-ID: <20261022050712.75035-2-kmehltretter@gmail.com> (raw)
In-Reply-To: <20261022050712.75035-1-kmehltretter@gmail.com>
IRQ action tracepoints describe handlers, not the enclosing interrupt
context. One hardirq context may run several actions. Synthetic dispatch
may also invoke an action outside hardirq context.
Add events at the generic hardirq and serving-softirq boundaries. Record
the hardirq depth and whether serving-softirq state temporarily replaces
hardirq state during interrupt return.
A callback attached to a boundary event can raise softirq work after the
normal pending-work check. Include work raised by the softirq-entry
callback in the initial pending snapshot. Wake ksoftirqd or ktimerd for
work raised by a final boundary callback.
The events cover paths through irq_enter()/irq_exit() or
irq_enter_rcu()/irq_exit_rcu(). Direct __irq_enter()/__irq_exit() users
and raw paths remain outside their scope.
Assisted-by: LLM
---
include/trace/events/irq.h | 70 ++++++++++++++++++++++++++++++++
kernel/softirq.c | 83 +++++++++++++++++++++++++++++++++++++-
2 files changed, 151 insertions(+), 2 deletions(-)
diff --git a/include/trace/events/irq.h b/include/trace/events/irq.h
index 837c1740d0d07..0549fbcdbb1b6 100644
--- a/include/trace/events/irq.h
+++ b/include/trace/events/irq.h
@@ -39,6 +39,76 @@ SOFTIRQ_NAME_LIST
#define show_softirq_name(val) \
__print_symbolic(val, SOFTIRQ_NAME_LIST)
+DECLARE_EVENT_CLASS(hardirq_context,
+ TP_PROTO(unsigned int depth),
+ TP_ARGS(depth),
+ TP_STRUCT__entry(__field(unsigned int, depth)),
+ TP_fast_assign(__entry->depth = depth;),
+ TP_printk("depth=%u", __entry->depth));
+
+/**
+ * hardirq_context_entry - generic hardirq state has been established
+ * @depth: hardirq nesting depth, including the context being entered
+ *
+ * This event is emitted after generic hardirq preempt-count, lockdep, timer,
+ * and accounting state has been established. It does not describe the
+ * architecture-specific interval before irq_enter() or irq_enter_rcu().
+ */
+DEFINE_EVENT(hardirq_context, hardirq_context_entry,
+ TP_PROTO(unsigned int depth),
+ TP_ARGS(depth));
+
+/**
+ * hardirq_context_exit - generic hardirq state is about to be removed
+ * @depth: hardirq nesting depth, including the context being exited
+ *
+ * This event is emitted with interrupts disabled immediately before generic
+ * hardirq preempt-count state is removed. Hardirq accounting ends earlier.
+ */
+DEFINE_EVENT(hardirq_context, hardirq_context_exit,
+ TP_PROTO(unsigned int depth),
+ TP_ARGS(depth));
+
+DECLARE_EVENT_CLASS(softirq_context,
+ TP_PROTO(bool serving, bool from_hardirq),
+ TP_ARGS(serving, from_hardirq),
+ TP_STRUCT__entry(
+ __field(bool, serving)
+ __field(bool, from_hardirq)
+ ),
+ TP_fast_assign(
+ __entry->serving = serving;
+ __entry->from_hardirq = from_hardirq;
+ ),
+ TP_printk("serving=%d from_hardirq=%d",
+ __entry->serving, __entry->from_hardirq));
+
+/**
+ * softirq_context_entry - serving-softirq state has been established
+ * @serving: whether the current task is serving a softirq
+ * @from_hardirq: whether hardirq state was replaced by serving-softirq state
+ *
+ * This event runs with local interrupts disabled after the serving bit is
+ * set. On PREEMPT_RT it includes preparation before handle_softirqs(), even
+ * if the pending-work check finds nothing. It does not mark an individual
+ * action or the start of CPU-time accounting.
+ */
+DEFINE_EVENT(softirq_context, softirq_context_entry,
+ TP_PROTO(bool serving, bool from_hardirq),
+ TP_ARGS(serving, from_hardirq));
+
+/**
+ * softirq_context_exit - serving-softirq state is about to be removed
+ * @serving: whether the current task is serving a softirq
+ * @from_hardirq: whether hardirq state will replace serving-softirq state
+ *
+ * This event runs with local interrupts disabled before the serving bit is
+ * cleared. On PREEMPT_RT this includes teardown after handle_softirqs().
+ */
+DEFINE_EVENT(softirq_context, softirq_context_exit,
+ TP_PROTO(bool serving, bool from_hardirq),
+ TP_ARGS(serving, from_hardirq));
+
/**
* irq_handler_entry - called immediately before the irq action handler
* @irq: irq number
diff --git a/kernel/softirq.c b/kernel/softirq.c
index be49e6469f3ad..2e3b6fd3f6d5d 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -178,7 +178,9 @@ bool local_bh_blocked(void)
void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
{
+ unsigned long trace_flags = 0;
unsigned long flags;
+ bool trace_serving;
int newcnt;
WARN_ON_ONCE(in_hardirq());
@@ -200,6 +202,16 @@ void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
}
}
+ /*
+ * A serving interval starts here, before handle_softirqs(). When its
+ * entry is traced, keep IRQs and task switches from observing the bit
+ * before the event. Any blocking BH lock was acquired above.
+ */
+ trace_serving = (cnt & SOFTIRQ_OFFSET) &&
+ trace_softirq_context_entry_enabled();
+ if (trace_serving)
+ local_irq_save(trace_flags);
+
/*
* Track the per CPU softirq disabled state. On RT this is per CPU
* state to allow preemption of bottom half disabled sections.
@@ -233,15 +245,27 @@ void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
raw_local_irq_restore(flags);
}
}
+
+ if (trace_serving) {
+ trace_softirq_context_entry(!!in_serving_softirq(), false);
+ local_irq_restore(trace_flags);
+ }
}
EXPORT_SYMBOL(__local_bh_disable_ip);
static void __local_bh_enable(unsigned int cnt, bool unlock)
{
+ bool entering = (cnt & SOFTIRQ_OFFSET) && !in_serving_softirq();
+ bool trace_exiting = (cnt & SOFTIRQ_OFFSET) && !entering &&
+ trace_softirq_context_exit_enabled();
unsigned long flags;
bool sirq_en = false;
int newcnt;
+ /* Callers already disabled IRQs around the counter and its events. */
+ if (trace_exiting)
+ trace_softirq_context_exit(!!in_serving_softirq(), false);
+
if (IS_ENABLED(CONFIG_PREEMPT_RT_NEEDS_BH_LOCK)) {
DEBUG_LOCKS_WARN_ON(current->softirq_disable_cnt !=
this_cpu_read(softirq_ctrl.cnt));
@@ -276,6 +300,18 @@ static void __local_bh_enable(unsigned int cnt, bool unlock)
WARN_ON_ONCE(current->softirq_disable_cnt < 0);
}
}
+
+ /*
+ * An exit probe can raise a softirq while serving state still suppresses
+ * the normal ksoftirqd wakeup. Hand it off once no outer BH-disable
+ * reference remains.
+ */
+ if (trace_exiting && sirq_en && unlikely(local_softirq_pending()))
+ wakeup_softirqd();
+
+ /* local_bh_enable() can turn BH-disabled state into serving state. */
+ if (entering)
+ trace_softirq_context_entry(!!in_serving_softirq(), false);
}
void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
@@ -640,11 +676,15 @@ static void handle_softirqs(bool ksirqd)
*/
current->flags &= ~PF_MEMALLOC;
- pending = local_softirq_pending();
-
from_irq_exit = softirq_handle_begin();
in_hardirq = lockdep_softirq_start();
account_softirq_enter(current);
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
+ trace_softirq_context_entry(!!in_serving_softirq(),
+ from_irq_exit);
+
+ /* Include work raised by the context-entry event. */
+ pending = local_softirq_pending();
restart:
/* Reset the pending bitmask before enabling irqs */
@@ -692,6 +732,14 @@ restart:
wakeup_softirqd();
}
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT) &&
+ trace_softirq_context_exit_enabled()) {
+ trace_softirq_context_exit(!!in_serving_softirq(),
+ from_irq_exit);
+ /* The final pending-work decision above has already completed. */
+ if (unlikely(local_softirq_pending()))
+ wakeup_softirqd();
+ }
account_softirq_exit(current);
lockdep_softirq_end(in_hardirq);
softirq_handle_end(from_irq_exit);
@@ -722,6 +770,7 @@ void irq_enter_rcu(void)
tick_irq_enter();
account_hardirq_enter(current);
+ trace_hardirq_context_entry(hardirq_count() >> HARDIRQ_SHIFT);
}
/**
@@ -796,6 +845,36 @@ static inline void __irq_exit_rcu(void)
wake_timersd();
tick_irq_exit();
+ if (trace_hardirq_context_exit_enabled()) {
+ bool ksoftirqd_wake_requested = false;
+ bool timersd_wake_requested = false;
+
+ trace_hardirq_context_exit(hardirq_count() >> HARDIRQ_SHIFT);
+
+ /* Hand work raised by the final boundary event to its worker. */
+ if (hardirq_count() == HARDIRQ_OFFSET) {
+ if (irq_count() == HARDIRQ_OFFSET &&
+ unlikely(local_softirq_pending()) &&
+ should_wake_ksoftirqd()) {
+ wakeup_softirqd();
+ ksoftirqd_wake_requested = true;
+ }
+
+ if (IS_ENABLED(CONFIG_IRQ_FORCED_THREADING) &&
+ force_irqthreads() && local_timers_pending_force_th()) {
+ wake_timersd();
+ timersd_wake_requested = true;
+ }
+
+ /* The timersd wakeup can itself raise a softirq. */
+ if (timersd_wake_requested &&
+ !ksoftirqd_wake_requested &&
+ irq_count() == HARDIRQ_OFFSET &&
+ unlikely(local_softirq_pending()) &&
+ should_wake_ksoftirqd())
+ wakeup_softirqd();
+ }
+ }
preempt_count_sub(HARDIRQ_OFFSET);
}
--
2.39.5 (Apple Git-154)
next prev parent reply other threads:[~2026-10-22 5:07 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-22 5:07 [RFC PATCH 0/9] rv: Verify generic IRQ context transitions Karl Mehltretter
2026-10-22 5:07 ` Karl Mehltretter [this message]
2026-10-22 5:44 ` [RFC PATCH 1/9] tracing/irq: Add generic IRQ context boundary events sashiko-bot
2026-10-22 5:07 ` [RFC PATCH 2/9] tracing/sched: Add IRQ preemption lifecycle events Karl Mehltretter
2026-10-22 5:07 ` [RFC PATCH 3/9] rv: Add a monitor for generic IRQ context transitions Karl Mehltretter
2026-10-22 5:07 ` [RFC PATCH 4/9] rv: Add a monitor for IRQ-exit scheduling ownership Karl Mehltretter
2026-10-22 5:07 ` [RFC PATCH 5/9] docs/rv: Document the IRQ-entry monitors Karl Mehltretter
2026-10-22 5:07 ` [RFC PATCH 6/9] rv: Add KUnit coverage for IRQ context transitions Karl Mehltretter
2026-10-22 5:33 ` sashiko-bot
2026-10-22 5:07 ` [RFC PATCH 7/9] rv: Add KUnit coverage for IRQ-exit scheduling Karl Mehltretter
2026-10-22 5:30 ` sashiko-bot
2026-10-22 5:07 ` [RFC PATCH 8/9] rv: Test empty PREEMPT_RT softirq worker intervals Karl Mehltretter
2026-10-22 5:07 ` [RFC PATCH 9/9] rv: Test IRQ-exit softirq provenance and handoff Karl Mehltretter
2026-10-22 5:33 ` sashiko-bot
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=20261022050712.75035-2-kmehltretter@gmail.com \
--to=kmehltretter@gmail.com \
--cc=bigeasy@linutronix.de \
--cc=bsegall@google.com \
--cc=clrkwllms@kernel.org \
--cc=corbet@lwn.net \
--cc=dietmar.eggemann@arm.com \
--cc=gmonaco@redhat.com \
--cc=juri.lelli@redhat.com \
--cc=kprateek.nayak@amd.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mgorman@suse.de \
--cc=mhiramat@kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=rdunlap@infradead.org \
--cc=rostedt@goodmis.org \
--cc=skhan@linuxfoundation.org \
--cc=tglx@kernel.org \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
/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
all inboxes | Powered by JetHome®