Re: Important patch to fix select!

Jamie Lokier (lkd@tantalophile.demon.co.uk)
Mon, 12 Jul 1999 17:39:24 +0200


Bernd Paysan wrote:
> For visual effects, the resolution of
> the OS timers generally is good enough (50 HZ are sufficient), but for
> sound, it's not. I've written an accurate MIDI player (using
> busy-waiting), and although the Linux kernel allows MIDI events to
> schedule at 100 HZ, you hear the difference for some special cases (like
> pitching a tone in a slope). Certainly you also hear a busy machine, but
> it isn't that awful on Linux, since the MIDI player gets a quite high
> dynamic priority.

MIDI is going to have those problems until you've got millisecond
accuracy. More so if you're triggering sounds close together to get
fake reverb effects. Really the sending of MIDI events should be timed
and handled by the sound driver, not the app. (My humble opinion).

However dynamically synthesised sound done in software works very well
even at 20Hz or so. That gets you about 50ms of lag between decision
and sound but the real world is just like that so it sounds great. Of
course your advanced mixer/synthesiser engine will time the actual start
of each sample _within_ each audio fragment to the sample point, won't
it? Well mine did :-)

> What I want from an OS (if it can't give me a precise timer), is at
> least allow a timer+busy waiting strategy.

gettimeofday() works pretty well and portably for the busy waiting part.
Linux used to have problems with it being not monotonic, and jumps and
so on. Never mind.

Busy waiting is a waste of good CPU time though -- which you could be
using for a background audio mix or even AIs if you're clever.

> The first timer that comes in mind is the setitimer timer - just do what
> the OS has to do in user space. However, timer signals are a bad idea
> under Unix, since with such a timer, you get EAGAIN all over the
> place.

No you don't -- set all syscalls restarteable by flagging the signals to
do that: see sigaction() and SA_RESTART.

Timers have pretty coarse granularity though for much the same reason as
select(). Signal delivery is traditionally thought of as quite slow --
I have a nagging feeling that select() is known to give more accurate
timeouts than timer signals on many systems.

> So next idea is select(). After all, you might be expecting some data
> anyway (e.g. on the pipe to X). Select's timeout has two disadvantageous
> properties: first, it's a delta. All my timer codes use absolute timers,
> which allows for predictable repetition, and a lot of other fine
> properties (especially that the timeout doesn't change with delay during
> process of a timer wait function). But worse, only select's man page
> does guarantee that it will return in time.

Don't worry about the delta time. It's not perfect, but gettimeofday()
followed immediately by select() is a good approximation. Not good
enough for hard RT, but in practice it's always good enough.

> What's my workaround?
>
> First, I measure the actual worst-case delay of select(), that is I call
> select with a 20 ms timeout (if the machine is idle, that'll return just
> after a tick occured). Then I call gettimeofday(), select with 1 ms
> timeout, and gettimeofday() again. Until recently, the time difference
> was almost 20 ms. The improvement the patch in this thread was to "fix"
> about gives me almost 10 ms (the current experimental kernel select is
> conformant with the somewhat contradictionary POSIX description).

Yes I think at very least you should be able to wait approx. 10ms, and
not have 20ms be the enforced minimum.

> What I really want is less than or up to 1 ms - first, because that's
> what's literally in the select manpage,

The select() man page is a bit optimistic here methinks. It's always
been the case that (a) there's a timeout then (b) process is woken and
goes on run queue and then (c) eventually gets a timeslice.

> and second, because that allows me to busy-wait only when busy-waiting
> *really is necessary*, and no more than that.

Go check out the UTIME patch to see that *no* busy waiting is necessary,
in principle (on systems that can do utime):

http://hegel.ittc.ukans.edu/projects/utime/

In practice that would amount to treating a utime-d kernel as one having
a very short tick. You still want to run well on other kernels and
other systems after all.

> And finally a rant to all CPU designers:
>
> Add a timer source to your CPU! It needs one cyclic counter (one tick
> per clock, like the TSC, could also be one tick per bus clock; I'm
> completely agnostig about increment or decrement, but the wrapover must
> be more than 10 ms), and one compare register. Issue an interrupt when
> the compare register becomes equal to the timer. And add a "reset all
> timers" pin/command and a master clock signal to your SMP bus
> specification. Timers must be in sync!

Take a look at the Pentium local APIC sometime. I haven't looked but
I've been told it does have a high-resolution local timer than can issue
interrupts.

Actually my wish list is starting to include: suspend individual
interrupt sources for X ticks. For batching input from network packet
drivers.

-- Jamie

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/