Re: [RFC PATCH v4 0/4] Hazard Pointers
Joel Fernandes <[email protected]> Thu, 18 Dec 2025 05:33:02 -0500
| Newsgroups | dev.linux.lists.lkmm,org.kernel.vger.linux-kernel,org.kernel.vger.rcu,org.kvack.linux-mm |
|---|---|
| Message-ID | <[email protected]> |
Hi Mathieu, Thanks for posting this. > On Dec 17, 2025, at 8:45=E2=80=AFPM, Mathieu Desnoyers <mathieu.desnoyers@= efficios.com> wrote: >=20 > =EF=BB=BFHi, >=20 > Here is a revisited version of my Hazard Pointers series. Boqun, Joel, > if you guys have time to try it out with your use-cases it would be > great! >=20 > This new version does the following: >=20 > - It has 8 preallocated hazard pointer slots per CPU (one cache line), > - The hazard pointer user allocates a hazard pointer context variable > (typically on the stack), which contains the pointer to the slot *and* > a backup slot, > - When all the per-CPU slots are in use, fallback to the backup slot. > Chain the backup slot into per-CPU lists, each protected by a raw > spinlock. > - The hazard pointer synchronize does a piecewise iteration on the > per-CPU overflow slots lists, releasing the raw spinlock between > each list item. It uses a 64-bit generation counter to check for > concurrent list changes, and restart the traversal on generation > counter mismatch. > - There is a new CONFIG_PREEMPT_HAZPTR config option. When enabled, > the hazard pointer acquire/release adds and then removes the hazard > pointer context from a per-task linked list. On context switch, the > scheduler migrates the per-CPU slots used by the task to the backup > per-context slots, thus making sure the per-CPU slots are not used > by preempted and blocked tasks. This last point is another reason why I want the slots to be per task instea= d of per CPU. It becomes very natural because the hazard pointer is always a= ssociated with a task only anyway, not with the CPU (at usecase level). By p= utting the slot in the task struct, we allow these requirements to flow natu= rally without requiring any locking or list management.. Did I miss somethin= g about the use cases? I did some measurements about the task-scanning issue, and it is fast in my t= esting (~1ms/10000 tasks). Any input from you or anyone on what the typical t= ask count distribution is that we are addressing? I also made a rough protot= ype, and it appears to be simpler with fewer lines of code because I do not n= eed to handle preemption. It just happens naturally. First of all, we can have a per-task counter that tracks how many hazard poi= nters are active. If this is zero, then we can simply skip the task instead o= f wasting cycles scanning all the task slot. Further, we can have a retire l= ist that reuses a single scan to scan all the objects in the retire list, th= us reusing the scan cost. This can also assist in asynchronously implementin= g object retiring via a dedicated thread perhaps with the tasks RCU infrastr= ucture. We can also make this per-task counter a bitmap to speed up scanning= potentially. I am okay with the concept of an overflow list, but if we keep the overflow l= ist at the per-task level instead of the per-CPU level, it is highly unlikel= y IMO that such an overflow list will be used unless more than, say, eight h= azard pointers per task are active at any given time. So its lock contention= would be rarer than, say, having a per-CPU overflow list. I would say that c= ontention would be incredibly rare because typically hazard pointers are use= d by multiple tasks, each of which will have its own unique set of slots. Wh= ereas in a per-CPU overflow approach, we have a higher chance of lock conte= ntion, especially when the number of CPUs is low. Other than the task-scanning performance issue, what am I missing? Another nice benefit of using per-task hazard pointers is that we can also i= mplement sleeping in hazard pointer sections because we will be scanning for= sleeping tasks as well. By contrast, the other approaches I have seen with per-CPU hazard pointers f= orbid sleeping, since after sleeping a task is no longer associated with its= CPU. The other approaches also have a higher likelihood of locking Due to r= unning out of slots. Of course I am missing a use case, but I suspect we can find a per-CPU ref-c= ount use case that benefits from this. I am researching use cases when I get= time. I think my next task is to find a solid use case for this before doin= g further development of a solution.. By the way, feedback on the scanning patch: Can you consider using a per-CPU counter to track the number of active slots= per CPU? That way you can ignore CPU slots for CPUs that are not using haza= rd pointers. Another idea is to skip idle CPUs as well. Have you also considered any asynchronous use case where maintaining a retir= ed list would assist in RCU-style deferred reclaim of hazard-pointer objects= ? thanks, - Joel=20 >=20 > It is based on v6.18.1. >=20 > Review is very welcome, >=20 > Thanks, >=20 > Mathieu >=20 > Cc: Nicholas Piggin <[email protected]> > Cc: Michael Ellerman <[email protected]> > Cc: Greg Kroah-Hartman <[email protected]> > Cc: Sebastian Andrzej Siewior <[email protected]> > Cc: "Paul E. McKenney" <[email protected]> > Cc: Will Deacon <[email protected]> > Cc: Peter Zijlstra <[email protected]> > Cc: Boqun Feng <[email protected]> > Cc: Alan Stern <[email protected]> > Cc: John Stultz <[email protected]> > Cc: Neeraj Upadhyay <[email protected]> > Cc: Linus Torvalds <[email protected]> > Cc: Andrew Morton <[email protected]> > Cc: Boqun Feng <[email protected]> > Cc: Frederic Weisbecker <[email protected]> > Cc: Joel Fernandes <[email protected]> > Cc: Josh Triplett <[email protected]> > Cc: Uladzislau Rezki <[email protected]> > Cc: Steven Rostedt <[email protected]> > Cc: Lai Jiangshan <[email protected]> > Cc: Zqiang <[email protected]> > Cc: Ingo Molnar <[email protected]> > Cc: Waiman Long <[email protected]> > Cc: Mark Rutland <[email protected]> > Cc: Thomas Gleixner <[email protected]> > Cc: Vlastimil Babka <[email protected]> > Cc: [email protected] > Cc: Mateusz Guzik <[email protected]> > Cc: Jonas Oberhauser <[email protected]> > Cc: [email protected] > Cc: [email protected] > Cc: [email protected] >=20 > Mathieu Desnoyers (4): > compiler.h: Introduce ptr_eq() to preserve address dependency > Documentation: RCU: Refer to ptr_eq() > hazptr: Implement Hazard Pointers > hazptr: Migrate per-CPU slots to backup slot on context switch >=20 > Documentation/RCU/rcu_dereference.rst | 38 +++- > include/linux/compiler.h | 63 +++++++ > include/linux/hazptr.h | 241 ++++++++++++++++++++++++++ > include/linux/sched.h | 4 + > init/init_task.c | 3 + > init/main.c | 2 + > kernel/Kconfig.preempt | 10 ++ > kernel/Makefile | 2 +- > kernel/fork.c | 3 + > kernel/hazptr.c | 150 ++++++++++++++++ > kernel/sched/core.c | 2 + > 11 files changed, 512 insertions(+), 6 deletions(-) > create mode 100644 include/linux/hazptr.h > create mode 100644 kernel/hazptr.c >=20 > -- > 2.39.5 >=20