jextract woes

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Feb 3 10:06:20 UTC 2020


On 03/02/2020 01:52, Michael Zucchi wrote:
> On 1/2/20 1:57 am, Maurizio Cimadamore wrote:
>> I'm not sure I get what you are asking here - I'm pretty sure the old 
>> Libraries.bind could not be used for things like the ones you 
>> described. The only difference between old and new is that in the old 
>> world, Libraries.bind was actually generating a brand new class - at 
>> runtime - to implement a given interface (generated by jextract) 
>> based on the contents of some annotations. If you want to use 
>> something like that in a core framework like the JDK you realize that 
>> you are pulling in more dependencies than really needed - in fact the 
>> JDK wouldn't even start if we tried to use the binder-based approach 
>> because that was trying to parse annotation and spin classfiles 
>> _while_ the JDK itself was still being initialized. So, in terms of 
>> footprint and dependencies, the new approach is much better - some 
>> preliminary tests I did using an OpenGL demo, the time to first drawn 
>> frame dropped 4x when switching to the new bindings. And there's lots 
>> of room for improvements (generating classfile could make all the MH 
>> initialization lazy, which means you pay only for the MH you use). 
>
> Above is regarding the dynamic binding, and yeah you could do it.  See 
> below, this was one of my first experiments with panama.
>
> Given that you were building classes dynamically and then loading them 
> during initialisation, well it's perhaps no wonder it was slower?
>
> Also, what I was asking was simple: "where is the performance hit" of 
> using a call to downcallHandle() at runtime vs using a 
> CONSTANT_MethodHandle_info.  Does it only affect startup-time (as you 
> imply above), or does it affect the invokeExact() calls as well?

If you have a single native method handle to create, there's no 
difference between having an explicit call to downcall handle and doing 
something smarter in the classfile.

In a more complex (and realistic) binding, you will have dozens of 
functions, hundreds of layouts and so forth - this implies two things:

- most of the layouts are going to be shared across multiple calls to 
'downcall handle'
- the client is probably not going to call all the method handles

So anything which can be done to improve sharing (so that less instances 
have to be built and can be reused) and only allocating the handles you 
really need will have a positive impact on startup.

In terms of performance when _invoking_ a method handle - there is a big 
difference between invoking an handle that is shared in a static final 
field, and one that is not. In the former case, C2 will see it as a true 
constant (like if it was a  CONSTANT_MethodHandle_info, so to speak) - 
and it can inline through it. In other cases (e.g. if the MethodHandle 
is stored in a mutable non-static field) those optimizations won't kick in.

>
> At some point I will try some startup-time experiments although I'm 
> not sure of the best way to measure them.
>
>
>     @NativeHeader()
>     public interface APIExt {
>
>         @NativeFunction(value="(i32)v")
>         public void funca(int a);
>
>         @NativeFunction(value="(i32)i32")
>         public int funcb(short b);
>
>         @NativeFunction(value="(f32)i32")
>         public int funcc(float b);
>
>         @NativeFunction(value="(f32)i32")
>         public int funcd(float b);
>
>         public static APIExt bind(APILib lib) {
>             APIExt ext = Libraries.bind(APIExt.class, (String name)->{
>                     Scope ss = s.fork();
>                     Pointer<Byte> cname = ss.allocateCString(name);
> *                    Pointer<?> p = lib.api_func(cname);  // this 
> resolves the address at runtime, it doesn't, but could take other 
> arguments*
>                     ss.close();
>
>                     return new Library.Symbol() {
>                         public String getName() {
>                             return name;
>                         }
>                         public Pointer<?> getAddress() {
>                             return p;
>                         }
>                     };
>                 });
>         }
>         }

I see what you are doing there - you are essentially implementing your 
own lookup - that is the feature that allows you to lookup for dynamic 
functions.

Maurizio



More information about the panama-dev mailing list