[foreign-memaccess] Add direct access (DAX) support to MappedMemorySegment
Marcel Käufler
marcel.kaeufler at hhu.de
Sat Apr 3 21:38:50 UTC 2021
Hi all,
I'm currently working with the Foreign Memory Access API and (emulated)
non-volatile RAM. With JDK 14 support for non-volatile memory was added
to MappedByteBuffers by mapping with ExtendedMapMode.READ_ONLY_SYNC or
ExtendedMapMode.READ_WRITE_SYNC.
Calling force() on the MappedByteBuffer will then just flush caches
instead of invoking msync and also reading won't use the page cache.
MappedMemorySegment already builds on the same logic and would be
NVM-aware but unfortunately mapping with an ExtendedMapMode is currently
not supported. The only way to map a MemorySegment in sync mode is to
first map a ByteBuffer and then use MemorySegment.ofByteBuffer() which
of course comes with some limitations.
From my observation the only issue is the openOptions() method in
MappedMemorySegmentImpl which does not consider the two SYNC modes.
After adding the modes to the respective conditions I was able call
`MemorySegment.mapFile(path, offset, size,
ExtendedMapMode.READ_WRITE_SYNC)` and it worked just as expected.
private static OpenOption[] openOptions(FileChannel.MapMode mapMode) {
if (mapMode == FileChannel.MapMode.READ_ONLY || mapMode ==
ExtendedMapMode.READ_ONLY_SYNC) {
return new OpenOption[] { StandardOpenOption.READ };
} else if (mapMode == FileChannel.MapMode.READ_WRITE || mapMode
== FileChannel.MapMode.PRIVATE || mapMode ==
ExtendedMapMode.READ_WRITE_SYNC) {
return new OpenOption[] { StandardOpenOption.READ,
StandardOpenOption.WRITE };
} else {
throw new UnsupportedOperationException("Unsupported map
mode: " + mapMode);
}
}
Is there anything against adding this?
Additionally MappedByteBuffer offers a `force(int index, int length)`
method whereas for MappedMemorySegments there's only a
`MappedMemorySegments.force(memorySegment)`.
In DAX mode the later is horribly slow because it iterates over the
whole segment in 64 byte steps to evict cache lines. A targeted force
can already be accomplished by slicing first and calling force on the
slice. When working on NVM and frequently flushing cache lines, this
creates a lot of throwaway MemorySegments for the gc to collect.
Admitted, this overhead is probably negligible compared to the NVM write
but a method with offset and length would be nice to match the
MappedByteBuffer API.
Everything needed is also already present and it would be easy to add a
`force(MemorySegment segment, long offset, long length)`:
In MappedMemorySegments:
public static void force(MemorySegment segment, long offset, long
length) {
toMappedSegment(segment).force(offset, length);
}
In MappedMemorySegmentImpl:
public void force(long offset, long length) {
checkBounds(offset, length); // used from
AbstractMemorySegmentImpl if made protected (out-of-bounds message with
"new offset" and "new length" doesn't fit exactly, thought)
SCOPED_MEMORY_ACCESS.force(scope, unmapper.fileDescriptor(),
min, unmapper.isSync(), offset, length);
}
Thoughts on this?
Best Regards
Marcel
More information about the panama-dev
mailing list