3030import com .evolvedbinary .jnibench .consbench .NarSystem ;
3131import com .evolvedbinary .jnibench .jmhbench .cache .*;
3232import com .evolvedbinary .jnibench .jmhbench .common .*;
33+ import io .netty .buffer .ByteBuf ;
3334import io .netty .buffer .PooledByteBufAllocator ;
35+ import java .lang .foreign .Arena ;
36+ import java .lang .foreign .FunctionDescriptor ;
37+ import java .lang .foreign .Linker ;
38+ import java .lang .foreign .MemorySegment ;
39+ import java .lang .foreign .SymbolLookup ;
40+ import java .lang .foreign .ValueLayout ;
41+ import java .lang .invoke .MethodHandle ;
42+ import java .nio .ByteBuffer ;
43+ import java .text .SimpleDateFormat ;
44+ import java .util .Date ;
45+ import java .util .concurrent .TimeUnit ;
46+ import java .util .logging .Logger ;
3447import org .openjdk .jmh .annotations .*;
3548import org .openjdk .jmh .infra .Blackhole ;
3649import org .openjdk .jmh .runner .Runner ;
3750import org .openjdk .jmh .runner .RunnerException ;
3851import org .openjdk .jmh .runner .options .Options ;
3952import org .openjdk .jmh .runner .options .OptionsBuilder ;
40- import io .netty .buffer .ByteBuf ;
41-
42- import java .nio .ByteBuffer ;
43- import java .text .SimpleDateFormat ;
44- import java .util .Date ;
45- import java .util .concurrent .TimeUnit ;
46- import java .util .logging .Logger ;
4753
4854/**
4955 * Benchmark getting byte arrays from native methods.
@@ -58,8 +64,24 @@ public class PutJNIBenchmark {
5864
5965 private static final Logger LOG = Logger .getLogger (GetJNIBenchmark .class .getName ());
6066
67+ private static final MethodHandle PUT_FROM_MEMORY_SEGMENT_HANDLE ;
68+
6169 static {
6270 NarSystem .loadLibrary ();
71+
72+ // 2. Initialize the Linker and Lookup
73+ Linker linker = Linker .nativeLinker ();
74+ SymbolLookup loaderLookup = SymbolLookup .loaderLookup ();
75+
76+ // 3. Find the symbol and create the Downcall Handle once
77+ PUT_FROM_MEMORY_SEGMENT_HANDLE = loaderLookup .find ("putFromMemorySegment" )
78+ .map (symbol -> linker .downcallHandle (symbol ,
79+ FunctionDescriptor .of (
80+ ValueLayout .JAVA_INT ,
81+ ValueLayout .ADDRESS ,
82+ ValueLayout .ADDRESS ,
83+ ValueLayout .JAVA_INT )))
84+ .orElseThrow ();
6385 }
6486
6587 @ State (Scope .Benchmark )
@@ -90,6 +112,8 @@ public static class GetJNIBenchmarkState {
90112
91113 String keyBase ;
92114 byte [] keyBytes ;
115+ MemorySegment keyMemorySegment ;
116+ private Arena benchmarkArena ;
93117
94118 JMHCaller caller ;
95119
@@ -99,14 +123,19 @@ public void setup() {
99123
100124 keyBase = "testKeyWithReturnValueSize" + String .format ("%07d" , valueSize ) + "Bytes" ;
101125
126+ benchmarkArena = Arena .ofShared ();
127+
102128 keyBytes = keyBase .getBytes ();
129+ keyMemorySegment = benchmarkArena .allocateArray (ValueLayout .JAVA_BYTE , keyBytes );
103130
104131 writePreparation = AllocationCache .Prepare .valueOf (preparation );
105132 }
106133
107134 @ TearDown
108135 public void tearDown () {
109-
136+ if (benchmarkArena != null ) {
137+ benchmarkArena .close ();
138+ }
110139 }
111140 }
112141
@@ -117,6 +146,7 @@ public static class GetJNIThreadState {
117146 private final UnsafeBufferCache unsafeBufferCache = new UnsafeBufferCache ();
118147 private final ByteArrayCache byteArrayCache = new ByteArrayCache ();
119148 private final IndirectByteBufferCache indirectByteBufferCache = new IndirectByteBufferCache ();
149+ private final MemorySegmentCache memorySegmentCache = new MemorySegmentCache ();
120150 private final PooledByteBufAllocator pooledByteBufAllocator = PooledByteBufAllocator .DEFAULT ;
121151 private final NettyByteBufCache nettyByteBufCache = new NettyByteBufCache ();
122152
@@ -152,6 +182,9 @@ public void setup(GetJNIBenchmarkState benchmarkState, Blackhole blackhole) {
152182 case "putFromByteArrayCritical" :
153183 byteArrayCache .setup (valueSize , cacheSize , benchmarkState .cacheEntryOverhead , benchmarkState .writePreparation , blackhole );
154184 break ;
185+ case "putFromMemorySegment" :
186+ memorySegmentCache .setup (valueSize , cacheSize , benchmarkState .cacheEntryOverhead , benchmarkState .writePreparation , blackhole );
187+ break ;
155188 default :
156189 throw new RuntimeException ("Don't know how to setup() for benchmark: " + benchmarkState .caller .benchmarkMethod );
157190 }
@@ -184,6 +217,9 @@ public void tearDown(GetJNIBenchmarkState benchmarkState) {
184217 case "putFromByteArrayCritical" :
185218 byteArrayCache .tearDown ();
186219 break ;
220+ case "putFromMemorySegment" :
221+ memorySegmentCache .tearDown ();
222+ break ;
187223 default :
188224 throw new RuntimeException ("Don't know how to tearDown() for benchmark: " + benchmarkState .caller .benchmarkMethod );
189225 }
@@ -196,6 +232,26 @@ public void buffersOnlyDirectByteBufferFromUnsafe(GetJNIThreadState threadState)
196232 threadState .unsafeBufferCache .release (unsafeBuffer );
197233 }
198234
235+ @ Benchmark
236+ public void putFromMemorySegment (GetJNIBenchmarkState benchmarkState , GetJNIThreadState threadState ,
237+ Blackhole blackhole ) {
238+ final var segment = threadState .memorySegmentCache .acquire ();
239+ threadState .memorySegmentCache .prepareBuffer (segment , benchmarkState .fillByte );
240+
241+ try {
242+ final var size = (int ) PUT_FROM_MEMORY_SEGMENT_HANDLE .invokeExact (
243+ benchmarkState .keyMemorySegment , // Pre-allocated segment for key
244+ segment ,
245+ benchmarkState .valueSize
246+ );
247+ blackhole .consume (size );
248+ } catch (Throwable e ) {
249+ throw new RuntimeException (e );
250+ }
251+
252+ threadState .memorySegmentCache .release (segment );
253+ }
254+
199255 @ Benchmark
200256 public void putFromDirectByteBuffer (GetJNIBenchmarkState benchmarkState , GetJNIThreadState threadState , Blackhole blackhole ) {
201257 ByteBuffer byteBuffer = threadState .directByteBufferCache .acquire ();
0 commit comments