Re: [Jack-Devel] mumbo jumbo on a wiki page

PrevNext  Index
DateMon, 04 Jul 2011 18:57:35 +0000
From Fons Adriaensen <[hidden] at linuxaudio dot org>
To[hidden] at lists dot jackaudio dot org
In-Reply-ToPaul Davis [Jack-Devel] mumbo jumbo on a wiki page
Follow-UpPaul Davis Re: [Jack-Devel] mumbo jumbo on a wiki page
On Mon, Jul 04, 2011 at 12:42:06PM -0400, Paul Davis wrote:
> this wiki page:
> 
>     http://trac.jackaudio.org/wiki/WalkThrough/Dev/LatencyBufferProcess?version=5
> 
> seems filled with a lot of mumbo jumbo, and worse appears to recommend
> using locks to protect buffers used by process().
> 
> my gut feeling is to remove the entire page unless someone wants to
> step up and edit this into useful form, and without erroneous
> suggestions about locking.

I agree with your sentiments about that page - too many half-truths
and I-don't-knows. 

But using locks is not by itself evil - it all depends on how
they are used - and in some cases it seems unavoidable.

I've been working on a framework that runs an arbitrary graph
of audio 'process units' on a multi-cpu machine, and I've not
found an efficient solution without locks. OTOH, the chance
of contention in this case is low, if there is no contention
everything happens in user space, and it there is it will be
short. So using one or two more threads than you have CPUs 
should keep them all busy.

I wonder what sort of solutions others are using for this
problem.

In my case, things work as follows:

* There is queue of pointers to PUs ready to run. In each
cycle it is initially prefilled with those PUs that have
no other dependencies except input buffers.
* There are N threads, same priority as Jack's one, that
read from this queue, execute the PU, and then look at
the list of those that depend on the one just executed
(each PU has such a list).
* Readyness is indicated by a dependency count becoming
zero. The first one ready will be taken by the current
thread (this optimises chains of PUs with just one
dependency, as e.g. in a mixer strip), any others are
added to the queue. If no other PUs become ready the
thread reads the next one to execute from the queue.

There are two places where locks have to be taken: when
accessing the queue, and when decrementing and checking
the dependency count of other PUs. After some experimen-
tation, the most efficient (and the simplest) approach
seems to use just one lock: that of the queue. It is taken
while checking the complete list of PUs that depend on the
one just executed, so it also protects the dependency 
counts. The code within the critical section is very
fast, so the chance of contention is small.

Ciao,

-- 
FA
PrevNext  Index

1309805871.27347_0.ltw:2,a <20110704185735.GA9322 at linuxaudio dot org>