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
