Ingo Molnar wrote:
below i've also attached a softirq.c patch against 2.6.8-rc2 that does
unconditional deferring. (this patch is of course not intended to be
merged upstream as-is, since normally we want to process softirqs
right after the irq context.)


i've got a more complete patch against vanilla 2.6.8-rc2:

 http://redhat.com/~mingo/voluntary-preempt/defer-softirqs-2.6.8-rc2-A2

which introduces the following tunable:

    /proc/sys/kernel/defer_softirqs  (default: 0)

this, if enabled, causes all softirqs to be processed within ksoftirqd,
and it also breaks out of the softirq loop if preemption of ksoftirqd
has been triggered by a higher-prio task.

I've also added this additional break-out to the -H6 patch of
voluntary-preempt:

  http://redhat.com/~mingo/voluntary-preempt/voluntary-preempt-2.6.8-rc2-H6

it's enabled by default.


What do you think about deferring softirqs just while in critical sections?

I'm not sure how well this works, and it is CONFIG_PREEMPT only
but in theory it should prevent unbounded softirqs while under
locks without taking the performance hit of doing the context
switch.


---

 linux-2.6-npiggin/include/asm-i386/hardirq.h |    8 ++++++--
 linux-2.6-npiggin/include/linux/preempt.h    |    6 +-----
 linux-2.6-npiggin/kernel/sched.c             |   13 +++++++++++--
 linux-2.6-npiggin/kernel/softirq.c           |    4 ++--
 4 files changed, 20 insertions(+), 11 deletions(-)

diff -puN kernel/softirq.c~lat-softirq kernel/softirq.c
--- linux-2.6/kernel/softirq.c~lat-softirq	2004-07-17 00:32:52.000000000 +1000
+++ linux-2.6-npiggin/kernel/softirq.c	2004-07-17 00:32:52.000000000 +1000
@@ -68,7 +68,7 @@ static inline void wakeup_softirqd(void)
  * we want to handle softirqs as soon as possible, but they
  * should not be able to lock up the box.
  */
-#define MAX_SOFTIRQ_RESTART 10
+#define MAX_SOFTIRQ_RESTART 4
 
 asmlinkage void __do_softirq(void)
 {
@@ -322,7 +322,7 @@ void __init softirq_init(void)
 
 static int ksoftirqd(void * __bind_cpu)
 {
-	set_user_nice(current, 19);
+	set_user_nice(current, 10);
 	current->flags |= PF_NOFREEZE;
 
 	set_current_state(TASK_INTERRUPTIBLE);
diff -puN include/asm-i386/hardirq.h~lat-softirq include/asm-i386/hardirq.h
--- linux-2.6/include/asm-i386/hardirq.h~lat-softirq	2004-07-17 00:32:52.000000000 +1000
+++ linux-2.6-npiggin/include/asm-i386/hardirq.h	2004-07-17 00:32:52.000000000 +1000
@@ -80,17 +80,21 @@ typedef struct {
 # include <linux/smp_lock.h>
 # define in_atomic()	((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
+#define irq_exit()							\
+do {									\
+		preempt_count() -= IRQ_EXIT_OFFSET;			\
+		preempt_enable_no_resched(); /* This will catch the softirq */ \
+} while (0)
 #else
 # define in_atomic()	(preempt_count() != 0)
 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
-#endif
 #define irq_exit()							\
 do {									\
 		preempt_count() -= IRQ_EXIT_OFFSET;			\
 		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
 			do_softirq();					\
-		preempt_enable_no_resched();				\
 } while (0)
+#endif
 
 #ifndef CONFIG_SMP
 # define synchronize_irq(irq)	barrier()
diff -puN include/linux/preempt.h~lat-softirq include/linux/preempt.h
--- linux-2.6/include/linux/preempt.h~lat-softirq	2004-07-17 00:32:52.000000000 +1000
+++ linux-2.6-npiggin/include/linux/preempt.h	2004-07-17 00:32:52.000000000 +1000
@@ -16,12 +16,8 @@ do { \
 	preempt_count()++; \
 } while (0)
 
-#define dec_preempt_count() \
-do { \
-	preempt_count()--; \
-} while (0)
-
 #ifdef CONFIG_PREEMPT
+void dec_preempt_count(void);
 
 asmlinkage void preempt_schedule(void);
 
diff -puN kernel/sched.c~lat-softirq kernel/sched.c
--- linux-2.6/kernel/sched.c~lat-softirq	2004-07-17 00:32:52.000000000 +1000
+++ linux-2.6-npiggin/kernel/sched.c	2004-07-17 00:32:52.000000000 +1000
@@ -3968,8 +3968,16 @@ void __might_sleep(char *file, int line)
 EXPORT_SYMBOL(__might_sleep);
 #endif
 
+#ifdef CONFIG_PREEMPT
+void dec_preempt_count(void)
+{
+	if (unlikely(preempt_count() == 1 &&
+				softirq_pending(smp_processor_id())))
+		do_softirq();
+	preempt_count()--;
+}
 
-#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT)
+#ifdef CONFIG_SMP
 /*
  * This could be a long-held lock.  If another CPU holds it for a long time,
  * and that CPU is not asked to reschedule then *this* CPU will spin on the
@@ -4012,4 +4020,5 @@ void __sched __preempt_write_lock(rwlock
 }
 
 EXPORT_SYMBOL(__preempt_write_lock);
-#endif /* defined(CONFIG_SMP) && defined(CONFIG_PREEMPT) */
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_PREEMPT */

_

Reply via email to