From nobody Tue Dec 16 20:00:34 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E605B1944E for ; Mon, 15 Jan 2024 14:38:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="2DRMDITF"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="/JAX5835" From: Anna-Maria Behnsen DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1705329494; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Cm9ubgE2S8LXnJlXOk04it5H/fBOtaMthr0f/KhtUW4=; b=2DRMDITF5UybmTlVWk6gbbm2t4vIeSkHOcUurkwV7YpktOGCzTlCCh3ZAah2BOvxVTUt35 s28u+l2Nrdf6OH/dTiqHMdDtApojeHNR8tEdP4EEjc9WmAj0c1nRb37CoJvBmAR9+QZPCQ AJKy7Y2RUQA3Wjg+wCxwDOXlCbsGsrBrLTlcQKkVZk8G55+a4YZWnSuYCE298sEJ7xguEY KtQ6k3Bc/bpXxzQcqx/zM6a/72kN+plAJb4LwA54rg983xVVT3YFlA4NpxUzI9clEKLmiO 75jmtz7pr9fX3V4CW/P5tS2eloK8OybLJCefsfsAOJ+zITWAlZGHX9MpbnQ5Xw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1705329494; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Cm9ubgE2S8LXnJlXOk04it5H/fBOtaMthr0f/KhtUW4=; b=/JAX58356Wn3eGipK9Y6eLDwDlXr1PO6NkOuv8E/VD2z6yhBY067mF9p0EwSdbiStsl2A5 p0stlNxo5CzdW+Cg== To: linux-kernel@vger.kernel.org Cc: Peter Zijlstra , John Stultz , Thomas Gleixner , Eric Dumazet , "Rafael J . Wysocki" , Arjan van de Ven , "Paul E . McKenney" , Frederic Weisbecker , Rik van Riel , Steven Rostedt , Sebastian Siewior , Giovanni Gherdovich , Lukasz Luba , "Gautham R . Shenoy" , Srinivas Pandruvada , K Prateek Nayak , Anna-Maria Behnsen Subject: [PATCH v10 19/20] timer_migration: Add tracepoints Date: Mon, 15 Jan 2024 15:37:42 +0100 Message-Id: <20240115143743.27827-20-anna-maria@linutronix.de> In-Reply-To: <20240115143743.27827-1-anna-maria@linutronix.de> References: <20240115143743.27827-1-anna-maria@linutronix.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The timer pull logic needs proper debugging aids. Add tracepoints so the hierarchical idle machinery can be diagnosed. Signed-off-by: Anna-Maria Behnsen --- v10: Make an entry in MAINTAINERS file v9: Add tmigr_cpu_new_timer_idle tracepoint v8: Add wakeup value to tracepoints --- --- MAINTAINERS | 1 + include/trace/events/timer_migration.h | 297 +++++++++++++++++++++++++ kernel/time/timer_migration.c | 26 +++ 3 files changed, 324 insertions(+) create mode 100644 include/trace/events/timer_migration.h diff --git a/MAINTAINERS b/MAINTAINERS index a7c4cf8201e0..9f9f2a695082 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17244,6 +17244,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/gi= t/tip/tip.git timers/core F: fs/timerfd.c F: include/linux/time_namespace.h F: include/linux/timer* +F: include/trace/events/timer* F: kernel/time/*timer* F: kernel/time/namespace.c =20 diff --git a/include/trace/events/timer_migration.h b/include/trace/events/= timer_migration.h new file mode 100644 index 000000000000..a2e7e32058f8 --- /dev/null +++ b/include/trace/events/timer_migration.h @@ -0,0 +1,297 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM timer_migration + +#if !defined(_TRACE_TIMER_MIGRATION_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_TIMER_MIGRATION_H + +#include + +/* Group events */ +TRACE_EVENT(tmigr_group_set, + + TP_PROTO(struct tmigr_group *group), + + TP_ARGS(group), + + TP_STRUCT__entry( + __field( void *, group ) + __field( unsigned int, lvl ) + __field( unsigned int, numa_node ) + ), + + TP_fast_assign( + __entry->group =3D group; + __entry->lvl =3D group->level; + __entry->numa_node =3D group->numa_node; + ), + + TP_printk("group=3D%p lvl=3D%d numa=3D%d", + __entry->group, __entry->lvl, __entry->numa_node) +); + +TRACE_EVENT(tmigr_connect_child_parent, + + TP_PROTO(struct tmigr_group *child), + + TP_ARGS(child), + + TP_STRUCT__entry( + __field( void *, child ) + __field( void *, parent ) + __field( unsigned int, lvl ) + __field( unsigned int, numa_node ) + __field( unsigned int, num_children ) + __field( u32, childmask ) + ), + + TP_fast_assign( + __entry->child =3D child; + __entry->parent =3D child->parent; + __entry->lvl =3D child->parent->level; + __entry->numa_node =3D child->parent->numa_node; + __entry->numa_node =3D child->parent->num_children; + __entry->childmask =3D child->childmask; + ), + + TP_printk("group=3D%p childmask=3D%0x parent=3D%p lvl=3D%d numa=3D%d num_= children=3D%d", + __entry->child, __entry->childmask, __entry->parent, + __entry->lvl, __entry->numa_node, __entry->num_children) +); + +TRACE_EVENT(tmigr_connect_cpu_parent, + + TP_PROTO(struct tmigr_cpu *tmc), + + TP_ARGS(tmc), + + TP_STRUCT__entry( + __field( void *, parent ) + __field( unsigned int, cpu ) + __field( unsigned int, lvl ) + __field( unsigned int, numa_node ) + __field( unsigned int, num_children ) + __field( u32, childmask ) + ), + + TP_fast_assign( + __entry->parent =3D tmc->tmgroup; + __entry->cpu =3D tmc->cpuevt.cpu; + __entry->lvl =3D tmc->tmgroup->level; + __entry->numa_node =3D tmc->tmgroup->numa_node; + __entry->numa_node =3D tmc->tmgroup->num_children; + __entry->childmask =3D tmc->childmask; + ), + + TP_printk("cpu=3D%d childmask=3D%0x parent=3D%p lvl=3D%d numa=3D%d num_ch= ildren=3D%d", + __entry->cpu, __entry->childmask, __entry->parent, + __entry->lvl, __entry->numa_node, __entry->num_children) +); + +DECLARE_EVENT_CLASS(tmigr_group_and_cpu, + + TP_PROTO(struct tmigr_group *group, union tmigr_state state, u32 childmas= k), + + TP_ARGS(group, state, childmask), + + TP_STRUCT__entry( + __field( void *, group ) + __field( void *, parent ) + __field( unsigned int, lvl ) + __field( unsigned int, numa_node ) + __field( u8, active ) + __field( u8, migrator ) + __field( u32, childmask ) + ), + + TP_fast_assign( + __entry->group =3D group; + __entry->parent =3D group->parent; + __entry->lvl =3D group->level; + __entry->numa_node =3D group->numa_node; + __entry->active =3D state.active; + __entry->migrator =3D state.migrator; + __entry->childmask =3D childmask; + ), + + TP_printk("group=3D%p lvl=3D%d numa=3D%d active=3D%0x migrator=3D%0x " + "parent=3D%p childmask=3D%0x", + __entry->group, __entry->lvl, __entry->numa_node, + __entry->active, __entry->migrator, + __entry->parent, __entry->childmask) +); + +DEFINE_EVENT(tmigr_group_and_cpu, tmigr_group_set_cpu_inactive, + + TP_PROTO(struct tmigr_group *group, union tmigr_state state, u32 childmas= k), + + TP_ARGS(group, state, childmask) +); + +DEFINE_EVENT(tmigr_group_and_cpu, tmigr_group_set_cpu_active, + + TP_PROTO(struct tmigr_group *group, union tmigr_state state, u32 childmas= k), + + TP_ARGS(group, state, childmask) +); + +/* CPU events*/ +DECLARE_EVENT_CLASS(tmigr_cpugroup, + + TP_PROTO(struct tmigr_cpu *tmc), + + TP_ARGS(tmc), + + TP_STRUCT__entry( + __field( void *, parent) + __field( unsigned int, cpu) + __field( u64, wakeup) + ), + + TP_fast_assign( + __entry->cpu =3D tmc->cpuevt.cpu; + __entry->parent =3D tmc->tmgroup; + __entry->wakeup =3D tmc->wakeup; + ), + + TP_printk("cpu=3D%d parent=3D%p wakeup=3D%llu", __entry->cpu, __entry->pa= rent, __entry->wakeup) +); + +DEFINE_EVENT(tmigr_cpugroup, tmigr_cpu_new_timer, + + TP_PROTO(struct tmigr_cpu *tmc), + + TP_ARGS(tmc) +); + +DEFINE_EVENT(tmigr_cpugroup, tmigr_cpu_active, + + TP_PROTO(struct tmigr_cpu *tmc), + + TP_ARGS(tmc) +); + +DEFINE_EVENT(tmigr_cpugroup, tmigr_cpu_online, + + TP_PROTO(struct tmigr_cpu *tmc), + + TP_ARGS(tmc) +); + +DEFINE_EVENT(tmigr_cpugroup, tmigr_cpu_offline, + + TP_PROTO(struct tmigr_cpu *tmc), + + TP_ARGS(tmc) +); + +DEFINE_EVENT(tmigr_cpugroup, tmigr_handle_remote_cpu, + + TP_PROTO(struct tmigr_cpu *tmc), + + TP_ARGS(tmc) +); + +DECLARE_EVENT_CLASS(tmigr_idle, + + TP_PROTO(struct tmigr_cpu *tmc, u64 nextevt), + + TP_ARGS(tmc, nextevt), + + TP_STRUCT__entry( + __field( void *, parent) + __field( unsigned int, cpu) + __field( u64, nextevt) + __field( u64, wakeup) + ), + + TP_fast_assign( + __entry->cpu =3D tmc->cpuevt.cpu; + __entry->parent =3D tmc->tmgroup; + __entry->nextevt =3D nextevt; + __entry->wakeup =3D tmc->wakeup; + ), + + TP_printk("cpu=3D%d parent=3D%p nextevt=3D%llu wakeup=3D%llu", + __entry->cpu, __entry->parent, __entry->nextevt, __entry->wakeup) +); + +DEFINE_EVENT(tmigr_idle, tmigr_cpu_idle, + + TP_PROTO(struct tmigr_cpu *tmc, u64 nextevt), + + TP_ARGS(tmc, nextevt) +); + +DEFINE_EVENT(tmigr_idle, tmigr_cpu_new_timer_idle, + + TP_PROTO(struct tmigr_cpu *tmc, u64 nextevt), + + TP_ARGS(tmc, nextevt) +); + +TRACE_EVENT(tmigr_update_events, + + TP_PROTO(struct tmigr_group *child, struct tmigr_group *group, + union tmigr_state childstate, union tmigr_state groupstate, + u64 nextevt), + + TP_ARGS(child, group, childstate, groupstate, nextevt), + + TP_STRUCT__entry( + __field( void *, child ) + __field( void *, group ) + __field( u64, nextevt ) + __field( u64, group_next_expiry ) + __field( unsigned int, group_lvl ) + __field( u8, child_active ) + __field( u8, group_active ) + __field( unsigned int, child_evtcpu ) + __field( u64, child_evt_expiry ) + ), + + TP_fast_assign( + __entry->child =3D child; + __entry->group =3D group; + __entry->nextevt =3D nextevt; + __entry->group_next_expiry =3D group->next_expiry; + __entry->group_lvl =3D group->level; + __entry->child_active =3D childstate.active; + __entry->group_active =3D groupstate.active; + __entry->child_evtcpu =3D child ? child->groupevt.cpu : 0; + __entry->child_evt_expiry =3D child ? child->groupevt.nextevt.expires : = 0; + ), + + TP_printk("child=3D%p group=3D%p group_lvl=3D%d child_active=3D%0x group_= active=3D%0x " + "nextevt=3D%llu next_expiry=3D%llu child_evt_expiry=3D%llu child_evtcp= u=3D%d", + __entry->child, __entry->group, __entry->group_lvl, __entry->child_act= ive, + __entry->group_active, + __entry->nextevt, __entry->group_next_expiry, __entry->child_evt_expir= y, + __entry->child_evtcpu) +); + +TRACE_EVENT(tmigr_handle_remote, + + TP_PROTO(struct tmigr_group *group), + + TP_ARGS(group), + + TP_STRUCT__entry( + __field( void * , group ) + __field( unsigned int , lvl ) + ), + + TP_fast_assign( + __entry->group =3D group; + __entry->lvl =3D group->level; + ), + + TP_printk("group=3D%p lvl=3D%d", + __entry->group, __entry->lvl) +); + +#endif /* _TRACE_TIMER_MIGRATION_H */ + +/* This part must be outside protection */ +#include diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c index de1905b0bae7..d3b7200a9f4a 100644 --- a/kernel/time/timer_migration.c +++ b/kernel/time/timer_migration.c @@ -14,6 +14,9 @@ #include "timer_migration.h" #include "tick-internal.h" =20 +#define CREATE_TRACE_POINTS +#include + /* * The timer migration mechanism is built on a hierarchy of groups. The * lowest level group contains CPUs, the next level groups of CPU groups @@ -537,6 +540,8 @@ static bool tmigr_active_up(struct tmigr_group *group, */ group->groupevt.ignore =3D true; =20 + trace_tmigr_group_set_cpu_active(group, newstate, childmask); + return walk_done; } =20 @@ -546,6 +551,8 @@ static void __tmigr_cpu_activate(struct tmigr_cpu *tmc) =20 data.childmask =3D tmc->childmask; =20 + trace_tmigr_cpu_active(tmc); + tmc->cpuevt.ignore =3D true; WRITE_ONCE(tmc->wakeup, KTIME_MAX); tmc->wakeup_recalc =3D false; @@ -703,6 +710,9 @@ bool tmigr_update_events(struct tmigr_group *group, str= uct tmigr_group *child, data->firstexp =3D tmigr_next_groupevt_expires(group); } =20 + trace_tmigr_update_events(child, group, childstate, groupstate, + nextexp); + unlock: raw_spin_unlock(&group->lock); =20 @@ -745,6 +755,8 @@ static u64 tmigr_new_timer(struct tmigr_cpu *tmc, u64 n= extexp) if (tmc->remote) return KTIME_MAX; =20 + trace_tmigr_cpu_new_timer(tmc); + tmc->cpuevt.ignore =3D false; data.remote =3D false; =20 @@ -787,6 +799,8 @@ static u64 tmigr_handle_remote_cpu(unsigned int cpu, u6= 4 now, return next; } =20 + trace_tmigr_handle_remote_cpu(tmc); + tmc->remote =3D true; WRITE_ONCE(tmc->wakeup, KTIME_MAX); =20 @@ -872,6 +886,7 @@ static bool tmigr_handle_remote_up(struct tmigr_group *= group, =20 childmask =3D data->childmask; =20 + trace_tmigr_handle_remote(group); again: /* * Handle the group only if @childmask is the migrator or if the @@ -1140,6 +1155,7 @@ u64 tmigr_cpu_new_timer(u64 nextexp) */ WRITE_ONCE(tmc->wakeup, ret); =20 + trace_tmigr_cpu_new_timer_idle(tmc, nextexp); raw_spin_unlock(&tmc->lock); return ret; } @@ -1243,6 +1259,8 @@ static bool tmigr_inactive_up(struct tmigr_group *gro= up, } } =20 + trace_tmigr_group_set_cpu_inactive(group, newstate, childmask); + return walk_done; } =20 @@ -1295,6 +1313,7 @@ u64 tmigr_cpu_deactivate(u64 nextexp) */ WRITE_ONCE(tmc->wakeup, ret); =20 + trace_tmigr_cpu_idle(tmc, nextexp); raw_spin_unlock(&tmc->lock); return ret; } @@ -1407,6 +1426,7 @@ static struct tmigr_group *tmigr_get_group(unsigned i= nt cpu, int node, =20 /* Setup successful. Add it to the hierarchy */ list_add(&group->list, &tmigr_level_list[lvl]); + trace_tmigr_group_set(group); return group; } =20 @@ -1424,6 +1444,8 @@ static void tmigr_connect_child_parent(struct tmigr_g= roup *child, raw_spin_unlock(&parent->lock); raw_spin_unlock_irq(&child->lock); =20 + trace_tmigr_connect_child_parent(child); + /* * To prevent inconsistent states, active children need to be active in * the new parent as well. Inactive children are already marked inactive @@ -1504,6 +1526,8 @@ static int tmigr_setup_groups(unsigned int cpu, unsig= ned int node) =20 raw_spin_unlock_irq(&group->lock); =20 + trace_tmigr_connect_cpu_parent(tmc); + /* There are no children that need to be connected */ continue; } else { @@ -1571,6 +1595,7 @@ static int tmigr_cpu_online(unsigned int cpu) WRITE_ONCE(tmc->wakeup, KTIME_MAX); } raw_spin_lock_irq(&tmc->lock); + trace_tmigr_cpu_online(tmc); tmc->idle =3D timer_base_is_idle(); if (!tmc->idle) __tmigr_cpu_activate(tmc); @@ -1592,6 +1617,7 @@ static int tmigr_cpu_offline(unsigned int cpu) * offline; Therefore nextevt value is set to KTIME_MAX */ __tmigr_cpu_deactivate(tmc, KTIME_MAX); + trace_tmigr_cpu_offline(tmc); raw_spin_unlock_irq(&tmc->lock); =20 return 0; --=20 2.39.2