dissecting the Scope API
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Sat Dec 22 22:02:27 UTC 2018
Hi David,
yes, I knew about these articles as Alex pointed me at them few months
ago - but thanks for the reference.
For the records, Loom is also exploring similar directions for managing
lifecycle of groups of logically connected fibers.
Maurizio
On 22/12/2018 06:53, David Holmes wrote:
> Hi Maurizio,
>
> On a casual read aspects of this are sounding like RTSJ MemoryAreas
> [1][2][3], which define allocation contexts which allow for a
> bounded/scoped lifetime (and very strong rules about allowing things
> to be referenced from other scopes).
>
> Are you aware of those? John may have mentioned them.
>
> Cheers,
> David
>
> [1] http://www.rtsj.org/specjavadoc/book_index.html
> [2]
> https://docs.oracle.com/javase/realtime/doc_2.1/release/rtsj-docs/javax/realtime/MemoryArea.html
> [3] http://janvitek.org/pubs/isorc04.pdf "Real-Time Java Scoped
> Memory: Design Patterns and Semantics", by Vitek, Pizlo, Fox & Holmes
>
>
> On 22/12/2018 10:18 am, Maurizio Cimadamore wrote:
>> Hi,
>> as mentioned in a recent email, I think the Scope API is conflating
>> several aspects together, which makes it difficult to discuss it
>> and/or evolve it into a more stable API. This email is an attempt at
>> teasing apart the various aspects of the Scope API; while it's not
>> meant to be a full proposal, I think there are many ideas in here
>> worthy of more consideration. Much of the credits for the ideas in
>> here go to Steve Dohrmann from Intel and Jorn Vernee who recently
>> started a discussion on this [1]; Henry Jen also provided some
>> insights into the dual nature played by the Scope API.
>>
>> So, before jumping into some pseudocode, let's review some basic key
>> points:
>>
>> * I believe Scope is condensing two aspects: it has an allocation
>> interface (Scope::allocateXYZ), but it also serves as a life-cycle
>> management. While in the end we might (or not) end up to conflate the
>> two, let's try to keep them separated for now
>>
>> * Let's try to get there in layers (as we did for the SystemABI);
>> there are clearly low level allocators - e.g. things that just give
>> you a slab of memory - called memory regions - and high-level
>> allocators, e.g. things that can allocate user defined data (structs,
>> arrays, etc.)
>>
>> * We'd like the approach to scale, if possible, to different kind of
>> memories (heap, offheap, NVM, ...)
>>
>> * Let's double down on the Pointer abstraction to do the memory
>> dereference; e.g. let's not add methods to a memory abstraction a la
>> Unsafe (get/putLong, ...) instead, let's have a way to get a Pointer
>> out of a memory region
>>
>> So, let's start... the first thing we need is something that creates
>> memory regions:
>>
>> interface MemoryStore {
>> MemoryRegion allocate(long size);
>> MemoryRegion allocate(Access access, long size);
>> void free(MemoryRegion region);
>>
>> interface Access {
>> READ, WRITE, READ_WRITE;
>> }
>>
>> static MemoryStore offheapStore() { ... }
>> static MemoryStore heapStore() { ... }
>> ... //others?
>> }
>>
>> So far so good, we can create regions, with given access etc. Note
>> that here I'm trying to hide the addressing model used by Unsafe
>> (Object + long offset); after all, the addressing model depends on
>> the kind of memory you are operating on, so I don't think it's good
>> to expose it via the API (if we can avoid doing so).
>>
>> What is a memory region? Here:
>>
>>
>> interface MemoryRegion {
>> MemoryStore store();
>> Pointer<?> basePointer();
>> //maybe ByteBuffer accessor too?
>> boolean checkAlive();
>> boolean checkAccess(Memory.Access access);
>> long size();
>> }
>>
>> As Jorn (and separately, Steve) suggested, this could be the place
>> where we add the logic for liveness check - more specifically, a
>> memory region is considered alive unless freed on its corresponding
>> store. Interestingly, a memory region has a way to retrieve a pointer
>> to its base location. We can assume it will be a void pointer and
>> that the client will have to cast accordingly; this is, after all, a
>> low level API. This is also a very general API - it's not really
>> specific to Panama - other than the fact that a memory region can be
>> projected to a Pointer - but we can imagine other useful projections
>> too (e.g. Bytebuffers).
>>
>> What about high-level allocation? This is where Panama-related
>> concepts start to kick in:
>>
>>
>> abstract class Allocator {
>> Allocator(MemoryStore store);
>>
>> public <Z> Pointer<Z> allocate(LayoutType<Z> type);
>> public <Z extends Struct<Z>> allocateStruct(Class<Z> strClass);
>> ... //other allocation factories
>> }
>>
>> So, an allocator takes a store, and then implements the various
>> allocation functions; it is easy to see how such allocation functions
>> can be implemented: they will typically obtain a region (using the
>> store) of a given size (given by some LayoutType), then obtain a
>> pointer from the region and cast it to the desired type.
>>
>> What about scope-ness? Let's start from here:
>>
>> abstract class ScopedAllocator extends Allocator implements
>> AutoCloseable {
>> ScopedAllocator(MemoryStore store);
>> public void close() //this makes sure that all regions created
>> within this 'scope' are automatically freed
>> }
>>
>> So, this is a special allocator that also supports the AutoCloseable
>> interface, and can therefore be used with a try-with-resources, in
>> the usual way. In other words, clients will often do things like:
>>
>> try (Scope sc = new ScopedAllocator(MemoryStore.offheapStore())) {
>> sc.allocateStruct(...)
>> }
>>
>> You can think of this as an allocator that keeps track of the regions
>> it creates, and frees them as soon as you call close().
>>
>> I think this looks more or less equivalent to what we have now, but
>> we have captured and broken down the primitive concepts more clearly
>> now. There's a *store* that is responsible for allocating regions
>> (all relatively Panama-agnostic), and high level allocators, built on
>> top of stores, which provide the user facing allocation facilities.
>> Scoped allocators keep track of memory region usages, to allow for
>> automatic collection upon closing.
>>
>> One remarkable thing is that Scope/Resource have disappeared from
>> this API - the features available in the current Scope interface have
>> been split between memory regions and allocators. I think there could
>> be ways to add back explicit scopes into this flavor of the API - but
>> I think that, before we jump to that, it's better to stop and ask -
>> what are the use cases that would not be covered by this proposal?
>>
>> Maurizio
>>
>> [1] -
>> http://mail.openjdk.java.net/pipermail/panama-dev/2018-December/003572.html
>>
>>
More information about the panama-dev
mailing list