FFM API: EA failure with 4+ address parameters
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Wed Oct 23 16:21:46 UTC 2024
Thanks Ioannis, we'll take a look.
One thing that comes to mind is that when you pass an address to a
downcall, the Linker has to keep its arena alive (to ensure it stays
alive for the entire duration of the call). Now, if the segments you
pass are constructed with MemorySegment::ofAddress, you get back
segments associated with the global scope, so this "acquire" operation
is a no-op.
But the Linker-generated code contains some non-trivial logic to try to
reduce the number of acquire calls that are generated - e.g. if you pass
7 arguments all associated with the same arena, we'll just do a single
acquire. I wonder if, as the number of argument becomes increasingly
big, the generated code for the downcall bindings becomes too complex
and full of control flow, which then results in EA bailing out.
(Needless to say, we can't wait to make MemorySegment implementation a
value class and avoid all these issues :-) )
If that is the issue, it might be that case that calling one acquire per
pointer argument, even if redundant, leads to better optimizations than
what we have now. The complex logic I'm referring to is here:
https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java#L497
Maurizio
On 23/10/2024 16:51, Ioannis Tsakpinis wrote:
> Hello,
>
> I've been migrating LWJGL to FFM and during testing of some real-world
> code (Vulkan rendering), I noticed a spike in GC activity with the FFM
> implementation, compared to the old JNI implementation. I think I've
> been able to track it down to what looks like an odd failure of escape
> analysis. Specifically, scalar replacement no longer occurs when
> calling functions with 4 or more ADDRESS (MemorySegment) parameters.
>
> JMH benchmark (you'll need to build a shared library with some empty
> functions and run with GC profiling enabled) that demonstrates the
> issue:
>
> https://gist.github.com/Spasi/71d5cfa687a1dbe95b3fce608d31ae6b
>
> There are functions with arity from 0 to 5. When invoking a downcall,
> raw pointer values are wrapped with MemorySegment.ofAddress() and
> passed to each argument. The exact pointer values do not matter.
>
> Until 3 ADDRESS parameters, or 3 ADDRESS parameters plus other non-
> ADDRESS parameters, everything is fine and there's no GC activity.
> With 4 or more ADDRESS parameters, allocations are no longer
> eliminated. The problem also occurs with a single MemorySegment that
> is passed to all parameters:
>
> var p = MemorySegment.ofAddress(42L);
> functionMH.invokeExact(p, p, p, p);
>
> Any idea what might be causing this?
>
> - Ioannis
More information about the panama-dev
mailing list