Memory Segment efficient array handling

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Apr 1 13:44:35 UTC 2021


igger sizes, bulk copy wins (which is why System.arrayCopy doesn't - 
always - do a loop).
>
>
> To be clear, I wasn't saying that looping was better. I was saying 
> that the amount of code you need to go through to get to the point 
> where you could do a bulk copy in the original code snippets 
> *probably* isn't efficient because of the wrapping and slicing among 
> other things(e.g. internal checks).
>
>
> Regarding the actual GC cost of wrapping and slicing and immutable 
> types in general: there is zero indication as an end programmer as to 
> whether or not the JVM is going to apply optimizations AFAIK. Netbeans 
> isn't yelling at me saying "Hey, you should write code this way to 
> take advantage of JVM optimization <X> in version <Y>!". Most of the 
> people who seem to have any clue what optimizations the JVM can and 
> will apply at any given time are the people who actively work on it, 
> and even then you/they throw out vague qualifiers like "most" or say 
> that what optimizations the JVM actually applies depends on a given 
> Java version. Is the expectation that people have to buy and read a 
> metaphorical "Java <X> for dummies"book every new Java release just so 
> they know what the current set of optimizations are and in what 
> situations they do and don't come into play?
>
>
> Maybe it's a dumb question but: why should anyone depend on the 
> **possibility** that the JVM **might** optimize objects that are 
> allocated and then discarded right away?


Well, why should anyone second guess the VM and prematurely optimize 
code that doesn't need optimizing? This is something that happens a lot, 
I see people writing very low level code in the hope that that would 
perform better, when the higher-level code performs just as well.

The benchmark I shared shows (with hard evidence, as opposed to 
speculation), that there's no difference between a straight Unsafe call 
and doing the slicing + copyFrom.

If evidence emerges which point to the contrary, we will deal with that, 
of course - but that just doesn't seem to be the case.

Again: this thread has nothing (or little) to do with performance and 
everything to do with usability. Let's keep the performance/GC side out 
of the equation, please.

As for the usability bit, I've filed this:

https://bugs.openjdk.java.net/browse/JDK-8264594

We're happy to accept contributions in that direction!

Maurizio



>
>
>>
>> Maurizio
>>
>>>
>>>
>>> That said, maybe it wouldn't be a bad idea to do add overloads for 
>>> copyFrom that take an index and offset into account for when the 
>>> source is a MemorySegment.
>>>
>>>
>>> On 3/31/21 7:41 PM, leerho wrote:
>>>> Folks,
>>>>
>>>> I am in the process of refactoring our code to use FMA (from JDK16) 
>>>> in our
>>>> application.  But what I find missing is the ability to do efficient
>>>> getting and putting of arrays with MemorySegments.
>>>>
>>>> What I need to do often is to place part of an existing array into a
>>>> segment at a specific offset and the reverse; getting an array of 
>>>> elements
>>>> from a segment at a specific offset and placing it into an existing 
>>>> array
>>>> at a specific offset.  I have looked closely at MemoryAccess and 
>>>> the latest
>>>> ByteBuffer, but I have not found anything quite as flexible as the
>>>> following.
>>>>
>>>> What I have ended up doing is creating an entire class of array 
>>>> methods
>>>> like the following:
>>>>
>>>> public class MemoryArrays {
>>>>>    public static void putIntArray(int[] srcArr, long srcIndex, long
>>>>> numInts,
>>>>>        MemorySegment dstSeg, long dstOffsetBytes) {
>>>>>      MemorySegment srcSeg = MemorySegment.ofArray(srcArr);
>>>>>      MemorySegment srcSegSlice = srcSeg.asSlice(srcIndex << 2, 
>>>>> numInts <<
>>>>> 2);
>>>>>      MemorySegment dstSegSlice = dstSeg.asSlice(dstOffsetBytes, 
>>>>> numInts <<
>>>>> 2);
>>>>>      dstSegSlice.copyFrom(srcSegSlice);
>>>>>    }
>>>>>
>>>>>    /* ...Same as above for all primitive types... */
>>>>>
>>>>>    public static void getIntArray(MemorySegment srcSeg, long
>>>>> srcOffsetBytes,
>>>>>        int[] dstArr, long dstIndex, long numInts) {
>>>>>      MemorySegment srcSegSlice = srcSeg.asSlice(srcOffsetBytes, 
>>>>> numInts <<
>>>>> 2);
>>>>>      MemorySegment dstSeg = MemorySegment.ofArray(dstArr);
>>>>>      MemorySegment dstSegSlice = dstSeg.asSlice(dstIndex << 2, 
>>>>> numInts <<
>>>>> 2);
>>>>>      dstSegSlice.copyFrom(srcSegSlice);
>>>>>    }
>>>>>
>>>>>    /* ...Same as above for all primitive types... */
>>>>> }
>>>>>
>>>> I would think that if these methods were built-in to FMA either as a
>>>> separate class or included in MemoryAccess, it would be so much more
>>>> efficient.  All of these separate
>>>> calls to MemorySegment could be eliminated and the entire method 
>>>> inlined
>>>> with a few lines of C++ code.
>>>>
>>>> If Panama is interested I would be happy to contribute such a class.
>>>>
>>>> Lee.


More information about the panama-dev mailing list