Setting a value to a MemorySegment slower with VarHandle
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Tue Nov 1 10:47:49 UTC 2022
Hi Daniele,
The first suggestion would be to use a `final static` field as a holder
for the VarHandle. This is the same as what happens with MethodHandles -
the JVM can apply more optimizations if the VarHandle is a known constant.
Alternatively, you can just use
`MemorySegment::setAtIndex(ValueLayout.JAVA_INT, index)`, which will do
the right thing, with the correct performance model.
Secondly, note that your benchmark is heavily dependent on
On-Stack-Replacement - that is, the method being optimized is the same
one being executed. This sometimes can lead to suboptimal optimizations
(which is one of the things JMH tries to avoid). Not sure how much that
would impact in this case.
We do have JMH benchmarks with mapped buffers:
https://github.com/openjdk/panama-foreign/blob/foreign-memaccess%2Babi/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantMapped.java
These show that memory segment access is as fast as byte buffer and/or
Unsafe.
Thanks
Maurizio
On 28/10/2022 22:59, Daniele Guiducci wrote:
> Hello,
>
> I'm running some tests comparing the performance of the various
> methods available to set a value in a MemorySegment.
>
> Based on a simple benchmark I wrote, VarHandle seems to be the slowest
> one, which is odd to me.
>
> This is the output of the benchmark:
>
> * Manual offset set; Total time 147
> * VarHandle; Total time 3197
> * Method Handle; Total time 767
>
> I'm testing this from a MacOS Air M2 (arm chip). I also ran other
> tests trying to warm up the virtual machine but I didn't get much
> improvements.
>
> And this is the code. I didn't use microbenchmarking but the result
> wouldn't change:
> public static void main(String[] args) throws Throwable {
> long elementCount = 200_000_000;
> var testFile = Path.of("test.data");
> FileChannel fc = FileChannel.open(testFile,
> StandardOpenOption.CREATE,
> StandardOpenOption.READ,
> StandardOpenOption.WRITE
> );
> var segment = fc.map(FileChannel.MapMode.READ_WRITE, 0,
> elementCount * Integer.BYTES, MemorySession.global());
>
> MemoryLayout memoryLayout = MemoryLayout.sequenceLayout(
> elementCount, ValueLayout.JAVA_INT.withName("counter")
> );
>
> VarHandle varHandle =
> memoryLayout.varHandle(MemoryLayout.PathElement.sequenceElement());
> var arrayMethodHandle =
> memoryLayout.byteOffsetHandle(MemoryLayout.PathElement.sequenceElement());
>
>
> // Init file Manually
> for (int i = 0; i < elementCount; i++) {
> segment.set(ValueLayout.JAVA_INT, i * 4L, 99);
> }
>
> long startTime;
>
>
> startTime = System.currentTimeMillis();
> for (int i = 0; i < elementCount; i++) {
> segment.set(ValueLayout.JAVA_INT, i * Integer.BYTES, 33);
> }
> System.out.println("Manual offset set; Total time " +
> (System.currentTimeMillis() - startTime));
>
>
> startTime = System.currentTimeMillis();
> for (int i = 0; i < elementCount; i++) {
> varHandle.set(segment, (long) i, 10);
> }
> System.out.println("VarHandle; Total time " +
> (System.currentTimeMillis() - startTime));
>
>
> startTime = System.currentTimeMillis();
> for (int i = 0; i < elementCount; i++) {
> // User method handle to calculate offset
> long offset = (long) arrayMethodHandle.invokeExact((long) i);
> segment.set(ValueLayout.JAVA_INT, offset, 10);
> }
> System.out.println("Method Handle; Total time " +
> (System.currentTimeMillis() - startTime));
>
> fc.close();
> Files.delete(testFile);
> }
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20221101/004196cb/attachment-0001.htm>
More information about the panama-dev
mailing list