Memory Segment efficient array handling
Ty Young
youngty1997 at gmail.com
Thu Apr 1 04:58:07 UTC 2021
It's kind of a dirty little secret, but FMA just uses Unsafe under the hood:
https://github.com/openjdk/panama-foreign/blob/5a3a9fe4a9f320515f2bef9b22ce0a004f99b260/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java#L134
https://github.com/openjdk/panama-foreign/blob/5a3a9fe4a9f320515f2bef9b22ce0a004f99b260/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template#L128
(side note: someone forgot @override on copyFrom in
AbstractMemorySegmentImpl)
On the issue of alignment, while slicing is awful in regards to on-heap
allocations, if a MemorySegment represents a distinct type(number,
pointer, array, struct, union, etc) I think it's OK to do it*. The
amount of arguments that you have to pass to use that static method and
its complexity is kind of egregious as-is the amount of overloads for
everything in MemoryAccess.
*except arrays and array-like struct where you can just use VarHandle
offsets.
On 3/31/21 10:26 PM, leerho wrote:
> Ty,
> Your idea (with a few corrections) implemented in Java might look like
> this:
>
> *public* *static* *void* putIntArray(*int*[] srcArr, *int*
> srcIndex, *int* numInts,
>
> MemorySegment dstSeg, *long* dstOffsetBytes) {
>
> *for* (*int* i = 0; i < numInts; i++) {
>
> MemoryAccess./setIntAtOffset/(dstSeg, dstOffsetBytes + 4 * i,
> srcArr[srcIndex + i]);
>
> }
>
> }
>
> I have to use "setIntAtOffset" because I can't assume that the
> integers in the segment are integer aligned.
>
> Thanks again!
> Lee.
>
> On Wed, Mar 31, 2021 at 8:05 PM leerho <leerho at gmail.com
> <mailto:leerho at gmail.com>> wrote:
>
> Ty,
> Thanks, that is an excellent suggestion. It is my hope, however,
> to get methods with similar method signatures implemented
> somewhere in FMA. If the work was done on the C++ side it should
> be even more efficient than trying to do the loop in java.
> Especially if the data to be put or extracted is very large, the
> copy loop should be done as a low-level bulk copy.
>
> Lee.
>
>
>
>
> On Wed, Mar 31, 2021 at 7:08 PM Ty Young <youngty1997 at gmail.com
> <mailto:youngty1997 at gmail.com>> wrote:
>
> It would probably be more efficient to skip the whole
> MemorySegment.ofArray() and MemorySegment.copyFrom bits and
> just do:
>
>
> public static void arrayCopy(int[] javaArray, int index,
> MemorySegment
> destination, int offset)
> {
> for(int i = index; i < javaArray.length; i++)
> MemoryAccess.setIntAtIndex(destination, offset + i,
> javaArray[i]);
> }
>
>
> Because you already have the array of ints in a standard Java
> array, If
> you do what you're doing, you're creating on-heap objects that
> are then
> GC'd right away and wasting time slicing segments to each
> element's
> exact size to copy the data. Slicing should really be avoided
> when
> possible. My JavaFX application has to slice MemorySegments
> and it's one
> of the biggest sources of on-heap allocations according to
> Java Mission
> Control.
>
>
> 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