Taaitaaiger / jlrs

Julia bindings for Rust
MIT License
408 stars 21 forks source link

Benchmarks #92

Closed Taaitaaiger closed 11 months ago

Taaitaaiger commented 1 year ago

jlrs currently has no benchmarks. A few changes are planned which should improve performance, in particular the performance of functions exported with the julia_module macro. In order to verify that these changes are improvements I want to add a few benchmarks.

When ConstructType::construct_type is called the type object is constructed recursively, which can involve accessing modules and allocating several values depending on the complexity of the type object. Constructed types with no free type parameters can (probably) be considered globally rooted because they're cached by the TypeName. This means such a type only has to be constructed once, can be cached in some global container in Rust, and looked up in that cache to avoid the overhead of recursively calling ConstructType::construct_type. In order to verify that the performance is actually improved by caching the constructed type, we need to verify that with a benchmark.

There need to be benchmarks for several "levels of complexity": Types that are already exported by julia.h, types that have to be looked up, types with type parameters.

The ledger is used to track what Julia data is currently dereferenced in Rust code doesn't break any aliasing rules. The only way to get a reference to the content of some Julia data right now is by using the ledger, so this needs to be as fast as possible. These benchmarks should be added to the jlrs_ledger crate, but I think it also makes sense to add a few to jlrs to track the overhead of calling into jlrs_ledger. The library is loaded with the RTLD_GLOBAL flag so I want to check if the Ledger struct can be dropped in favor of simply calling these functions because they should be callable after JlrsCore has been loaded.

There are two ways to export a function from Rust to Julia with the julia_module macro: you can either export a free-standing unsafe extern "C" function directly, or you can export a method of some type and a free-standing function that calls it is generated. I want to know the how expensive calling a trivial function and method is, how expensive constructing and returning a RustResult is, and how expensive it is to call methods that take self in some form.