Re: [PATCH] sched/psi: use for_each_set_bit() in psi_group_change() task-count walk

From: Johannes Weiner

Date: Wed Jul 15 2026 - 10:10:51 EST


On Tue, Jul 14, 2026 at 07:20:57AM -0700, Usama Arif wrote:
> psi_group_change() walks the @clear and @set bitmasks to
> decrement/increment groupc->tasks[t]. Both masks are at most
> NR_PSI_TASK_COUNTS (=4) wide, dense at [0, 4), and typically
> sparse. Today's form visits every position up to the highest set
> bit:
>
> for (t = 0, m = clear; m; m &= ~(1 << t), t++) {
> if (!(m & (1 << t)))
> continue;
> ...
> }
>
> so a mask with only bit 3 set still spins four times; the same
> open-coded shape repeats for @set. The code is also unnecessarily
> hard to read.
>
> Switch both walks to for_each_set_bit() which is easier to read
> and also more efficient. As NR_PSI_TASK_COUNTS is a compile-time
> constant <= BITS_PER_LONG, find_next_bit() folds into its
> small_const_nbits() fast path (single load + GENMASK + __ffs), lowering
> to a bit-scan where one exists (x86 TZCNT/BSF, arm64 RBIT+CLZ).
>
> psi_group_change() runs from psi_task_switch() and psi_task_change()
> once per ancestor psi_group per event, so the saved iterations
> multiply out on any hot scheduler workload.
>
> No functional change intended.

This actually started out using ffs. Because the performance is so
sensitive in this path, this was handtuned to scheduler benchmarks.

https://lore.kernel.org/all/20180718120318.GC2476@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/

Not the worst idea to revisit this, but you have to be careful, look
at the asm, and benchmark it. gcc is producing more code for me with
your patch.