resource scopes and close actions
Michael Zucchi
notzed at gmail.com
Wed Feb 9 04:23:38 UTC 2022
On 9/2/22 13:12, Maurizio Cimadamore wrote:
>
> On 09/02/2022 02:19, Michael Zucchi wrote:
>>
>> Ok cheers that should probably do. I only just noticed you can use
>> it as an addressable a couple of days ago but using it for non-symbol
>> things isn't obvious especially given it's name and it's documentation.
>>
>> So it seems a 'typed' handle-like object that wanted to use a scope
>> on close action will have to:
>>
>> - use NativeSymbol as the native 'this', which contains a copy of the
>> MemoryAddress, a string and the scope handle.
>> - keep a private copy of the MemoryAddress so any close function can
>> use it after the scope is closed (whether it be in the object or in a
>> lambda, it may as well be in the object)
> yes
>> - (based on the proposed api change) also keep a copy of the
>> ResourceScope if it wants to be able to propagate it automatically
>> which would often be desirable (... i think).
> stay tuned on this. We're looking into ways to mitigate the impact of
> the proposed changes which will not require you to keep a
> ResourceScope around (and use a segment instead as a "proxy" of the
> temporal bounds you want to use e.g. to create another segment).
What if you have a NativeSymbol instead?
>>
>> Doesn't seem too elegant but that should work? I'll explore that
>> with opencl as i've the most experience with that api and it has some
>> consistent conventions that i think will mesh well.
>>
>> e.g. as a first thought, does this look about right?
>>
>> An example case is CLCommandQueue which is an object which is created
>> by and belongs to a CLContext and can be closed either by an explicit
>> unref or when the context is unreffed.
>>
>> public CLCommandQueue {
>> NativeSymbol symbol;
>> ResourceScope scope;
>> MemoryAddress addr;
>>
>> // package private
>> close() {
>> clReleaseCommandQueue$MH.invokeExact((Addressable)addr);
>> }
>> }
> This looks mostly ok - not sure whether you need to keep the `addr`
> around. I would have expected `addr` to only really be used in a close
> action, so when you create CLCommandQueue (e.g.
> CLCommandQueue::create). Am I missing something?
Only because it needs to be stored somewhere, either in the lambda or
the object. I was thinking of having the ability to implement an
idempotent close at the time so you can't just have it in the lambda,
but I don't think that will be possible with scopes - unless you have
scope-per-object which as you mentioned isn't optimal. Otherwise you're
basically just back to a stale object on an open scope and would need
more checks every time you use it. I was also thinking broader such as
the ffmpeg AVFormatContext example earlier where some other object state
defines which close to use.
An implementation that used a cleaner would have to do something else
anyway.
>
>>
>> My JNI code uses reference queues so both explicit and gc-release are
>> possible, this is particularly handy for lambda-based processing
>> chains where there's no 'object' to hold references around and
>> ownership is basically passed by argument in a graph of unpredictable
>> ways. A common shared scope with a cleaner should work i think but
>> that would require a different design.
>
> In general, starting off with single scope, GC-managed, sounds like a
> good default choice - and then sprinkle scopes as you see needs to
> deallocate more promptly and/or add more fine-grained lifecycle
> management to your library (assuming that is required). Btw, note that
> a GC-backed scope can still be released explicitly, if you so wish (so
> you have both options at once).
>
The case i'm trying to solve is where you don't really know the
lifecycle of the object. With opencl you use reference counting to hold
objects as long as you need them so they can change ownership and/or be
shared amongst different functions and libraries in ways the caller
can't control. My JNI wrapping hid all that by just using java
reference gc to effectively do the same thing as far as java was concerned.
I've also made an embarrassing mistake, closing the context doesn't
release it's objects, in opencl they all have a reference count on the
context so the other discussion is a little moot. I believe it does in
vulkan although it's an error to close the instance before all of it's
objects are closed.
Oh well i'll have to about it more. Implicit scopes wont be enough in
the case of such an api unless each object also retains a java reference
to it's parent - leaving it up to the application isn't really safe
enough is it?
Just FYI command queues are not short lived, a simple app might be:
create a context
create a small number of queues
create your kernels
then set up a processing pipeline - could be multiple, could come and go:
create some memory buffers and images
maybe create some specific kernels
then execute a processing pipeline - this will happen multiple times,
and an individual execution could span multiple threads:
execute kernels, track execution using events - some will have the
lifetime of the pipeline, others a fragment of it, perhaps allocate/free
temp image/memory along the way
close everything in reverse
Given the realisation of my mistake on how the refcounting works in
opencl i think this should be covered by a few relatively simple scope
mechanisms under application control.
!Z
More information about the panama-dev
mailing list