On Thu, 1 Oct 2026 12:05:31 GMT, Fredrik Bredberg <[email protected]> wrote:

> This PR reduces the Thread-SMR (Safe Memory Reclamation) related cost of 
> starting and exiting threads.
> 
> Both starting and exiting a thread create a new `ThreadsList` and retire the 
> old one. Previously, we used to scan the hazard pointers of all threads when 
> a `ThreadsList` was retired. This made the execution cost increasingly higher 
> as more threads were started.
> 
> This PR tackles the problem in three ways:
> 
> 1. By not scanning hazard pointers every time a new thread is started. 
> Instead, we defer the scanning until either 16 `ThreadsLists` have been 
> retired or the retired lists occupy at least 4 MB of memory.
> 2. We use the scan that is performed when removing a thread to also determine 
> if it's safe to delete the thread, and thereby we potentially avoid a costly 
> re-scan in `wait_until_not_protected()`.
> 3. By checking if there is no retired `ThreadsList` that can protect the 
> thread, `wait_until_not_protected()` can also avoid a re-scan.
> 
> I've run the ThreadStart reproducer that is attached to 
> [JDK-8307970](https://bugs.openjdk.org/browse/JDK-8307970). Depending on the 
> number of idle threads, the changes in this PR show that threads start up to 
> ~63% faster (or in other words, a ~39% reduction in time to start a thread).
> 
> To go further than this likely requires a major rewrite of the Thread-SMR 
> system, which would not be a walk in the park.
> 
> Passes tier1-3 tests.
> 
> ---------
> - [x] I confirm that I make this contribution in accordance with the [OpenJDK 
> Interim AI Policy](https://openjdk.org/legal/ai).

I thought about using an atomic counter to track numbers of threads that 
acquire a stable `ThreadsList` (inc/dec on non-nested case), which would allow 
to delete all retired lists without the need to scan anything if the counter is 
zero. It does reduce startup costs further for this benchmark, but it would add 
extra overhead for readers and create cache contention when multiple readers 
execute concurrently. Ideally the scan would not need to walk all threads but 
that would require a bigger rewrite and would likely come with other costs. In 
any case this looks like an improvement over the current implementation so 
further optimizations can always be explored separately. Some comments below, 
thanks.

src/hotspot/share/runtime/threadSMR.cpp line 971:

> 969:   }
> 970:   _retired_since_reclaim_cnt = 0;
> 971:   _retired_since_reclaim_mem = 0;

If we don’t delete any list below (or just a few) the number of retired 
`ThreadsLists` and memory used can keep growing past the 16 and 4M thresholds 
before the next reclaim attempt. Was the intended policy to trigger the next 
reclaim attempt based on newly retired lists, or should the counters be updated 
based on lists removed below? If it should be based on removed lists, the 
counters would also need to be incremented when `thread_to_delete != nullptr` 
above.

src/hotspot/share/runtime/threadSMR.cpp line 1007:

> 1005:       }
> 1006:     } else {
> 1007:       if (thread_is_safe_to_delete && 
> current->includes(thread_to_delete)) {

If `current == threads` we know the list will include the thread being removed 
so we can avoid the list search.

-------------

PR Review: https://git.openjdk.org/jdk/pull/33166#pullrequestreview-5553747491
PR Review Comment: https://git.openjdk.org/jdk/pull/33166#discussion_r4299407786
PR Review Comment: https://git.openjdk.org/jdk/pull/33166#discussion_r4299386989

Reply via email to