VCVRack / VCV-Prototype

Other
130 stars 22 forks source link

Uses LuaJIT FFI to speedup access to the ProcessBlock #28

Closed modlfo closed 4 years ago

modlfo commented 4 years ago

I found that most of the overhead in LuaJIT is caused when accessing the block information. I have a complex piece of Lua code (generated with Vult) that runs at ~25% (using the CPU meter in Rack) and goes down to ~5% when using the FFI. Other complex modules that I have tested have a similar performance.

This has some big disadvantages:

That said. This is how it works. I'm loading the FFI library in Lua and I'm creating the following piece of code:

local ffi = require("ffi")
ffi.cdef[[
   struct ProcessBlock {
      float sampleRate;
      float sampleTime;
      int bufferSize;
      float inputs[6][4096];
      float outputs[6][4096];
      float knobs[6];
      bool switches[6];
      float lights[6][3];
      float switchLights[6][3];};
]]

function castBlock(b)
   return ffi.cast('struct ProcessBlock*', b)
end

Check commit bdd1ff7 "Example on how to use the FFI in LuaJIT to increase the performance".

The first part describes the ProcessBlock structure that way LuaJIT knows how to access it. The function is used to covert the C++ ProcessBlock pointer to a LuaJIT cdata.

Since my objective is to run Vult code translated to Lua I could work instead on adding support for Vult language. In that case I would use different API. Rather than having access to the arrays I would use functions. For example:

fun process(in1, in2) {
   val x = getKnob(0);
   _ = setLight(0, x);
   return x * (in1 + in2);
}
AndrewBelt commented 4 years ago

block.inputs[i][j] needs to be accessed with 0-based indices

Can't you just set float* array = &buffer[-1] so that array[1] refers to buffer[0]?

Memory protection is lost

That's probably fine since we now have a warning message that scripts don't run in a safe sandbox.

modlfo commented 4 years ago

@AndrewBelt I have implemented what you suggested and it works fine. The data inside the ProcessBlock can be accessed from the Lua side using 1-based indices. The existing examples work fine and my complex plugins run at a good speed.

teknico commented 4 years ago

Anything blocking this? A nice speedup would be helpful. Thanks.

AndrewBelt commented 4 years ago

Just reviewed, looks great! I like your use of LuaProcessBlock. One-indexed and as fast as any FFI access can be. Cleaned up the code a bit after rebasing.