From: Vineet Gupta <vineet.gupta@linux.dev>
To: Peter Zijlstra <peterz@infradead.org>
Cc: rostedt@goodmis.org, mhiramat@kernel.org, mark.rutland@arm.com,
mathieu.desnoyers@efficios.com, andrii@kernel.org,
linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org,
bpf@vger.kernel.org, kernel-team@meta.com,
stable@vger.kernel.org
Subject: Re: [PATCH 1/2] tracing: fgraph: Raise FTRACE_RETSTACK_ALLOC_SIZE to 1024
Date: Fri, 25 Sep 2026 12:32:49 -0700 [thread overview]
Message-ID: <1e223334-b371-487b-a60a-7f1f5c007f7e@linux.dev> (raw)
In-Reply-To: <20260924100040.GD4121339@noisy.programming.kicks-ass.net>
On 9/24/26 3:00 AM, Peter Zijlstra wrote:
> On Tue, Sep 22, 2026 at 03:55:25PM -0700, Vineet Gupta wrote:
>> When ftrace graphing is turned on, all tasks in the system missing
>> return stack page are assigned one. This is done in a simplistic
>> multi-sweep loop of FTRACE_RETSTACK_ALLOC_SIZE (currently 32) tasks
>> at a time as follows:
>>
>> start_graph_tracing()
>> do {
>> alloc_retstack_tasklist
>> } while (-EAGAIN);
>>
>> alloc_retstack_tasklist()
>> alloc x32 # GFP_KERNEL, may sleep
>> rcu_read_lock() # preempt off
>> for_each_process_thread walk N_total, no cond_resched
>> t->ret_stack = new_page
>> rcu_read_unlock() # preempt enable but no explicit yield
>>
>> Each successive iteration of loop invokes for_each_process_thread()
>> which doesn't support cursor based resume and always restarts from the
>> init_task. Thus each successive loop needs to skip the tasks assigned
>> ret_stack in prior sweeps and thus take longer and longer to find the
>> candidate 32 tasks.
> Does this work?
Yes it does and much better at that: test run for 400k threads went down
from 227 s (stock) to 7.2 s (my patch) to 92 ms. Woo hoo !
I didn't know about this cool trick.
A couple of things worth pointing out:
> diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
> index ed455b53513b..155dafad474d 100644
> --- a/kernel/trace/fgraph.c
> +++ b/kernel/trace/fgraph.c
> @@ -1036,10 +1036,9 @@ trace_func_graph_ent_t ftrace_graph_entry = ftrace_graph_entry_stub;
> /* Try to assign a return stack array on FTRACE_RETSTACK_ALLOC_SIZE tasks. */
> static int alloc_retstack_tasklist(unsigned long **ret_stack_list)
> {
> - int i;
> - int ret = 0;
> int start = 0, end = FTRACE_RETSTACK_ALLOC_SIZE;
> struct task_struct *g, *t;
> + int i, ret = 0;
>
> if (WARN_ON_ONCE(!fgraph_stack_cachep))
> return -ENOMEM;
> @@ -1054,26 +1053,29 @@ static int alloc_retstack_tasklist(unsigned long **ret_stack_list)
> }
> }
>
> - rcu_read_lock();
> - for_each_process_thread(g, t) {
> - if (start == end) {
> - ret = -EAGAIN;
> - goto unlock;
> - }
> + scoped_guard (rcu) {
> + for_each_process_thread(g, t) {
> + unsigned long *rs;
> +
> + if (t->ret_stack)
> + continue;
> +
> + rs = kmem_cache_alloc(fgraph_stack_cachep, GFP_NOWAIT);
It still pre-allocates FTRACE_RETSTACK_ALLOC_SIZE reserves in the fast
path - my (limited) testing never hit the reserves, but I agree better
to keep it and 32 seems like a reasonably low number?
> + if (!rs) {
> + if (start == end)
> + return -EAGAIN;
This indicates the reserve pool is exhausted so it safe to elide the
free: loop at the end: warrants a comment IMO.
For submission, would you take this up as reported-by me or do you
prefer I send a v2 (your authorship and SoB etc) ? No big deal either
ways just not sure what the std operating procedure is and nuances of
all the tags etc.
Thx,
-Vineet
> + rs = ret_stack_list[start++];
> + }
>
> - if (t->ret_stack == NULL) {
> atomic_set(&t->trace_overrun, 0);
> - ret_stack_init_task_vars(ret_stack_list[start]);
> + ret_stack_init_task_vars(rs);
> t->curr_ret_stack = 0;
> t->curr_ret_depth = -1;
> /* Make sure the tasks see the 0 first: */
> - smp_wmb();
> - t->ret_stack = ret_stack_list[start++];
> + smp_store_release(&t->ret_stack, rs);
> }
> }
>
> -unlock:
> - rcu_read_unlock();
> free:
> for (i = start; i < end; i++)
> kmem_cache_free(fgraph_stack_cachep, ret_stack_list[i]);
next prev parent reply other threads:[~2026-09-25 19:32 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-22 22:55 [PATCH 0/2] tracing: fgraph: cut the cost of the shadow stack retry loop Vineet Gupta
2026-09-22 22:55 ` [PATCH 1/2] tracing: fgraph: Raise FTRACE_RETSTACK_ALLOC_SIZE to 1024 Vineet Gupta
2026-09-24 10:00 ` Peter Zijlstra
2026-09-25 19:32 ` Vineet Gupta [this message]
2026-09-26 12:46 ` Steven Rostedt
2026-09-22 22:55 ` [PATCH 2/2] tracing: fgraph: Add a cond_resched() to the shadow stack retry loop Vineet Gupta
2026-09-23 8:47 ` Steven Rostedt
2026-09-24 20:45 ` [PATCH 0/2] tracing: fgraph: cut the cost of " Steven Rostedt
2026-09-25 2:31 ` Vineet Gupta
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=1e223334-b371-487b-a60a-7f1f5c007f7e@linux.dev \
--to=vineet.gupta@linux.dev \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=kernel-team@meta.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mathieu.desnoyers@efficios.com \
--cc=mhiramat@kernel.org \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=stable@vger.kernel.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 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.