On Sat, 6 Dec 2025 12:55:37 GMT, ExE Boss <[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...
>
> 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

Thanks - that's a good suggestion.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/28575#discussion_r2605783455

Reply via email to