JEP 424 (FFM API / Project Panama) first look

207 views
Skip to first unread message

Daniel Widdis

unread,
Oct 3, 2022, 2:05:38 AM10/3/22
to Java Native Access

JDK 19 upgraded the Foreign Function & Memory API from incubating to preview state, making it a lot easier to load and test and start writing code.  I’ve spent a week exploring some of the functionality and figured I’d share some of my observations.

 

Overall:

  1. If you’ve already done enough JNA development to get comfortable with pointers, offsets, and more complex structure mappings, the learning curve isn’t that steep. The JEP provides several examples, and soon there will be more example projects (including mine) to look at for examples/inspiration.
  2. I would absolutely LOVE for an equivalent of “jna-platform” to be developed so I can contribute my mappings there and not keep them in my own project.  Not sure how much interest there is hosting that at the jna project, and happy to discuss the potential for that at JNA or starting an alternative project with other interested parties.

 

The good:

 

  1. Performance.  I’ve seen single-function benchmarks suggesting 12x faster.  I’ve actually implemented code from my library and seen about 5x faster in informal/real-world testing.
  2. Simple API.  There really are just a small number of methods that can be learned quickly.  If you wanted to write JNA code with only Memory and Pointer classes, you could probably get things done, and that’s somewhat the same experience.
  3. A lot more fine-grained control over allocating and releasing native memory.
  4. The Layout classes (Structures, Unions, etc.) are actually really easy to define, avoid the “field order” annoyance, and support layouts down to the bit level.

 

The bad:

  1. Common constructs like “IntByReference” aren’t available.  It’s not that hard to create them but it leads to repetitive code.
  2. Community mappings / util classes don’t exist yet.  I’m hoping this will change.
  3. The Layout classes require you to manually check alignment/padding when defining them (not a horrible problem) but the bigger issue is that from a userspace perspective, fetching a field from a structure is a bit more complex than the “field of an object” abstraction of JNA.   You’re essentially calculating offsets, which the Structure class does under the hood, but the inner guts are a bit more obvious.

 

The ugly:

  1. There seems to be an underlying assumption that size_t is always pointer-sized. 
  2. There’s a lack of very common low-level libc functions like fetching errno after an exception.

 

For a side-by-side comparison of Library class implementation, enjoy:

JNA: https://github.com/java-native-access/jna/blob/master/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java

FFM: https://github.com/oshi/oshi-ffm/blob/main/src/main/java/ooo/oshi/foreign/mac/SystemLibrary.java

 

 

Timothy Wall

unread,
Oct 21, 2022, 12:01:53 PM10/21/22
to jna-...@googlegroups.com
Cool!  Thanks for this, Daniel.

JNA's had a 20+ year run, not bad for software.

T.

--
You received this message because you are subscribed to the Google Groups "Java Native Access" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jna-users/FAFBF698-B06B-45A6-879A-6363ABF86DAB%40gmail.com.

Matthias Bläsing

unread,
Nov 29, 2022, 3:09:25 PM11/29/22
to jna-...@googlegroups.com
Hi,

I had not yet time to really look into panama, so this is more to get my thoughts out and my inbox empty.

  1. I can imagine creating a repository for bindings. The big question how it should be structured. "Platform" can be anything and can get big if you just want basic bindings. It could be multiple packages, that depend on each other. Something like "basic types" (the reference types), "windows basics" (the types MS defines and uses), building on the latter individual packages for windows libraries.
  2. JNA could introduce replacement code, that replaces the native libraries with panama invocations, though I suspect, that some of the callback code can't be that easily be replaced.

Greetings

Matthias
--

Chris Nuernberger

unread,
Nov 29, 2022, 5:58:34 PM11/29/22
to jna-...@googlegroups.com
I also have played quite a lot with panama.

I have an ffi layer that generates code for jna, panama, and a limited subset of graal native - here is an example project.  I built a popular python binding library mainly with JNA named libpython-clj which has some unique properties such as the ability to run in embedded mode which means running under a python host.

When I tried the panama bindings with libpython-clj everything sorted worked and I did see some performance advantages until I attempted to load numpy.  No matter what I did numpy would not load - I think this has to do with the fact that numpy needs to bind to existing process symbols and the panama ffi layer loads the shared library in a very particular mode that doesn't make its symbols available process wide - most likely I think so they can tie the shared library to a class loader.

I also found that panama's library lookup system completely ignores the users PATH variable which also meant that loading shared libraries under a system like python's conda was nearly impossible.  While I understand their desire to go through the existing java library-path system I think that system very fragile, not well integrated with current operating systems, and out of date.

Finally I did see some performance advantages - but libpython-clj already is faster than other existing python bindings and no matter what extremely granular calls across languages is never going to be fast -- you want fewer calls and batched data.

So I found panama to be a mixed bag.  Faster in some cases but overall less robust and it completely failed for an important use case of ours.

 Chris

PS - here is an article on the  FFI system.

Daniel D.

unread,
Jan 14, 2023, 12:52:20 PM1/14/23
to jna-...@googlegroups.com
I'll throw my 0.02c. From the user perspective I think I'd like to upgrade JNA and get the Panama performance boost without changing any code. What would it take?



--

dB. | Moscow - Geneva - Seattle - New York
code.dblock.org - t:@dblockdotorg - ig:@artdblockdotorggithub/dblock

Chris Nuernberger

unread,
Jan 14, 2023, 12:58:49 PM1/14/23
to jna-...@googlegroups.com
The way I do exactly that is runtime code generation generating jvm bytecode using jvm byte library based on a library called insn which itself is based on org.ow2.asm/asm.

Daniel D.

unread,
Jan 14, 2023, 1:04:16 PM1/14/23
to jna-...@googlegroups.com
So do you think you could PR it into JNA? Even if you can get it 75% there, to me it feels like the quickest path forward for Panama adoption.

Chris Nuernberger

unread,
Jan 14, 2023, 1:08:40 PM1/14/23
to jna-...@googlegroups.com
Let's take a look at my codebase.  JNA is a backend that I also generate code for.  Here is an example project - bindings to MKL - https://github.com/cnuernber/mkl/blob/master/src/mkl/ffi.clj.



What this doesn't cover are different routes for creating nio buffers from integer addresses and vice versa but that is a minor difference that is JDK specific.  The key enabler for this is I describe the ffi bindings as backend independent datastructures that I iterate over with the code generator.  You could do the same with the classes that JNA expects users to create but it would take a major effort to do this in Java as compared to Clojure.  It's hairy stuff.

Chris Nuernberger

unread,
Jan 17, 2023, 11:44:26 AM1/17/23
to jna-...@googlegroups.com
JNA, however, already has class generation capabilities so an bytecode/asm pathway doesn't seem necessary.  One thing about the bindings I generate using code generation is that everything is direct mapped.  If you want JNA to have higher performance than making everything direct mapped seems like a no-brainer to me.   So, stated differently, why don't the interface mappings have the same performance when at all possible (as in when the method isn't vararg) as direct mapping?  As a user I think this would be a higher priority and could be a first step.  

So my opinion is that we should consider making the current JNA better and cleaner first then worry about generating separate backend mappings for a separate JNI layer which will introduce as I also stated earlier difficult to solve issues regarding specifically dynamic library loading.  This would impact more users than JDK-19 FFI support - the US government, for example, still mandates JDK-8 support for many users.

Chris 
Reply all
Reply to author
Forward
0 new messages