As I am experimenting several ways to abstract over C libraries wrapped with Clang with minimal overhead, I am starting to wonder whether Julia is a good fit for this kind of thing if one wants to preserve performance. The hardest thing is to make sure that pointers remain valid, particularly when C structs themselves involve pointers to other C structs. Having to fight compiler optimizations and garbage collection to keep pointed variables valid is a tough challenge, even if
ccall helps for simple API calls.
I would love to have your opinion on the subject. So far, I have investigated two tricks that work well for preserving pointer validity, but which incur high runtime costs:
- Using a global
WeakKeyDictto keep Refs/Strings/Arrays alive as long as their “parent” lives
- Tweaking the
- produce pointers on-the-fly upon an API call (from a Julian struct which may contain plain struct/Ref/Array/String fields) and explicitly preserve them using LLVM instructions for that specific call
- create the corresponding C structs (with pointers that are guaranteed to be valid)
- call the API function
For the first option, allocations seem inevitable when adding anything to that dict, and simple structs take as long as ~300 ns to initialize.
For the second option, simple structs initialize quickly (~15 ns which would be totally OK) but the more complex the struct is, the slower it gets (since a whole struct has to be generated at every API call). Plus, handling of optional parameters (such as when
NULL can be accepted from a C function instead of a struct pointer) are nontrivial to implement without losing a lot of performance.
My desire for performance comes from the fact that the library I am trying to wrap (Vulkan, a library for doing GPU stuff including rendering graphics) would be used inside an event loop with a lot of API calls (potentially hundreds if not thousands of them) per loop.
What do you think on that subject? Is there something to fix/improve which would prevent from fighting the language wherever pointers are involved from an external C library? Or is it just something that Julia is not intended for, and therefore one should rely on other languages such as Rust or C/C++?