[code-reflection] RFR: ONNX FFM Runtime initial work [v3]
Maurizio Cimadamore
mcimadamore at openjdk.org
Mon Feb 10 11:14:51 UTC 2025
On Sun, 9 Feb 2025 14:31:14 GMT, Adam Sotona <asotona at openjdk.org> wrote:
>> This is initial work on ONNX FFM runtime with very raw connection with OnnxInterpreter and Tensor.
>>
>> It is a rebase of https://github.com/PaulSandoz/babylon/pull/1
>
> Adam Sotona has updated the pull request incrementally with one additional commit since the last revision:
>
> minor rename
I've tried to run jextract on the onnx header here:
https://github.com/microsoft/onnxruntime/blob/main/include/onnxruntime/core/session/onnxruntime_c_api.h
It seems to work correctly and to generate the bindings for the onnx runtime. Of course, this is not a classic API -- in the sense that the functions you want to call are defined inside a struct (OrtAPI). But, you can use a couple of jextract-generated function to get a pointer to that API struct:
1. `OrtGetApiBase` (in `onnxruntime_c_api_h`)
2. `GetApi` (in OrtApiBase)
Note: the latter returns a function pointer, so in order to get the API you need to "invoke" the pointer. To do that, there's a GetAPI functional interface generated by jextract for this function pointer -- it has a static invoke method:
public static MemorySegment invoke(MemorySegment funcPtr,int _x0) {
So, if you pass this static method the segment you got in (2), you should get the desired API back.
>From that point on, you use the same trick: that is, the OrtAPI struct is basically a struct containing a bunch of function pointers. So, to call a function in that API you need to:
1. get the memory segment for the field corresponding to the function you want to call
2. call the static `invoke` method on the generated functional interface modelling that function pointer
For instance, for `AllocatorGetInfo`, the OrtApi class has this getter:
/**
* Getter for field:
* {@snippet lang=c :
* OrtStatusPtr (*AllocatorGetInfo)(const OrtAllocator *, const struct OrtMemoryInfo **)
* }
*/
public static MemorySegment AllocatorGetInfo(MemorySegment struct) { .. }
You call that (`struct` here is the reference to the OrtApi struct). And then you pass the returned segment (a function pointer) to this:
/**
* {@snippet lang=c :
* OrtStatusPtr (*AllocatorGetInfo)(const OrtAllocator *, const struct OrtMemoryInfo **)
* }
*/
public static class AllocatorGetInfo {
/**
* Invoke the upcall stub {@code funcPtr}, with given parameters
*/
public static MemorySegment invoke(MemorySegment funcPtr,MemorySegment _x0, MemorySegment _x1) { ... }
}
The nice thing about this is that you don't need to hardwire "magic numbers" as you have done in your implementation. You can leave the mechanical part to jextract, and focus on what API you really want to expose (your `Environment` class).
-------------
PR Comment: https://git.openjdk.org/babylon/pull/311#issuecomment-2647671328
More information about the babylon-dev
mailing list