On Mon, 1 Dec 2025 11:59:38 GMT, Stuart Monteith <[email protected]> wrote:
> MemorySegments allocated from shared Arena from
> java.lang.foreign.Arena.ofShared() have their lifecycle controlled by
> jdk.internal.foreign.SharedSession. This class ensures that the
> MemorySegments can't be freed until after a thread has called Arena.close().
> This is implemented using a counter that is atomically incremented when used,
> and decremented when not used, on every invocation of a downcall. While
> shared Arenas allow any thread to use it and to close it, this tracking has a
> cost when multiple threads are contended on it. This patch changes the
> implementation to use multiple counters to reduce contention.
> sun.nio.ch.IOUtil, java.nio.Buffer and
> sun.nio.ch.SimpleAsynchronousFileChannelImpl are modified as they have
> threads releasing the scope different from the ones that allocated them, so a
> ticket that tracks the counter has to be passed over.
>
> The microbenchmark org.openjdk.bench.java.lang.foreign.
> CallOverheadConstant.panama_identity_memory_address_shared_3 was used to
> generate the following results. The scalability was checked on a number of
> platforms with the JMH parameter "-t" specifying the number of threads.
> Measurements are in ns/op .
>
> The hardware are the Neoverse-N1, N2, V1 and V2, Intel Xeon 8375c and the AMD
> Epyc 9654.
>
> | Threads | N1 | N2 | V1 | V2 | Xeon |
> Epyc |
> |---------|-------|-------|-------|-------|-------|-------|
> | 1 | 30.88 | 32.15 | 33.54 | 32.82 | 27.46 |
> 8.45 |
> | 2 | 142.56 | 134.48 | 132.01 | 131.50 | 116.68 | 46.53
> |
> | 4 | 310.18 | 282.75 | 287.59 | 271.82 | 251.88 | 86.11
> |
> | 8 | 702.02 | 710.29 | 736.72 | 670.63 | 533.46 | 194.60
> |
> | 16 | 1,436.17 | 1,684.80 | 1,833.69 | 1,782.78 | 1,100.15 |
> 827.28 |
> | 24 | 2,185.55 | 2,508.86 | 2,732.22 | 2,815.26 | 1,646.09 | 1,530.28
> |
> | 32 | 2,942.48 | 3,432.84 | 3,643.64 | 3,782.23 | 2,236.81 |
> 2,278.52 |
> | 48 | 4,466.56 | 5,174.72 | 5,401.95 | 5,621.41 | 4,926.30 |
> 3,026.58 |
>
> After:
>
> | Threads | N1 | N2 | V1 | V2 | Xeon |
> Epyc |
> |---------|-------|-------|-------|-------|-------|-------|
> | 1 | 32.41 | 32.11 | 34.43 | 31.32 | 27.94 | 9.82 |
> | 2 | 32.64 | 33.72 | 35.11 | 31.30 | 28.02 | 9.81 |
> | 4 | 32.71 | 36.84 | 34.67 | 31.35 | 28.12 | 10.49 |
> | 8 | 58.22 | 31.60 | 36.87 | 31.72 | 47.09 |...
src/java.base/share/classes/jdk/internal/foreign/SharedSession.java line 89:
> 87: @ForceInline
> 88: private int getCounter() {
> 89: return Thread.currentThread().hashCode() & mask;
Maybe use [`System::identityHashCode`] here instead, as the `hashCode()`
method of a `Thread` can be overridden by subclasses.
Suggestion:
return System.identityHashCode(Thread.currentThread()) & mask;
[`System::identityHashCode`]:
https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/System.html#identityHashCode%28java.lang.Object%29
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/28575#discussion_r2594828923