On Sat, 2012-10-20 at 21:03 +0000, Fons Adriaensen wrote:
On Sat, Oct 20, 2012 at 07:43:38PM +0200, Robin Gareus
wrote:
On 10/20/2012 01:44 PM, Fons Adriaensen wrote:
ConvoLV2 uses libzita-convolver, but in a very
inefficient way,
Yes, we are aware of that. At this point in time we favor clean design
over efficiency. The choice to use a fixed blocksize comes from the fact
that we do not want libzita-convolver to spawn addtional threads nor
makes use the semaphores in libzita's process callback.
What's the problem with the semas ? They are the simplest and most
efficient way to signal an event. And unless you use the 'sync' mode
(which you should do only when Jack is freewheeling), they are used
only to trigger the lower priority threads, and the thread calling
Convproc->process() will never wait for a sema or be blocked.
And what's the problem with the threads ? The only one I see is that
LV2 doesn't have any way to pass the required priority parameter, but
there are simple ways around that.
The goal of the plugin is to do synchronous (i.e. processing in the
run() context) convolution in a *strictly* hard-real-time fashion with
no latency. Doing the processing in another thread(s) does not meet
this requirement essentially by definition. Yes, it can work well
enough, sometimes, but that is different.
If the processing is happening in another thread, then e.g. at the very
first block, run() must either:
(1) Wait (i.e. block) for the other thread to process the data
(2) Add latency
(3) Busy wait and drop out if data is not available "in time"
(4) Attempt to split the work such that when run() finishes its part
the others will be done
(4) is admittedly clever, if you know there's idle cores to make it
beneficial and make some optimistic assumptions about scheduling.
convoLV2 aims to not do any of these things by doing the processing
synchronously, which is much simpler and more reliable. The cost is
block length restrictions.
Plugins that launch a bunch of processing threads can be problematic for
other reasons, e.g. if you have many of them instantiated, and they are
already spread across all available cores by the host (as Ardour can).
No amount of priority tweaking will make hundreds of threads thrashing
in a situation like this work well, it's bloated and will fall apart
much sooner than synchronous plugins. Other issues include memory
consumption, complexity and non-portability in plugins, priority
configuration as you mentioned, etc.
Using threads can be a perfectly reasonable thing to do, but the goal
and requirements of this plugin are as stated, which means no threads.
It breaks down pretty simply into two cases:
(1) Block length is arbitrary, in which case threads are necessary
(2) Block length restrictions can be guaranteed, in which case threads
are pointless bloat
convoLV2 aims to be the best solution for (2), at the cost of not being
a solution for (1) whatsoever. Threads may work for (2), but are not
ideal (especially when the host is already multi-threaded).
I don't claim synchronous is ideal for all, or even most situations, but
it definitely is for some.
-dr