From nobody Tue Jun 16 20:37:15 2026 Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) (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 45792240611; Wed, 29 Apr 2026 06:07:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.97.179.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777442876; cv=none; b=MMh22ygDuNp0XPyL0BhGPYFPvUjqQd06U2/VQi5cMIZ22jlnDMqi3lEwta72Unao4xzYqA5D13Vzai1v4qJC4j9LixsgidvQEAw7r/bQz4PhPSIg0IhVPl8hCLVo3ZJb2dR3RyGYgnUPgobz3wAnfOrezY8h00Ts9o9zqXR3GD4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777442876; c=relaxed/simple; bh=tmev3C0/K61R5hUQP3goa+paRWXMOoFpuhKJgZgtJAg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tHrfej9irKfBRRl+bVdCmFm1yr+uxlryDkF0ee3d3BbOCD5gkGXAk6xo26Zj+YowrknJg79NgksRVX3tsnmun2GCSks8qkY/rw/5i8eijnbNPFhpQ8Sp6mFDycwE1IN+Pksm4HvSmni9YglALuBDh7Vlz15XH0/gnDzbDxyltsQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com; spf=pass smtp.mailfrom=igalia.com; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b=NYVIlGGm; arc=none smtp.client-ip=213.97.179.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=igalia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b="NYVIlGGm" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=xgf1mC19G3kAVlRSFzdVX0/yQON471GsvBrex7BxcXc=; b=NYVIlGGmaP7avJmXRiFiRWkapD Hbc0AqhIlPUE6TMPb6PL3PyYlC2ntBZ7j5k80lRLE5auVgWt6TZGQeuC//fRnjaGOYQHQYpiBNb2P GSCBqsVr4TDF7J4kMnZl9MDjJSj+/HzT8xqJK2yCBUHd0Is3ryHuETkNnTyGMfC18DCctpucFfCeY HsfaQXZP3B9OF11ezRnZ4NezL5fL1fB3gd1P7XgG/MJrdV76lWZT/sMbMeKMLZcM93uxqa/6zU9Xr 386xiB7u5nSvvsnZCOw6dliz9+0SDYsuiyCqGTkEm64anOl3JjZr2n+bz6YzrkOJVmPBhXxg4R3SJ H13RSM1Q==; Received: from [58.29.145.179] (helo=localhost) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1wHy5L-003k59-0u; Wed, 29 Apr 2026 08:07:47 +0200 From: Changwoo Min To: tj@kernel.org, void@manifault.com, arighi@nvidia.com, changwoo@igalia.com Cc: kernel-dev@igalia.com, sched-ext@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/3] sched_ext: Extract scx_dump_cpu() from scx_dump_state() Date: Wed, 29 Apr 2026 15:07:24 +0900 Message-ID: <20260429060726.359024-2-changwoo@igalia.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260429060726.359024-1-changwoo@igalia.com> References: <20260429060726.359024-1-changwoo@igalia.com> 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" Factor out the per-CPU state dump logic from the for_each_possible_cpu loop in scx_dump_state() into a new scx_dump_cpu() helper to improve readability. No functional change. Signed-off-by: Changwoo Min --- kernel/sched/ext.c | 171 +++++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 82 deletions(-) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index f7b1b16e81a5..025bd8c6f429 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -6256,6 +6256,94 @@ static void scx_dump_task(struct scx_sched *sch, str= uct seq_buf *s, struct scx_d } } =20 +static void scx_dump_cpu(struct scx_sched *sch, struct seq_buf *s, + struct scx_dump_ctx *dctx, int cpu, + bool dump_all_tasks) +{ + struct rq *rq =3D cpu_rq(cpu); + struct rq_flags rf; + struct task_struct *p; + struct seq_buf ns; + size_t avail, used; + char *buf; + bool idle; + + rq_lock_irqsave(rq, &rf); + + idle =3D list_empty(&rq->scx.runnable_list) && + rq->curr->sched_class =3D=3D &idle_sched_class; + + if (idle && !SCX_HAS_OP(sch, dump_cpu)) + goto next; + + /* + * We don't yet know whether ops.dump_cpu() will produce output + * and we may want to skip the default CPU dump if it doesn't. + * Use a nested seq_buf to generate the standard dump so that we + * can decide whether to commit later. + */ + avail =3D seq_buf_get_buf(s, &buf); + seq_buf_init(&ns, buf, avail); + + dump_newline(&ns); + dump_line(&ns, "CPU %-4d: nr_run=3D%u flags=3D0x%x cpu_rel=3D%d ops_qseq= =3D%lu ksync=3D%lu", + cpu, rq->scx.nr_running, rq->scx.flags, + rq->scx.cpu_released, rq->scx.ops_qseq, + rq->scx.kick_sync); + dump_line(&ns, " curr=3D%s[%d] class=3D%ps", + rq->curr->comm, rq->curr->pid, + rq->curr->sched_class); + if (!cpumask_empty(rq->scx.cpus_to_kick)) + dump_line(&ns, " cpus_to_kick : %*pb", + cpumask_pr_args(rq->scx.cpus_to_kick)); + if (!cpumask_empty(rq->scx.cpus_to_kick_if_idle)) + dump_line(&ns, " idle_to_kick : %*pb", + cpumask_pr_args(rq->scx.cpus_to_kick_if_idle)); + if (!cpumask_empty(rq->scx.cpus_to_preempt)) + dump_line(&ns, " cpus_to_preempt: %*pb", + cpumask_pr_args(rq->scx.cpus_to_preempt)); + if (!cpumask_empty(rq->scx.cpus_to_wait)) + dump_line(&ns, " cpus_to_wait : %*pb", + cpumask_pr_args(rq->scx.cpus_to_wait)); + if (!cpumask_empty(rq->scx.cpus_to_sync)) + dump_line(&ns, " cpus_to_sync : %*pb", + cpumask_pr_args(rq->scx.cpus_to_sync)); + + used =3D seq_buf_used(&ns); + if (SCX_HAS_OP(sch, dump_cpu)) { + ops_dump_init(&ns, " "); + SCX_CALL_OP(sch, dump_cpu, rq, dctx, cpu, idle); + ops_dump_exit(); + } + + /* + * If idle && nothing generated by ops.dump_cpu(), there's + * nothing interesting. Skip. + */ + if (idle && used =3D=3D seq_buf_used(&ns)) + goto next; + + /* + * $s may already have overflowed when $ns was created. If so, + * calling commit on it will trigger BUG. + */ + if (avail) { + seq_buf_commit(s, seq_buf_used(&ns)); + if (seq_buf_has_overflowed(&ns)) + seq_buf_set_overflow(s); + } + + if (rq->curr->sched_class =3D=3D &ext_sched_class && + (dump_all_tasks || scx_task_on_sched(sch, rq->curr))) + scx_dump_task(sch, s, dctx, rq, rq->curr, '*'); + + list_for_each_entry(p, &rq->scx.runnable_list, scx.runnable_node) + if (dump_all_tasks || scx_task_on_sched(sch, p)) + scx_dump_task(sch, s, dctx, rq, p, ' '); +next: + rq_unlock_irqrestore(rq, &rf); +} + /* * Dump scheduler state. If @dump_all_tasks is true, dump all tasks regard= less * of which scheduler they belong to. If false, only dump tasks owned by @= sch. @@ -6276,7 +6364,6 @@ static void scx_dump_state(struct scx_sched *sch, str= uct scx_exit_info *ei, }; struct seq_buf s; struct scx_event_stats events; - char *buf; int cpu; =20 guard(raw_spinlock_irqsave)(&scx_dump_lock); @@ -6316,87 +6403,7 @@ static void scx_dump_state(struct scx_sched *sch, st= ruct scx_exit_info *ei, dump_line(&s, "----------"); =20 for_each_possible_cpu(cpu) { - struct rq *rq =3D cpu_rq(cpu); - struct rq_flags rf; - struct task_struct *p; - struct seq_buf ns; - size_t avail, used; - bool idle; - - rq_lock_irqsave(rq, &rf); - - idle =3D list_empty(&rq->scx.runnable_list) && - rq->curr->sched_class =3D=3D &idle_sched_class; - - if (idle && !SCX_HAS_OP(sch, dump_cpu)) - goto next; - - /* - * We don't yet know whether ops.dump_cpu() will produce output - * and we may want to skip the default CPU dump if it doesn't. - * Use a nested seq_buf to generate the standard dump so that we - * can decide whether to commit later. - */ - avail =3D seq_buf_get_buf(&s, &buf); - seq_buf_init(&ns, buf, avail); - - dump_newline(&ns); - dump_line(&ns, "CPU %-4d: nr_run=3D%u flags=3D0x%x cpu_rel=3D%d ops_qseq= =3D%lu ksync=3D%lu", - cpu, rq->scx.nr_running, rq->scx.flags, - rq->scx.cpu_released, rq->scx.ops_qseq, - rq->scx.kick_sync); - dump_line(&ns, " curr=3D%s[%d] class=3D%ps", - rq->curr->comm, rq->curr->pid, - rq->curr->sched_class); - if (!cpumask_empty(rq->scx.cpus_to_kick)) - dump_line(&ns, " cpus_to_kick : %*pb", - cpumask_pr_args(rq->scx.cpus_to_kick)); - if (!cpumask_empty(rq->scx.cpus_to_kick_if_idle)) - dump_line(&ns, " idle_to_kick : %*pb", - cpumask_pr_args(rq->scx.cpus_to_kick_if_idle)); - if (!cpumask_empty(rq->scx.cpus_to_preempt)) - dump_line(&ns, " cpus_to_preempt: %*pb", - cpumask_pr_args(rq->scx.cpus_to_preempt)); - if (!cpumask_empty(rq->scx.cpus_to_wait)) - dump_line(&ns, " cpus_to_wait : %*pb", - cpumask_pr_args(rq->scx.cpus_to_wait)); - if (!cpumask_empty(rq->scx.cpus_to_sync)) - dump_line(&ns, " cpus_to_sync : %*pb", - cpumask_pr_args(rq->scx.cpus_to_sync)); - - used =3D seq_buf_used(&ns); - if (SCX_HAS_OP(sch, dump_cpu)) { - ops_dump_init(&ns, " "); - SCX_CALL_OP(sch, dump_cpu, rq, &dctx, cpu, idle); - ops_dump_exit(); - } - - /* - * If idle && nothing generated by ops.dump_cpu(), there's - * nothing interesting. Skip. - */ - if (idle && used =3D=3D seq_buf_used(&ns)) - goto next; - - /* - * $s may already have overflowed when $ns was created. If so, - * calling commit on it will trigger BUG. - */ - if (avail) { - seq_buf_commit(&s, seq_buf_used(&ns)); - if (seq_buf_has_overflowed(&ns)) - seq_buf_set_overflow(&s); - } - - if (rq->curr->sched_class =3D=3D &ext_sched_class && - (dump_all_tasks || scx_task_on_sched(sch, rq->curr))) - scx_dump_task(sch, &s, &dctx, rq, rq->curr, '*'); - - list_for_each_entry(p, &rq->scx.runnable_list, scx.runnable_node) - if (dump_all_tasks || scx_task_on_sched(sch, p)) - scx_dump_task(sch, &s, &dctx, rq, p, ' '); - next: - rq_unlock_irqrestore(rq, &rf); + scx_dump_cpu(sch, &s, &dctx, cpu, dump_all_tasks); } =20 dump_newline(&s); --=20 2.54.0 From nobody Tue Jun 16 20:37:15 2026 Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) (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 96BE436DA13; Wed, 29 Apr 2026 06:07:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.97.179.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777442881; cv=none; b=ihWLPUsPYa8O16g76aSczneRFyFOFywvlT1IbLGsI9RBUx7fTTXPA4KHYkll43wx/0ppPkMs5rCPX3vc5KD9UnEFlUZ1mscJb/937B9bZrGjBRHdhR/0WhxEut+GEfTksV02jjrSDQHkNg8zNwP3FYVwlhG3qhbg52lSPFSYTFU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777442881; c=relaxed/simple; bh=MzkGOIQZmAlxtv9jbJE3n0cz9aG7n+FPf8/CrqMObJI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LAlV2BUHY2zeii+Q06s5LV/vSCVY0NtSpHTyE56GOW+KoKfADF+GZRqCoIJhZtvBukcBcstMv38xshorEmrifIA51OL+swkeP8x2u3iiIxKMpT55WNfxjTt52fK3CHk1SQR7GlgYEsT4lvXVNcL8Np3LGWvVlH/sliQG3PAPDY0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com; spf=pass smtp.mailfrom=igalia.com; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b=DUoM65R/; arc=none smtp.client-ip=213.97.179.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=igalia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b="DUoM65R/" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=BW36nr8kIqpjT8I1PC2ncsZ47BXza7ZFAyF3zgV2BZE=; b=DUoM65R/5Zkm4Y8NM1B22C/Pd/ SGf7GahdtHHqcCi4PCeGPDGcje1LB9jsF52wg/Whyl8muZpad37Z+yJKEz+h7pQ970vNwP6vWb7VM 4TU/rF/Fm2zs4AqyVJA8XZQxTeEchANX3+vBwzU8mfLrgoVytiT0zVtVrPHlvEgY3kgVJRPkHrNKw QHfc3WZ5aYo3hoxU9SULGAO1xAyIPDuxGo+0pYyfhk4hgrQW6tILuDe9ZGQE4a2tKX9WVUKzPxnOP UamwhIfb61tKIhlJWnD3zpDTFO5pA95QXhLaOHx21WnBW6lbg6RTKjyn+5ZvF4GkYYClOE303DHZb h6HStN2A==; Received: from [58.29.145.179] (helo=localhost) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1wHy5R-003k5P-63; Wed, 29 Apr 2026 08:07:53 +0200 From: Changwoo Min To: tj@kernel.org, void@manifault.com, arighi@nvidia.com, changwoo@igalia.com Cc: kernel-dev@igalia.com, sched-ext@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/3] sched_ext: Dump the exit CPU first Date: Wed, 29 Apr 2026 15:07:25 +0900 Message-ID: <20260429060726.359024-3-changwoo@igalia.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260429060726.359024-1-changwoo@igalia.com> References: <20260429060726.359024-1-changwoo@igalia.com> 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" When sched_ext is disabled by an error, the CPU that triggered the exit is the most relevant piece of information for diagnosing the problem. However, if there are many CPUs, the dump can get truncated and that CPU's information may not appear in the output. Add an exit_cpu field to scx_exit_info and thread it through scx_vexit() / __scx_exit(). For the watchdog stall path, populate it from cpu_of(rq) in check_rq_for_timeouts(). For all other exit paths, define a scx_exit() macro that wraps __scx_exit() with raw_smp_processor_id(), so the CPU that initiated the exit is captured automatically, with no call-site changes needed. In scx_dump_state(), report the exit CPU in the dump header ("on cpu N") and dump that CPU first, skipping it in the per-CPU loop, so the most relevant CPU is never truncated out of the dump. The SysRq-D path initializes exit_cpu to -1 so debug dumps not tied to an exit don't arbitrarily promote CPU 0. Signed-off-by: Changwoo Min --- kernel/sched/ext.c | 52 +++++++++++++++++++++++++++---------- kernel/sched/ext_internal.h | 6 +++++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 025bd8c6f429..958935b96d05 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -234,24 +234,29 @@ static bool task_dead_and_done(struct task_struct *p); static void scx_kick_cpu(struct scx_sched *sch, s32 cpu, u64 flags); static void scx_disable(struct scx_sched *sch, enum scx_exit_kind kind); static bool scx_vexit(struct scx_sched *sch, enum scx_exit_kind kind, - s64 exit_code, const char *fmt, va_list args); + s64 exit_code, int exit_cpu, const char *fmt, + va_list args); =20 -static __printf(4, 5) bool scx_exit(struct scx_sched *sch, - enum scx_exit_kind kind, s64 exit_code, - const char *fmt, ...) +static __printf(5, 6) bool __scx_exit(struct scx_sched *sch, + enum scx_exit_kind kind, s64 exit_code, + int exit_cpu, const char *fmt, ...) { va_list args; bool ret; =20 va_start(args, fmt); - ret =3D scx_vexit(sch, kind, exit_code, fmt, args); + ret =3D scx_vexit(sch, kind, exit_code, exit_cpu, fmt, args); va_end(args); =20 return ret; } =20 +#define scx_exit(sch, kind, exit_code, fmt, args...) \ + __scx_exit(sch, kind, exit_code, raw_smp_processor_id(), fmt, ##args) + #define scx_error(sch, fmt, args...) scx_exit((sch), SCX_EXIT_ERROR, 0, fm= t, ##args) -#define scx_verror(sch, fmt, args) scx_vexit((sch), SCX_EXIT_ERROR, 0, fmt= , args) +#define scx_verror(sch, fmt, args) \ + scx_vexit((sch), SCX_EXIT_ERROR, 0, raw_smp_processor_id(), fmt, args) =20 #define SCX_HAS_OP(sch, op) test_bit(SCX_OP_IDX(op), (sch)->has_op) =20 @@ -3389,9 +3394,10 @@ static bool check_rq_for_timeouts(struct rq *rq) last_runnable + READ_ONCE(sch->watchdog_timeout)))) { u32 dur_ms =3D jiffies_to_msecs(jiffies - last_runnable); =20 - scx_exit(sch, SCX_EXIT_ERROR_STALL, 0, - "%s[%d] failed to run for %u.%03us", - p->comm, p->pid, dur_ms / 1000, dur_ms % 1000); + __scx_exit(sch, SCX_EXIT_ERROR_STALL, 0, cpu_of(rq), + "%s[%d] failed to run for %u.%03us", + p->comm, p->pid, dur_ms / 1000, + dur_ms % 1000); timed_out =3D true; break; } @@ -5528,6 +5534,7 @@ static struct scx_exit_info *alloc_exit_info(size_t e= xit_dump_len) if (!ei) return NULL; =20 + ei->exit_cpu =3D -1; ei->bt =3D kzalloc_objs(ei->bt[0], SCX_EXIT_BT_LEN); ei->msg =3D kzalloc(SCX_EXIT_MSG_LEN, GFP_KERNEL); ei->dump =3D kvzalloc(exit_dump_len, GFP_KERNEL); @@ -6384,8 +6391,13 @@ static void scx_dump_state(struct scx_sched *sch, st= ruct scx_exit_info *ei, if (ei->kind =3D=3D SCX_EXIT_NONE) { dump_line(&s, "Debug dump triggered by %s", ei->reason); } else { - dump_line(&s, "%s[%d] triggered exit kind %d:", - current->comm, current->pid, ei->kind); + if (ei->exit_cpu >=3D 0) + dump_line(&s, "%s[%d] triggered exit kind %d on cpu %d:", + current->comm, current->pid, ei->kind, + ei->exit_cpu); + else + dump_line(&s, "%s[%d] triggered exit kind %d:", + current->comm, current->pid, ei->kind); dump_line(&s, " %s (%s)", ei->reason, ei->msg); dump_newline(&s); dump_line(&s, "Backtrace:"); @@ -6402,8 +6414,15 @@ static void scx_dump_state(struct scx_sched *sch, st= ruct scx_exit_info *ei, dump_line(&s, "CPU states"); dump_line(&s, "----------"); =20 + /* + * Dump the exit CPU first so it isn't lost to dump truncation, then + * walk the rest in order, skipping the one already dumped. + */ + if (ei->exit_cpu >=3D 0) + scx_dump_cpu(sch, &s, &dctx, ei->exit_cpu, dump_all_tasks); for_each_possible_cpu(cpu) { - scx_dump_cpu(sch, &s, &dctx, cpu, dump_all_tasks); + if (cpu !=3D ei->exit_cpu) + scx_dump_cpu(sch, &s, &dctx, cpu, dump_all_tasks); } =20 dump_newline(&s); @@ -6442,7 +6461,7 @@ static void scx_disable_irq_workfn(struct irq_work *i= rq_work) } =20 static bool scx_vexit(struct scx_sched *sch, - enum scx_exit_kind kind, s64 exit_code, + enum scx_exit_kind kind, s64 exit_code, int exit_cpu, const char *fmt, va_list args) { struct scx_exit_info *ei =3D sch->exit_info; @@ -6465,6 +6484,7 @@ static bool scx_vexit(struct scx_sched *sch, */ ei->kind =3D kind; ei->reason =3D scx_exit_reason(ei->kind); + ei->exit_cpu =3D exit_cpu; =20 irq_work_queue(&sch->disable_irq_work); return true; @@ -7730,7 +7750,11 @@ static const struct sysrq_key_op sysrq_sched_ext_res= et_op =3D { =20 static void sysrq_handle_sched_ext_dump(u8 key) { - struct scx_exit_info ei =3D { .kind =3D SCX_EXIT_NONE, .reason =3D "SysRq= -D" }; + struct scx_exit_info ei =3D { + .kind =3D SCX_EXIT_NONE, + .exit_cpu =3D -1, + .reason =3D "SysRq-D", + }; struct scx_sched *sch; =20 list_for_each_entry_rcu(sch, &scx_sched_all, all) diff --git a/kernel/sched/ext_internal.h b/kernel/sched/ext_internal.h index a54903bb74b3..58d675b57d04 100644 --- a/kernel/sched/ext_internal.h +++ b/kernel/sched/ext_internal.h @@ -97,6 +97,12 @@ struct scx_exit_info { /* %SCX_EXIT_* - broad category of the exit reason */ enum scx_exit_kind kind; =20 + /* + * CPU that initiated the exit, valid once @kind has been set. + * Negative if the exit path didn't identify a CPU. + */ + int exit_cpu; + /* exit code if gracefully exiting */ s64 exit_code; =20 --=20 2.54.0 From nobody Tue Jun 16 20:37:15 2026 Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) (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 3A955330644; Wed, 29 Apr 2026 06:08:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.97.179.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777442886; cv=none; b=GOvUkMwzjR01jOXfdKmkRVsxzO9FyS6FunqQCcItyzDuONwJUYLgrxV8UDMQnNTVaMsXJ682nyr8FjZdZmKveshPo9kBx0vGH8Q2mLrRCouZAMm1ngM+MA7FUAnV5Tf0fvXdHsStxeu5QblNciwZ4yXPzYJUw+HOvSgEM11nYI4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777442886; c=relaxed/simple; bh=+P8W/lT3bxuFm/Ngj7kKpLGTVtYYOj54bCstVxBja18=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MAmlGdU7EQVZBeye2IhkYnnDE5BgVHEW8fruXgZ8tgkm/yJtVy+L7GMHf8G1xAihu+847y2INIDJa6hmbCrsX2C9TfL1LqFs3UWiyhyz/evnZMQGiMBZVRinJP5PHXCHDiYkBJiBn6X32JsQl4Ag1noQfuWK23k9tYDi+kJSV/Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com; spf=pass smtp.mailfrom=igalia.com; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b=SgxJBHxc; arc=none smtp.client-ip=213.97.179.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=igalia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b="SgxJBHxc" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=gAy3VZ2Jr47jr7y04kRS3/RIQobp5zpizklhUo8OV4I=; b=SgxJBHxcZYyWIryahmDi6OREy3 64vCiLEixazKcqyDNL9K+vD92JmR8DgPRwBGE/MjnnxC7d9BsZmVPD3IrcykTLA/O7kPloZLXrhFo hrB/mzuAaWjPWyPwmprZefffcUEDt4EVpjn/0HzD3g5iuTxpA8XZ1F41QK1sYk5GJBynBaTAKmkWj fbhX3r1jmfkwZQkOh6vuJYuhHPRitl8BvBQ0jxVqoKkWXwggnwx3oDKN4RMCx6Z4cq8AzFhCI38D4 2FP4lUf1o7Yfd/Rjs7yJInG3qb/1Ur5YQR5BA9odZqIddlfibYHa6I13zUG9wVVKf+dzwH8lZ06M+ zYfUQyjQ==; Received: from [58.29.145.179] (helo=localhost) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1wHy5X-003k5h-3q; Wed, 29 Apr 2026 08:07:59 +0200 From: Changwoo Min To: tj@kernel.org, void@manifault.com, arighi@nvidia.com, changwoo@igalia.com Cc: kernel-dev@igalia.com, sched-ext@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH v2 3/3] sched_ext: Expose exit_cpu to BPF and userspace Date: Wed, 29 Apr 2026 15:07:26 +0900 Message-ID: <20260429060726.359024-4-changwoo@igalia.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260429060726.359024-1-changwoo@igalia.com> References: <20260429060726.359024-1-changwoo@igalia.com> 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" Extend struct user_exit_info with an exit_cpu field so BPF schedulers and the userspace report path can see the CPU that triggered the exit, matching the kernel-side dump. UEI_RECORD() defaults the field to -1 before the CO-RE-gated copy so that running against an older kernel without exit_cpu stays distinguishable from "exit happened on CPU 0". UEI_REPORT() appends "on CPU N" to the EXIT line when the value is valid, surfacing the most diagnostically useful piece of exit info to any sched_ext userspace tool without needing to crack open the debug dump. Signed-off-by: Changwoo Min --- tools/sched_ext/include/scx/user_exit_info.bpf.h | 3 +++ tools/sched_ext/include/scx/user_exit_info.h | 2 ++ tools/sched_ext/include/scx/user_exit_info_common.h | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/tools/sched_ext/include/scx/user_exit_info.bpf.h b/tools/sched= _ext/include/scx/user_exit_info.bpf.h index e7ac6611a990..98cab643c8d9 100644 --- a/tools/sched_ext/include/scx/user_exit_info.bpf.h +++ b/tools/sched_ext/include/scx/user_exit_info.bpf.h @@ -32,6 +32,9 @@ __uei_name##_dump_len, (__ei)->dump); \ if (bpf_core_field_exists((__ei)->exit_code)) \ __uei_name.exit_code =3D (__ei)->exit_code; \ + __uei_name.exit_cpu =3D -1; \ + if (bpf_core_field_exists((__ei)->exit_cpu)) \ + __uei_name.exit_cpu =3D (__ei)->exit_cpu; \ /* use __sync to force memory barrier */ \ __sync_val_compare_and_swap(&__uei_name.kind, __uei_name.kind, \ (__ei)->kind); \ diff --git a/tools/sched_ext/include/scx/user_exit_info.h b/tools/sched_ext= /include/scx/user_exit_info.h index 399697fa372f..56a02b549aef 100644 --- a/tools/sched_ext/include/scx/user_exit_info.h +++ b/tools/sched_ext/include/scx/user_exit_info.h @@ -39,6 +39,8 @@ fprintf(stderr, "EXIT: %s", __uei->reason); \ if (__uei->msg[0] !=3D '\0') \ fprintf(stderr, " (%s)", __uei->msg); \ + if (__uei->exit_cpu >=3D 0) \ + fprintf(stderr, " on CPU %d", __uei->exit_cpu); \ fputs("\n", stderr); \ __uei->exit_code; \ }) diff --git a/tools/sched_ext/include/scx/user_exit_info_common.h b/tools/sc= hed_ext/include/scx/user_exit_info_common.h index 2d0981aedd89..b98dd2973aee 100644 --- a/tools/sched_ext/include/scx/user_exit_info_common.h +++ b/tools/sched_ext/include/scx/user_exit_info_common.h @@ -22,6 +22,11 @@ enum uei_sizes { =20 struct user_exit_info { int kind; + /* + * CPU that triggered the exit, or -1 if unset (e.g. running on an + * older kernel that does not expose this field). + */ + int exit_cpu; s64 exit_code; char reason[UEI_REASON_LEN]; char msg[UEI_MSG_LEN]; --=20 2.54.0