cmajor-lang/cmajor

Providing an allocator for `Engine::createPerformer()`

Closed this issue · 4 comments

Hello!

I was looking into the C++ API to see how feasible would be to embed the Cmajor JIT compiler within SuperCollider. The one thing that stops me is the need for it to be using SuperCollider's real-time allocator when creating a new instance from a compiled Cmajor program.

Compiling the program is not a problem, as that can be executed in a background thread, but allocating new instances of them via SuperCollider UGens could be problematic, as this happens on the audio thread. I was wondering if it would then be possible to pass a custom alloc function (which would point to SuperCollider's RTAlloc function) to Engine::createPerformer() for it to allocate the memory of each created instance with a custom allocator.

Thanks!

Our discord channel is probably a better place to have a proper discussion like this..
But my questions would be
a) Allocating new instances of what exactly? What are you actually trying to call?
b) if you can build on a background thread, then why can't you do all other allocation on that thread too, and pass the result object over to the audio thread?

My bad, didn't see the discord link!

a) Allocating a new instance of a cmaj::Performer out of a compiled program.

b) The idea is that I would compile the program once on the background thread, and then several instances of it could be dynamically created on the audio thread. This is a restriction of SuperCollider, where new UGens are allocated on the audio thread using its real-time allocator, which is simply an arena allocator. I guess I could have a pool of pre-allocated Performers in the background thread and index those from the audio thread, but I was wondering if there was a way to directly use a custom allocator function instead, or if it's something you considered adding.

There's a number of allocations going on, firstly with the PerformerBase which keeps track of handlers for each of the endpoints, but also the jit object that it manages, which will obviously have to allocate to track the memory used by the algorithm at runtime.

This could in theory be handled by a custom allocator, but there's quite a bit of STL container stuff going on within the PerformerBase which would need changing.

In addition, we have some choc::com stuff which I don't think supports a custom allocator, so that would need to be changed for this to work.

So, i'd definitely suggest pooling some created instances as a first pass at this, and see how that goes as it will be significantly easier to implement. I could imagine us needing something like what you are suggesting for more dynamic environments, if, say, we tried to make this work in a game audio engine we may have similar problems.

I see, thanks for the answer! I'll go with the pool option for now then