[LV2] worker thread question

David Robillard d at drobilla.net
Fri Dec 28 14:59:41 PST 2012


On Fri, 2012-12-28 at 18:50 +0100, hermann meyer wrote:
> Am 28.12.2012 17:38, schrieb David Robillard:
> > On Fri, 2012-12-28 at 05:25 +0100, hermann meyer wrote:
> > [...]
> >> . . but you will imagine that the design from the eg-sampler example
> >> plugin is exactly were I'm talking about (and is what I'm tried first) .
> >> The UI send a message to run() which in-turn fire up a worker thread.
> >> The internal UI from the host didn't know about that and will not work.
> >> So, the internal host UI is brocken.
> > You seem confused.  The UI, again, has nothing to do with the worker,
> > everything about that is on the plugin side.  The same message sent by a
> > host UI would, of course, do the exact same thing, because... it's the
> > same message.
> Well, if the host didn't know the message, he cant send it.
> 
> > Also, it's unlikely a host would implement the worker by launching a
> > thread for every request.  There's just one worker thread.  Possibly
> > just one for many plugins, even.
> >
> > The UI of the eg-sampler is a silly thing because most host UIs
> > currently don't understand how to send such messages.  Hopefully that
> > will change.  Is this what you mean?  That is unrelated to the worker
> > though.
> Exact, that is what I mean, for this case, a host UI cant work.

Hosts not happening to currently implement controls for messages like
this is very different from "can't work".  It *can* work, and it is
planned that hosts do support controls for messages eventually (though I
don't know when I will personally have the time to implement this).

If you want to do it in current hosts that do not support this, then
yes, you will need a custom UI.  Everything on the plugin side of things
is exactly the same either way.

> > There is nothing in the plugin interface about threads, there is no
> > distinguishing between messages that will be processed in real-time and
> > those that will not.  This is probably a good thing.
> >
> >> Now I have some controllers which presented to the user as simple knobs,
> >> like all other controllers as well, but those knobs control some
> >> convolvers which need a impdata.update when the controller is moved.
> >> Clearly that is a job for the worker-thread.
> >> For the record,I have no problem to get it all work, that isn't what I'm
> >> ask about, my question is related to the UI->host->engine communication,
> >> which seems to me, break the internal host UI.
> > Can you explain what you think is "broken" about host UIs?
> Again, I have controllers which change a value, if the value change, a 
> worker thread is required. I could send a message from the plugin UI, 
> like eg-sampler do it, but then, the internal UI from the host didn't 
> work, simply because he didn't know that a message is to send. That is 
> simply a broken host UI for the plugin.
> 
> Alternatively I can check the value in run(), which is the rt-thread, 
> when I get it right :-) , and send the message from run, this way, the 
> host UI didn't need to know about a special message to send.

This is how it works either way, including if you send fancy messages.
The plugin interface, via ports, does not change whatsoever with respect
to the worker or any other internal threading details.

> BUT, then I need to check the values from the controllers at any cycle 
> in run, that is, a wast of processing time. It isn't a big deal when I 
> have just one or two of those controllers which needs to be checked, but 
> again, they could become likely more,  . . .

Yes.  This is a limitation of ControlPort controls and has nothing to do
with threads (it's common in simple single-context plugins too).

That said, it's very very very very unlikely that a few float
comparisons are going to actually be significant.  The check to see if a
message has arrived would be at least as expensive anyway.

> If I have a thread which run with a higher timeout, and in non rt, it 
> will spare a lot of processing time and it will keep the rt-thread clean 
> for plain dsp processing. :-)

No, it won't, because you have an additional unnecessary thread, and you
have to actually send that data to that thread to do this comparison.
The data arrives in run() regardless.  You'd be doing an absolutely
massive amount of work in order to avoid an incredibly cheap number
comparison, and be copying a ton of completely useless data every time
the control *doesn't* change.  There is zero chance that would win you
anything.  Moving/accessing data is expensive on modern architectures;
much, MUCH more expensive than math and comparisons and such.

> > This way, everything enters/leaves ports in run(), it's synchronous and
> > simple, and if the plugin wants to queue off work to another thread, it
> > is free to do so, but it doesn't complicate the interface of the plugin.
> > It just works with ports and run() like every other LV2 plugin.
> That is why I'm talking to you, before I implement my own watch thread, 
> i would talk to you about this need, as if you completely negate it, so 
> be it. Just think about, do you believe a plug-in like guitar-rig could 
> work without a own watch thread? Switch plugs in the plug on and off, 
> move there position in the processing chain?
> That is exactly what I have in mind. The worker thread is a real good 
> extension to the LV2 specs, a additional watch thread would be awesome 
> and could extend the use of the worker thread to a bunch of possibility's.

More threads, more problems.  Do non-rt things in a worker, and I/O and
processing in run().  More threads complicated things massively for no
win.  The idea of a "watch thread" doesn't really make any sense.

Yes, plugins that dynamically reconfigure are possible using the worker.
Some plugins might have internal threads (Ingen does) but certainly not
just to watch port values - expecting to win performance by shuttling
data between threads via a ringbuffer to avoid a few comparisons is
insane.  What eg-sampler does is pretty much the same as this, instead
of loading a sample, rebuild your engine or whatever.  The stuff you
reconfigure will naturally have to be a separate object from the one
currently being executed for thread safety.

The worker is literally designed for exactly this sort of thing.  Send a
message off to the worker to reconfigure/recompute/do whatever, then
install it in run() later when it's done.  It also has the advantage of
making it possible to do this synchronously with sample accuracy when
rendering offline, which a DIY thread solution can not do.

Unless you have a particularly advanced use case (which it doesn't sound
like you do) or existing threaded engine code you're much better off
just sticking with the facilities that are there, and worrying about
premature optimization less.  KISS.

-dr

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://lists.lv2plug.in/pipermail/devel-lv2plug.in/attachments/20121228/73ed252c/attachment-0002.pgp>


More information about the Devel mailing list