Re: [linux-audio-dev] API design again [MORE code]

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: Re: [linux-audio-dev] API design again [MORE code]
From: David Olofson (audiality_AT_swipnet.se)
Date: su loka   10 1999 - 14:33:56 EDT


On Sun, 10 Oct 1999, Paul Barton-Davis wrote:
> [ ... sleeping ... ]
>
> >So where do you get the CPU time for other tasks, if the engine never
> >sleeps...? Or am I missing what you're actually saying here?
>
> (for a moment there, i thought i had fallen into my "i have a dual CPU
> box and so does everyone else" trap. but fortunately, no ... )

Scary... *hehe*

> the engine sleeps whenever it calls a plugin that calls
> read/write. how long it sleeps depends on the i-node it reads/writes.
> if it never calls read/write, it will never sleep.

Ok, that's exactly the sleep point I had in mind...

> "nothing is calling read/write" is actually a pathological situation,
> but relatively easily dealt with. quasimodo and hdr both have to do
> this. for quasimodo, a plugin must be able to tell us if it does
> input. for hdr, if there are no inputs active then we stall the
> engine. we focus on input because output is handled in these programs
> by the "engine" itself. in MCS, this may not be true, so the
> work_to_do() test has to include active ins OR active outs.

Yep. However, there's one thing to keep in mind here (at least with
the kernel MCS implementation I have in mind); it's perfectly
possible that the *engine* never calls an I/O plug-in, and therefore
never sleeps that way. Instead, it'll have to sleep on the MCS
connection it's supposed to be sync'ed with, after each finished
cycle. (Like Benno's client/server interface.)

> sensor threads should run with SCHED_FIFO, but its not clear to me if
> they should have a priority above or below or equal to that of the
> engine thread.

Above, as they have to be able to preempt the engine to get correct
timestamps.

> >Anyway... FIFO. Any other behavior would be erroneous and fatal in
> >this case. If your events are late for the cycle, you're missing a
> >deadline, which is a Very Bad Thing(tm) in a real time system.
>
> >> >Actually, there's one more level; the transfer of the finished list
> >> >of events (for the cycle) to the destination port.
> >>
> >> this can't happen without locking. we don't want to do this.
> >
> >A FIFO doesn't need locking in the single reader - single writer
> >case, and it also allows queueing of multiple event buffers. That
> >means we get cycle period matching almost for free. The engine only
> >needs to grab the buffers one by one and do the compulsory time stamp
> >conversion.
>
> time stamp conversion ? the sensor thread should have timestamped the
> events with the same timebase as the engine. hence:
>
> ev->timestamp = engine->timestamp();

Yes... But that means plug-ins will recieve events with running sample
clock timestamps, rather than start of buffer == 0.

Both system work, but is it a good idea to force every single plug-in
to convert the timestamps of all events it recieves, or to keep track
of the time base of the port(s) they send to?

My idea is that time == local time, at least for plug-ins.

> >> sorry, this won't work. once again, a sensor thread is not going to
> >> wait for a command to "finish the cycle". its working asynchronously
> >> with respect to the engine.
> >
> >So, your "cycle time" will have to be based on the only wake up
> >source you have; the device you're sensing. However, that does not
> >mean that you have to pass one event at a time. Just send'em all of
> >before you go back to sleep.
>
> well, yes, of course. but the point here is that this sending will
> happen (potentially) in the middle of the engine's control
> cycle, not at a point defined by the engine.

Yes, but if you're not missing the deadline, the event is going in
when it's supposed to; during the next cycle or later.

> the overall point here is to think of the engine as collecting events
> from the subscribable ports, not as the sensor threads delivering them
> anywhere. then all this "shadow port" stuff goes away. the only key
> thing, as i said before, is to ensure that we have reliable lock-free
> event queues for the ports.

Yes, but you want both threads to mess with the same event port
without locking?

1) The lock free queue gets in the inline code, rather than
   into the finish_cycle() API library *function call*.

2) There's no efficient way you can handle multiple senders
   to one port without shadow ports. Why *sort* events inside
   a lock free queue, when you can merge events from queues
   that you know contain events in order?

3) There's possibly more to the event port than point-to-point
   event transfer. This could mean more than one sync problem.
   How much complexity do we want to show through the API...?

IMO, direct access of the event port is only to be done when you're
in the same context (that is, same thread, same cycle time) as the
destination port, *and* you're the ony one sending to that port. (The
engine might work around that, but that's another story...) If there
are N senders, N-1 of them will get shadow ports, so that the engine
can get away with a single merge operation, in case the destination
port requires events to come in order. (Note: In VST 2.0, plug-ins
*have* to sort events themselves if they care... How nice is that?)

> [ ... handling non-shared memory stuff ... ]
>
> >Ok, just set up a communication thread with a sensible cycle rate, in
> >case event rate >> fixed latency. ("Fixed latency" being the jitter
> >elimination delay that makes time stamps useful.) What I mean is that
> >it's insane to send events 20 times during a single fixed latency
> >period.
>
> not really, if you forget about this idea of "sending" as an active
> thing. you're just putting events on a queue. somebody else will take
> them off when they're ready.

Yes, with a lock free queue, you're right. And the communication
thread would still work.

> >No, that's not the idea. I only want to clean up the API, and make it
> >posible to change the implementation without breaking the API.
> >
> >API != implementation.
>
> yep. and i think we agree that using a communication thread will
> satisfy this, so we can exclude all considerations of non-shared
> memory from our discussion :)

Yep, seems like it. :-)

However, let's not forget about non-shared memory completely, as that
might hurt a lot later on...

> >> aha! you admit it: "runs whenever it wants". this is why the
> >> "finish_cycle" operation idea won't work.
> >
> >finish_cycle() *can* be called whenever you want. (Plug-ins don't
> >need it, as returning from process() has the same meaning.) It's just
> >that *recommending* that it's not called more frequently than
> >necessary will make optimization of the implementation a bit easier.
>
> you write as if the engine calls finish_cycle(), and this is what i
> meant would not work. sure, a sensor thread can do this whenever it
> likes, but then it doesn't need a special name - its just another
> thing the sensor thread does on its own.

What about the API, then? *Every* MCS "client" will need to do the
finish_cycle() operation, and as it's the perfect hook for special
MCS implementations, I think it's silly leaving it out. It could be a
NOP, but because of the shadow ports, it probably won't.

//David

 ·A·U·D·I·A·L·I·T·Y· P r o f e s s i o n a l L i n u x A u d i o
- - ------------------------------------------------------------- - -
    ·Rock Solid David Olofson:
    ·Low Latency www.angelfire.com/or/audiality ·Audio Hacker
    ·Plug-Ins audiality_AT_swipnet.se ·Linux Advocate
    ·Open Source ·Singer/Composer


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : pe maalis 10 2000 - 07:27:13 EST