alloc_retstack_tasklist() assigns a shadow stack to every thread when fgraph is enabled. It did so FTRACE_RETSTACK_ALLOC_SIZE (32) tasks at a time, and since for_each_process_thread() has no cursor, every sweep restarted from init_task and re-walked the tasks already served, making the ftrace_graph_active 0 -> 1 transition quadratic in the thread count. On a 60-core Sapphire Rapids machine with 400000 idle threads it took 227 s, inside a single bpf() syscall for the kprobe_multi case.
Allocating inline with GFP_NOWAIT removes the batching: a single sweep serves every task, 227 s -> 0.092 s. v1: https://lore.kernel.org/all/[email protected]/ v2: https://lore.kernel.org/all/[email protected]/ Changes since v2: - update the stale alloc_retstack_tasklist() comment, which still described the old batch-of-32 behaviour (bot+bpf-ci) Sashiko flagged the mix of goto-based cleanup and scoped_guard() in this function. Peter and Andrii both considered it fine as is, so it is unchanged: https://lore.kernel.org/all/[email protected]/ Changes since v1: - replace both v1 patches with Peter's inline GFP_NOWAIT approach, which removes the quadratic behaviour rather than dividing it by a constant. With a single sweep there is no retry loop left, so the v1 cond_resched() patch has nothing to attach to and is dropped. - comment why returning from inside scoped_guard() skips the free loop safely Vineet Gupta (1): tracing: fgraph: allocate shadow stacks inline with GFP_NOWAIT kernel/trace/fgraph.c | 44 ++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) -- 2.53.0-Meta
