[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Interrupt latency problem



Eric Dönges <Eric.Doenges@xxxxxxx.de> writes:

> Hi all,
> 
> I'm having some trouble with interrupt latency and/or scheduling on my
> Etrax system. It seems that the kernel
> 
> a) Occasionally blocks interrupts for 10ms at a time.
> b) Occasionally takes 10ms (very occasionally, a multiple of 10ms)
> from calling wake_up_interruptible() in the
> interrupt service routine until the waiting process is actually
> running again (the process to run is set to be scheduled
> with SCHED_FIFO at the highest priority, so it should IMO get the CPU
> immediately).
> 
> Does anyone have any idea what could be causing this behaviour ?

The reason for the scheduling delay being 10 ms is simple, the timer
interrupt is set to 100Hz in the kernel, so if a process isn't
scheduled to run immediately after an interrupt, it will usually take
10ms until the next timer interrupt and the scheduler will notice that
your process is supposed to run.

Why your process isn't the top process to run is an interesting
problem though.  It may be that your process it sleeping on some other
event, and that this causes your process not to be scheduled.

If you increase the timer interrupt frequency you can probably reduce
the effects of a missed scheduling.  The following patch will increase
the frequency to 960Hz, but it does have the disadvantage that you
waste more time on scheduling.  Note that 19200 must be evenly
divisble by the frequency and that there are other limits in the
kernel that stop the frequency from being much higher than about
1200Hz, so you cant go up to 1920Hz.

This is just a workaround though, it doesn't solve the original
problem though.

  /Christer

diff -ur linux/arch/cris/kernel/setup.c.orig linux/arch/cris/kernel/setup.c
--- linux/arch/cris/kernel/setup.c.orig	2004-01-30 15:42:31.000000000 +0100
+++ linux/arch/cris/kernel/setup.c	2004-01-30 15:42:31.000000000 +0100
@@ -248,7 +251,8 @@
 		       "scsi\t\t: %s\n"
 		       "ata\t\t: %s\n"
 		       "usb\t\t: %s\n"
-		       "bogomips\t: %lu.%02lu\n",
+		       "bogomips\t: %lu.%02lu\n"
+		       "HZ\t\t: %u\n",
 
 		       revision,
 		       info->model,
@@ -262,6 +266,7 @@
 		       info->flags & HAS_ATA ? "yes" : "no",
 		       info->flags & HAS_USB ? "yes" : "no",
 		       (loops_per_jiffy * HZ + 500) / 500000,
-		       ((loops_per_jiffy * HZ + 500) / 5000) % 100);
+		       ((loops_per_jiffy * HZ + 500) / 5000) % 100,
+		       HZ);
 }
 #endif /* CONFIG_PROC_FS */
diff -ur linux/include/asm-cris/param.h.orig linux/include/asm-cris/param.h
--- linux/include/asm-cris/param.h.orig	2004-08-11 10:31:02.000000000 +0200
+++ linux/include/asm-cris/param.h	2004-08-11 10:31:27.000000000 +0200
@@ -2,7 +2,7 @@
 #define _ASMCRIS_PARAM_H
 
 #ifndef HZ
-#define HZ 100
+#define HZ 960
 #endif
 
 #define EXEC_PAGESIZE	8192
diff -ur linux/arch/cris/kernel/time.c.orig linux/arch/cris/kernel/time.c
--- linux/arch/cris/kernel/time.c.orig	2004-01-30 15:42:31.000000000 +0100
+++ linux/arch/cris/kernel/time.c	2004-01-30 15:42:31.000000000 +0100
@@ -435,9 +445,13 @@
 		IO_STATE( R_TIMER_CTRL, tm0, run) |
 		IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
 #else
+#define TIMER_DIV_VALUE (19200/HZ)
+#if 19200%HZ
+#error "HZ will give timer divisor rounding error" 
+#endif
 	*R_TIMER_CTRL = 
-		IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | 
-		IO_FIELD(R_TIMER_CTRL, timerdiv0, 192)      |
+ 		IO_FIELD(R_TIMER_CTRL, timerdiv1, TIMER_DIV_VALUE) | 
+ 		IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER_DIV_VALUE) | 
 		IO_STATE(R_TIMER_CTRL, i1,        nop)      | 
 		IO_STATE(R_TIMER_CTRL, tm1,       stop_ld)  |
 		IO_STATE(R_TIMER_CTRL, clksel1,   c19k2Hz)  |
@@ -446,8 +460,8 @@
 		IO_STATE(R_TIMER_CTRL, clksel0,   c19k2Hz);
 	
 	*R_TIMER_CTRL = r_timer_ctrl_shadow =
-		IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | 
-		IO_FIELD(R_TIMER_CTRL, timerdiv0, 192)      |
+ 		IO_FIELD(R_TIMER_CTRL, timerdiv1, TIMER_DIV_VALUE) | 
+ 		IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER_DIV_VALUE) | 
 		IO_STATE(R_TIMER_CTRL, i1,        nop)      |
 		IO_STATE(R_TIMER_CTRL, tm1,       run)      |
 		IO_STATE(R_TIMER_CTRL, clksel1,   c19k2Hz)  |



> 
> My setup is as follows:
> 
> I have a custom Etrax 100LX-based board running Linux 2.4.20. The
> Etrax talks with a FPGA that
> receives data from a Philips 7113 video slicer, puts this data into a
> FIFO and then raises an interrupt
> so that the Etrax can read and process the data; the processed data is
> then written back to the FPGA.
> The interrupt is raised every 40ms (i.e. for each video frame). The
> application doing the processing has
> two threads - one for receiving and sending data from/to the FPGA, and
> one to supervise the processing
> of the data. The actual processing is done by a (variable) number of
> "filter" processes forked by the main
> application. Both the main and the filter processes are set up to use
> the SCHED_FIFO policy, with the main
> process running at the highest priority, and the filters one priority
> level below that. Apart from these processes,
> the system is running sftpd, inetd, syslogd and ntpd. There is no
> disk, and there shouldn't be any writing to
> the flash file system either.
> 
> With kind regards,
> Eric
> 

-- 
"Just how much can I get away with and still go to heaven?"

Freelance consultant specializing in device driver programming for Linux 
Christer Weinigel <christer@xxxxxxx.se">http://www.weinigel.se