[lkml]   [1999]   [Jul]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Patch in this message
SubjectRe: real-time threaded IO with low latency (audio)
On Fri, 23 Jul 1999, Ingo Molnar wrote:
> On Fri, 23 Jul 1999, Sam Roberts wrote:
> > Sorry. If it gets your job done, great! I just think its an unfortunate
> > limitation of Linux. That Linux is optimized for throughput is great
> > for servers, and thats important. For personal workstations I don't think
> > its great. [...]
> hm, you havent been following Linux development for too long, have you?
> Latency was always the primary optimization target, bandwith the second.

> > As for the parts of Linux, like the scheduling alogrithm, that appear to
> > be optimized for multi-user time sharing systems, thats flat-out
> > archaic, in my view. [...]
> a severe misconception again. The Linux scheduler is optimized for
> latency, nothing else.

But while in kernel mode, in some parts of the buffer code, there are no
reschedules, preliminary tests show that a buffer.c patch from Andrea, shows
great improvements during non-DMAed EIDE disk transfers, and in
DMAed and mount -osync / transfers,
DMA + sync is really impressive , most of latency bursts stay below the 3ms mark
and even the /proc file system stress-test goes down from 9ms to 5.5 ms.
Unfortunately the mode which we need mostly, which is
DMA=on and async mounted disk, there are little improvements.

> the whole 'why sound skips' problem i think lacks one major necessery
> component: information. Nobody really ever analyzed what the problem
> really is/was. I do have a awe64 soundcard (which i almost never use), if
> you (or anyone else) could point to a method to make sound-playback
> produce bad quality, i'd be happy to analyze the problem. Is running
> mpg123 enough to see the problem? What should i do to make sound skip?

Mingo, take 10mins of your time, and try my latencytest,
I made this utility for the purpose to show up and track down latency problems
of the linux kernel.
It's very easy to use and it stresses several subsystems the kernel
( GFX, /proc files system, disk I/O)

You can get it here:

I'm sure that my program is able to produce at least 50-100ms latencies
on DMA=on EIDE disks, and at least 200-2000ms latencies with DMA=off.
SCSI might give a little better results, but the order of magnitude, is the
Christopher T. Lansdown sent me pictures on his Alpha box with UW SCSI disks,
and I must say, my PII400 + IBM 16GB EIDE disk performed better.

I'm trying a patch made by Andrea and modified Roger Larrson,
(attached below), which does resscheduling in some parts of buffer.c,
rescheduling in these parts helps especially in the DMA=off case,
because non DMA disk transfers use more CPU than DMA ones,
but IMHO the main problem is still the spinlocking collision.
Even usleep() is slowed down greatly during disk I/O and shows up
to 100-150ms scheduling latencies, and usleep() does not do so much
work, maybe usleep() is too a victim of spinlocking collision ?
Note that I conducted my tests on a HZ=1000 kernel, because
on HZ=100 I get only a minimum of 20ms usleep() accuracy ,
which is not suitable for low latency tests.

Roger suspects, that one more problem could persist in
ll_rw_block() , can you confim this ?
What are your opinion on the patch below ?

let me know !


> -- mingo
Benno Senoner
Linux scheduling latency benchmarks


Now there is a safe check in 'wait_for_buffer'.
And this does not lock up on me :-)

In addition to that, since it checks in
wait_for_buffer, it should help 'stress_diskread' too!
(Not verified since I have no baseline...)

I can not find another spot to fix in 'buffer.c',
there might be some issues in lower level drivers.
(I suspect ll_rw_block ...)


--- linux-2.2.10/fs/buffer.c Thu May 13 22:14:04 1999
+++ linux/fs/buffer.c Fri Jul 23 00:27:51 1999
@@ -131,11 +131,15 @@
struct task_struct *tsk = current;
struct wait_queue wait;

+ if (tsk->need_resched)// Since wait_on_buffer might end up in schedule
+ schedule(); // this should be safe - note: schedule() in
+ // TASK_UNINTERRUPTIBLE removes it from runqueue!
wait.task = tsk;
add_wait_queue(&bh->b_wait, &wait);
if (buffer_locked(bh)) {
@@ -214,6 +218,8 @@
* XXX We checked if it was locked above and there is no
* XXX way we could have slept in between. -DaveM
+ *
+ * Wrong: wait_on_buffer => schedule() ... /RogerL
if (buffer_locked(bh))
@@ -222,6 +228,8 @@
bh->b_flushtime = 0;
ll_rw_block(WRITE, 1, &bh);
+ if (current->need_resched) //RL analogue with Andreas patch
+ schedule();
retry = 1;
@@ -1090,6 +1098,10 @@
* Set our state for sleeping, then check again for buffer heads.
* This ensures we won't miss a wake_up from an interrupt.
+ if (current->need_resched)
+ schedule();
add_wait_queue(&buffer_wait, &wait);
current->state = TASK_UNINTERRUPTIBLE;
if (!recover_reusable_buffer_heads())
@@ -1622,8 +1634,12 @@

- if (buffer_locked(bh) || !buffer_dirty(bh))
- continue;
+ if (buffer_locked(bh) || !buffer_dirty(bh)) { //RL likely, looping throu all locked...
+ if (current->need_resched)
+ schedule(); // No worse than waiting for I/O to complete (handled above)
+ continue;
+ }
if(time_before(jiffies, bh->b_flushtime))
@@ -1636,6 +1652,8 @@
ll_rw_block(WRITE, 1, &bh);
+ if (current->need_resched)
+ schedule();
@@ -1644,7 +1662,7 @@
if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
printk("Wrote %d/%d buffers\n", nwritten, ndirty);
- run_task_queue(&tq_disk);
+ run_task_queue(&tq_disk); //RL why dual???
return 0;

@@ -1663,7 +1681,7 @@
goto out;

if (func == 1) {
- error = sync_old_buffers();
+ error = sync_old_buffers(); //RL shouldn't this be a parameter, and then "wakeup_bdflush(1)"
goto out;

@@ -1763,20 +1781,24 @@

- /* Clean buffer on dirty list? Refile it */
+ /* Clean buffer on dirty list? Refile it */ //RL unlikely, no resheduling needed
if (nlist == BUF_DIRTY && !buffer_dirty(bh)) {

- /* Unlocked buffer on locked list? Refile it */
+ /* Unlocked buffer on locked list? Refile it */ //RL unlikely, no resheduling needed
if (nlist == BUF_LOCKED && !buffer_locked(bh)) {

- if (buffer_locked(bh) || !buffer_dirty(bh))
+ if (buffer_locked(bh) || !buffer_dirty(bh)) { //RL likely, looping throu all locked...
+ if (current->need_resched)
+ schedule(); // No worse than waiting for I/O to complete (handled above)
+ }
major = MAJOR(bh->b_dev);
/* Should we write back buffers that are shared or not??
currently dirty buffers are not shared, so it does not matter */
@@ -1796,6 +1818,8 @@
if(nlist != BUF_DIRTY) ncount++;
+ if (current->need_resched)
+ schedule();

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to
Please read the FAQ at

 \ /
  Last update: 2005-03-22 13:53    [W:0.138 / U:0.680 seconds]
©2003-2018 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site