Re: RFR: 8254162: Implementation of Foreign-Memory Access API (Third Incubator) [v6]
On Mon, 12 Oct 2020 18:06:55 GMT, Maurizio Cimadamore wrote: >> Build changes look good. > > I've just uploaded a biggie update to the foreign memory access support. > While doing performance evaluation, we have > realized that mixing a multi-level hierarchy (`MappedMemorySegment extends > MemorySegments`) with exact invoke semantics > of `VarHandle` and `MethodHandle` is not a good match and can lead to great > performance degradation for seemingly > "correct" code. While some of this can be attributed to the `VarHandle` API, > or to the fact that the so called > "generic" invocation path should not be that slow in case where the > parameters are clearly related, it seems smelly > that a primitive API such as `MemorySegment` should give raise to such > issues. We have therefore decided to drop the > `MappedMemorySegment` - this means that there's only one memory segment type > users can deal with: `MemorySegment` - and > no chance for mistakes. Of course `MappedMemorySegment` has been primarily > introduces to allow for operations which > were previously possible on `MappedByteBuffer` such as `force`. To support > these use cases, a separate class has been > introduced, namely `MappedMemorySegments` (note the trailing `S`). This class > contains a bunch of static methods which > can be used to achieve the desired effects, without polluting the > `MemorySegment` API. A new method has been added on > `MemorySegment` which returns an optional file descriptor; this might be > useful for clients which want to guess whether > a segment is in fact a mapped segment, or if they need (e.g. in Windows) the > file descriptor to do some other kind of > low level op. I think this approach is more true to the goals and spirit of > the Foreign Memory Access API, and it also > offers some ways to improve over the existing API: for instance, the only > reason why the `MemorySegment::spliterator` > method was a static method was that we needed inference, so that we could > return either a `Spliterator` > or a `Spliterator`. All of that is gone now, so the > method can return to be what it morally always > has been: an instance method on `MemorySegment`. Updated javadoc: > http://cr.openjdk.java.net/~mcimadamore/8254162_v2/javadoc/jdk/incubator/foreign/package-summary.html > Updated > specdiff: > http://cr.openjdk.java.net/~mcimadamore/8254162_v2/specdiff/overview-summary.html The latest iteration addresses a comment raised during CSR review; more specifically, the `MemoryAccess` class has several variants of dereference methods - e.g. `getInt`, `getInt_LE`, `getInt_BE`, to support different endianness. The comment was to just have two overloads, e.g. `getInt` and `getInt(ByteOrder)` instead of three. I've implemented the suggestion in this new iteration, as I think it makes the API a bit more compact. - PR: https://git.openjdk.java.net/jdk/pull/548
Re: RFR: 8254162: Implementation of Foreign-Memory Access API (Third Incubator) [v6]
On Mon, 12 Oct 2020 11:42:04 GMT, Magnus Ihse Bursie wrote: >> Maurizio Cimadamore has updated the pull request incrementally with one >> additional commit since the last revision: >> >> Tweak referenced to MemoryAddressProxy in Utils.java > > Build changes look good. I've just uploaded a biggie update to the foreign memory access support. While doing performance evaluation, we have realized that mixing a multi-level hierarchy (`MappedMemorySegment extends MemorySegments`) with exact invoke semantics of `VarHandle` and `MethodHandle` is not a good match and can lead to great performance degradation for seemingly "correct" code. While some of this can be attributed to the `VarHandle` API, or to the fact that the so called "generic" invocation path should not be that slow in case where the parameters are clearly related, it seems smelly that a primitive API such as `MemorySegment` should give raise to such issues. We have therefore decided to drop the `MappedMemorySegment` - this means that there's only one memory segment type users can deal with: `MemorySegment` - and no chance for mistakes. Of course `MappedMemorySegment` has been primarily introduces to allow for operations which were previously possible on `MappedByteBuffer` such as `force`. To support these use cases, a separate class has been introduced, namely `MappedMemorySegments` (note the trailing `S`). This class contains a bunch of static methods which can be used to achieve the desired effects, without polluting the `MemorySegment` API. A new method has been added on `MemorySegment` which returns an optional file descriptor; this might be useful for clients which want to guess whether a segment is in fact a mapped segment, or if they need (e.g. in Windows) the file descriptor to do some other kind of low level op. I think this approach is more true to the goals and spirit of the Foreign Memory Access API, and it also offers some ways to improve over the existing API: for instance, the only reason why the `MemorySegment::spliterator` method was a static method was that we needed inference, so that we could return either a `Spliterator` or a `Spliterator`. All of that is gone now, so the method can return to be what it morally always has been: an instance method on `MemorySegment`. Updated javadoc: http://cr.openjdk.java.net/~mcimadamore/8254162_v2/javadoc/jdk/incubator/foreign/package-summary.html Updated specdiff: http://cr.openjdk.java.net/~mcimadamore/8254162_v2/specdiff/overview-summary.html - PR: https://git.openjdk.java.net/jdk/pull/548
Re: RFR: 8254162: Implementation of Foreign-Memory Access API (Third Incubator) [v6]
On Mon, 12 Oct 2020 10:50:48 GMT, Maurizio Cimadamore wrote: >> This patch contains the changes associated with the third incubation round >> of the foreign memory access API incubation >> (see JEP 393 [1]). This iteration focus on improving the usability of the >> API in 3 main ways: >> * first, by providing a way to obtain truly *shared* segments, which can be >> accessed and closed concurrently from >> multiple threads >> * second, by providing a way to register a memory segment against a >> `Cleaner`, so as to have some (optional) guarantee >> that the memory will be deallocated, eventually >> * third, by not requiring users to dive deep into var handles when they >> first pick up the API; a new `MemoryAccess` class >> has been added, which defines several useful dereference routines; these >> are really just thin wrappers around memory >> access var handles, but they make the barrier of entry for using this API >> somewhat lower. >> >> A big conceptual shift that comes with this API refresh is that the role of >> `MemorySegment` and `MemoryAddress` is not >> the same as it used to be; it used to be the case that a memory address >> could (sometimes, not always) have a back link >> to the memory segment which originated it; additionally, memory access var >> handles used `MemoryAddress` as a basic unit >> of dereference. This has all changed as per this API refresh; now a >> `MemoryAddress` is just a dumb carrier which >> wraps a pair of object/long addressing coordinates; `MemorySegment` has >> become the star of the show, as far as >> dereferencing memory is concerned. You cannot dereference memory if you >> don't have a segment. This improves usability >> in a number of ways - first, it is a lot easier to wrap native addresses >> (`long`, essentially) into a `MemoryAddress`; >> secondly, it is crystal clear what a client has to do in order to >> dereference memory: if a client has a segment, it can >> use that; otherwise, if the client only has an address, it will have to >> create a segment *unsafely* (this can be done >> by calling `MemoryAddress::asSegmentRestricted`). A list of the API, >> implementation and test changes is provided >> below. If you have any questions, or need more detailed explanations, I >> (and the rest of the Panama team) will be >> happy to point at existing discussions, and/or to provide the feedback >> required. A big thank to Erik Osterlund, >> Vladimir Ivanov and David Holmes, without whom the work on shared memory >> segment would not have been possible; also I'd >> like to thank Paul Sandoz, whose insights on API design have been very >> helpful in this journey. Thanks Maurizio >> Javadoc: >> http://cr.openjdk.java.net/~mcimadamore/8254162_v1/javadoc/jdk/incubator/foreign/package-summary.html >> Specdiff: >> >> http://cr.openjdk.java.net/~mcimadamore/8254162_v1/specdiff/jdk/incubator/foreign/package-summary.html >> >> CSR: >> >> https://bugs.openjdk.java.net/browse/JDK-8254163 >> >> >> >> ### API Changes >> >> * `MemorySegment` >> * drop factory for restricted segment (this has been moved to >> `MemoryAddress`, see below) >> * added a no-arg factory for a native restricted segment representing >> entire native heap >> * rename `withOwnerThread` to `handoff` >> * add new `share` method, to create shared segments >> * add new `registerCleaner` method, to register a segment against a cleaner >> * add more helpers to create arrays from a segment e.g. `toIntArray` >> * add some `asSlice` overloads (to make up for the fact that now segments >> are more frequently used as cursors) >> * rename `baseAddress` to `address` (so that `MemorySegment` can implement >> `Addressable`) >> * `MemoryAddress` >> * drop `segment` accessor >> * drop `rebase` method and replace it with `segmentOffset` which returns >> the offset (a `long`) of this address relative >> to a given segment >> * `MemoryAccess` >> * New class supporting several static dereference helpers; the helpers are >> organized by carrier and access mode, where a >> carrier is one of the usual suspect (a Java primitive, minus `boolean`); >> the access mode can be simple (e.g. access >> base address of given segment), or indexed, in which case the accessor >> takes a segment and either a low-level byte >> offset,or a high level logical index. The classification is reflected in >> the naming scheme (e.g. `getByte` vs. >> `getByteAtOffset` vs `getByteAtIndex`). >> * `MemoryHandles` >> * drop `withOffset` combinator >> * drop `withStride` combinator >> * the basic memory access handle factory now returns a var handle which >> takes a `MemorySegment` and a `long` - from which >> it is easy to derive all the other handles using plain var handle >> combinators. >> * `Addressable` >> * This is a new interface which is attached to entities which can be >> projected to a `MemoryAddress`. For now, both >>
Re: RFR: 8254162: Implementation of Foreign-Memory Access API (Third Incubator) [v6]
> This patch contains the changes associated with the third incubation round of > the foreign memory access API incubation > (see JEP 393 [1]). This iteration focus on improving the usability of the API > in 3 main ways: > * first, by providing a way to obtain truly *shared* segments, which can be > accessed and closed concurrently from > multiple threads > * second, by providing a way to register a memory segment against a > `Cleaner`, so as to have some (optional) guarantee > that the memory will be deallocated, eventually > * third, by not requiring users to dive deep into var handles when they first > pick up the API; a new `MemoryAccess` class > has been added, which defines several useful dereference routines; these > are really just thin wrappers around memory > access var handles, but they make the barrier of entry for using this API > somewhat lower. > > A big conceptual shift that comes with this API refresh is that the role of > `MemorySegment` and `MemoryAddress` is not > the same as it used to be; it used to be the case that a memory address could > (sometimes, not always) have a back link > to the memory segment which originated it; additionally, memory access var > handles used `MemoryAddress` as a basic unit > of dereference. This has all changed as per this API refresh; now a > `MemoryAddress` is just a dumb carrier which > wraps a pair of object/long addressing coordinates; `MemorySegment` has > become the star of the show, as far as > dereferencing memory is concerned. You cannot dereference memory if you don't > have a segment. This improves usability > in a number of ways - first, it is a lot easier to wrap native addresses > (`long`, essentially) into a `MemoryAddress`; > secondly, it is crystal clear what a client has to do in order to dereference > memory: if a client has a segment, it can > use that; otherwise, if the client only has an address, it will have to > create a segment *unsafely* (this can be done > by calling `MemoryAddress::asSegmentRestricted`). A list of the API, > implementation and test changes is provided > below. If you have any questions, or need more detailed explanations, I (and > the rest of the Panama team) will be > happy to point at existing discussions, and/or to provide the feedback > required. A big thank to Erik Osterlund, > Vladimir Ivanov and David Holmes, without whom the work on shared memory > segment would not have been possible; also I'd > like to thank Paul Sandoz, whose insights on API design have been very > helpful in this journey. Thanks Maurizio > Javadoc: > http://cr.openjdk.java.net/~mcimadamore/8254162_v1/javadoc/jdk/incubator/foreign/package-summary.html > Specdiff: > > http://cr.openjdk.java.net/~mcimadamore/8254162_v1/specdiff/jdk/incubator/foreign/package-summary.html > > CSR: > > https://bugs.openjdk.java.net/browse/JDK-8254163 > > > > ### API Changes > > * `MemorySegment` > * drop factory for restricted segment (this has been moved to > `MemoryAddress`, see below) > * added a no-arg factory for a native restricted segment representing > entire native heap > * rename `withOwnerThread` to `handoff` > * add new `share` method, to create shared segments > * add new `registerCleaner` method, to register a segment against a cleaner > * add more helpers to create arrays from a segment e.g. `toIntArray` > * add some `asSlice` overloads (to make up for the fact that now segments > are more frequently used as cursors) > * rename `baseAddress` to `address` (so that `MemorySegment` can implement > `Addressable`) > * `MemoryAddress` > * drop `segment` accessor > * drop `rebase` method and replace it with `segmentOffset` which returns > the offset (a `long`) of this address relative > to a given segment > * `MemoryAccess` > * New class supporting several static dereference helpers; the helpers are > organized by carrier and access mode, where a > carrier is one of the usual suspect (a Java primitive, minus `boolean`); > the access mode can be simple (e.g. access > base address of given segment), or indexed, in which case the accessor > takes a segment and either a low-level byte > offset,or a high level logical index. The classification is reflected in > the naming scheme (e.g. `getByte` vs. > `getByteAtOffset` vs `getByteAtIndex`). > * `MemoryHandles` > * drop `withOffset` combinator > * drop `withStride` combinator > * the basic memory access handle factory now returns a var handle which > takes a `MemorySegment` and a `long` - from which > it is easy to derive all the other handles using plain var handle > combinators. > * `Addressable` > * This is a new interface which is attached to entities which can be > projected to a `MemoryAddress`. For now, both > `MemoryAddress` and `MemorySegment` implement it; we have plans, with JEP > 389 [2] to add more implementations. Clients > can largely ignore this interface, which