From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
To: Peter Zijlstra <peterz@infradead.org>
Cc: Chris Mason <clm@meta.com>,
linux-kernel@vger.kernel.org,
Thomas Gleixner <tglx@linutronix.de>
Subject: Re: futex performance regression from "futex: Allow automatic allocation of process wide futex hash"
Date: Thu, 26 Jun 2025 15:48:20 +0200 [thread overview]
Message-ID: <20250626134820.ybEtTXSN@linutronix.de> (raw)
In-Reply-To: <20250624190118.GB1490279@noisy.programming.kicks-ass.net>
On 2025-06-24 21:01:18 [+0200], Peter Zijlstra wrote:
> How about something like this (very lightly tested)...
>
> the TL;DR is that it turns all those refcounts into per-cpu ops when
> there is no hash replacement pending (eg. the normal case), and only
> folds the lot into an atomic when we really care about it.
so we have per-CPU counter and on resize we wait one RCU grace period to
ensure everybody observed current fph, switch to atomics and wait one
grace period to ensure everyone is using atomics. Last step is to align
the atomic counter with the per-CPU counters and once the counter
reaches 0 perform the swap.
This looks fine :) Due to the RCU grace period, the swap takes longer
than before. I guess that is why you said earlier with to use srcu. For
things like "hackbench -T" you end up creating a new hash on every
thread creation which is not applied because RCU takes a while.
This could be optimized later by checking if the hash in futex_phash_new
matches the requested size.
> There's some sharp corners still.. but it boots and survives the
> (slightly modified) selftest.
The refcount does not pop up in perf so that is good.
> --- a/kernel/futex/core.c
> +++ b/kernel/futex/core.c
> @@ -243,14 +247,18 @@ static bool __futex_pivot_hash(struct mm_struct *mm,
> fph = rcu_dereference_protected(mm->futex_phash,
> lockdep_is_held(&mm->futex_hash_lock));
> if (fph) {
> - if (!rcuref_is_dead(&fph->users)) {
> + if (!futex_ref_is_dead(fph)) {
> mm->futex_phash_new = new;
> return false;
> }
>
> futex_rehash_private(fph, new);
> }
> - rcu_assign_pointer(mm->futex_phash, new);
> + new->state = FR_PERCPU;
> + scoped_guard (rcu) {
We do space or we don't? It looks like sched/ does while the remaining
bits of the kernel mostly don't. I don't care but we could (later)
adjust it for futex towards one direction.
> + mm->futex_batches = get_state_synchronize_rcu();
> + rcu_assign_pointer(mm->futex_phash, new);
> + }
> kvfree_rcu(fph, rcu);
> return true;
> }
…
> +static void futex_ref_drop(struct futex_private_hash *fph)
…
> + call_rcu_hurry(&mm->futex_rcu, futex_ref_rcu);
Do you think it would improve with srcu or it is not worth it?
> +}
> +
> +static bool futex_ref_get(struct futex_private_hash *fph)
> +{
> + struct mm_struct *mm = fph->mm;
> +
> + guard(preempt)();
> +
> + if (smp_load_acquire(&fph->state) == FR_PERCPU) {
> + this_cpu_inc(*mm->futex_ref);
> + return true;
> + }
> +
> + return atomic_long_inc_not_zero(&mm->futex_atomic);
> +}
> +
> +static bool futex_ref_put(struct futex_private_hash *fph)
> +{
> + struct mm_struct *mm = fph->mm;
> +
> + guard(preempt)();
> +
> + if (smp_load_acquire(&fph->state) == FR_PERCPU) {
> + this_cpu_dec(*mm->futex_ref);
> + return false;
> + }
> +
> + return atomic_long_dec_and_test(&mm->futex_atomic);
> +}
> +
> +static bool futex_ref_is_dead(struct futex_private_hash *fph)
> +{
> + struct mm_struct *mm = fph->mm;
> +
> + guard(preempt)();
> +
> + if (smp_load_acquire(&fph->state) == FR_PERCPU)
> + return false;
> +
> + return atomic_long_read(&mm->futex_atomic) == 0;
> +}
Why preempt_disable()? Is it just an optimized version of
rcu_read_lock()? I don't understand why. You don't even go for
__this_cpu_inc() so I a bit puzzled.
Sebastian
next prev parent reply other threads:[~2025-06-26 13:48 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-03 19:00 Chris Mason
2025-06-04 9:28 ` Sebastian Andrzej Siewior
2025-06-04 15:48 ` Chris Mason
2025-06-04 20:08 ` Sebastian Andrzej Siewior
2025-06-06 0:55 ` Chris Mason
2025-06-06 7:06 ` Sebastian Andrzej Siewior
2025-06-06 21:06 ` Chris Mason
2025-06-06 22:17 ` Chris Mason
2025-06-24 19:01 ` Peter Zijlstra
2025-06-26 11:01 ` Chris Mason
2025-06-26 13:17 ` Peter Zijlstra
2025-06-26 13:50 ` Sebastian Andrzej Siewior
2025-06-27 11:04 ` Peter Zijlstra
2025-06-27 12:14 ` Sebastian Andrzej Siewior
2025-06-30 14:50 ` [PATCH] futex: Temporary disable FUTEX_PRIVATE_HASH Sebastian Andrzej Siewior
2025-07-01 13:13 ` [tip: locking/urgent] " tip-bot2 for Sebastian Andrzej Siewior
2025-07-16 1:34 ` [PATCH] " kernel test robot
2025-06-26 13:48 ` Sebastian Andrzej Siewior [this message]
2025-06-26 14:36 ` futex performance regression from "futex: Allow automatic allocation of process wide futex hash" Peter Zijlstra
2025-06-27 12:24 ` Sebastian Andrzej Siewior
2025-06-27 22:48 ` Tim Chen
2025-06-28 8:23 ` Peter Zijlstra
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=20250626134820.ybEtTXSN@linutronix.de \
--to=bigeasy@linutronix.de \
--cc=clm@meta.com \
--cc=linux-kernel@vger.kernel.org \
--cc=peterz@infradead.org \
--cc=tglx@linutronix.de \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®