Mips scalibility problems & softirq.c improvments

From: D.J. Barrow (barrow_dj@yahoo.com)
Date: Mon May 13 2002 - 05:12:34 EST


Hi,
While testing the SMP performance of iptables with a lot of rules on a mips based cpu,
I found that the SMP performance was 40% lower on 2 cpus than 1 cpu.

There is a number of reasons for this the primary being that the rules were bigger
than the shared L2 cache, little enough can be done about this.

The second is that interrupts are on every mips port I bothered checking
are only delivered on cpu 0 ( this is really pathetic ).

See the code that prints /proc/interrupts in arch/mips/kernel/irq.c
int get_irq_list(char *buf)
{
        struct irqaction * action;
        char *p = buf;
        int i;

        p += sprintf(p, " ");
        for (i=0; i < 1 /*smp_num_cpus*/; i++)

Need I say more.....

As softirqs are usually bound to the same
cpu that start the softirqs softirqs performs really really badly,
also the fact that the softirq.c code checks in_interrupt on
entry means that it frequently does a quick exit.

I also will be providing a patch I developed to the developers of a mips based
system on chip which distributes the irqs over all cpus using 2 polices
even interrupts to cpu 0 odd interrupts to cpu 1 or leaving the interrupts
enter in all cpus & only call do_IRQ on the cpu with the lowest local_irq_count
 & local_bh_count this should cause softirqs to perform will on this
system anyway.

I've provided a small patch to irq.c which fixes /proc/interrupts in 2.4.18 mips32
hopefully somebody will be kind enough to fix up the 64 bit &
the latest stuff in mips64 & the latest oss.sgi.com cvs trees.

--- linux.orig/arch/mips/kernel/irq.c Sun Sep 9 18:43:01 2001
+++ linux/arch/mips/kernel/irq.c Mon May 13 10:34:15 2002
@@ -71,13 +71,13 @@

 int get_irq_list(char *buf)
 {
+ int i, j;
        struct irqaction * action;
        char *p = buf;
- int i;

        p += sprintf(p, " ");
- for (i=0; i < 1 /*smp_num_cpus*/; i++)
- p += sprintf(p, "CPU%d ", i);
+ for (j=0; j<smp_num_cpus; j++)
+ p += sprintf(p, "CPU%d ",j);
        *p++ = '\n';

        for (i = 0 ; i < NR_IRQS ; i++) {
@@ -85,7 +85,13 @@
                if (!action)
                        continue;
                p += sprintf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
                p += sprintf(p, "%10u ", kstat_irqs(i));
+#else
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
+#endif
                p += sprintf(p, " %14s", irq_desc[i].handler->typename);
                p += sprintf(p, " %s", action->name);

@@ -93,7 +99,7 @@
                        p += sprintf(p, ", %s", action->name);
                *p++ = '\n';
        }
- p += sprintf(p, "ERR: %10lu\n", irq_err_count);
+ p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
        return p - buf;
 }

I also provide a small patch for softirq.c which makes sure the
the softirqs stay running if in cpu_idle & no reschedule is pending.
This improves softirq.c performance a small bit as it usually exits
after calling each softirq once rather than staying in the loop
if it has nothing better to do.

--- linux.old/kernel/softirq.c Tue Jan 15 04:13:43 2002
+++ linux.new/kernel/softirq.c Thu May 9 12:36:46 2002
@@ -95,7 +95,8 @@
                local_irq_disable();

                pending = softirq_pending(cpu);
- if (pending & mask) {
+ if ((pending && current==idle_task(cpu) && !current->need_resched )
+ || (pending & mask) ) {
                        mask &= ~pending;
                        goto restart;
                }
diff -u -r linux.old/include/linux/sched.h linux.new/include/linux/sched.h
--- linux.old/include/linux/sched.h Thu May 9 18:08:42 2002
+++ linux.new/include/linux/sched.h Thu May 9 10:30:34 2002
@@ -936,6 +936,19 @@
        return res;
 }

+#ifdef CONFIG_SMP
+
+#define idle_task(cpu) (init_tasks[cpu_number_map(cpu)])
+#define can_schedule(p,cpu) \
+ ((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu))
+
+#else
+
+#define idle_task(cpu) (&init_task)
+#define can_schedule(p,cpu) (1)
+
+#endif
+
 #endif /* __KERNEL__ */

 #endif

diff -u -r linux.old/kernel/sched.c linux.new/kernel/sched.c
--- linux.old/kernel/sched.c Wed May 1 10:40:26 2002
+++ linux.new/kernel/sched.c Thu May 9 10:30:26 2002
@@ -112,18 +112,7 @@
 struct kernel_stat kstat;
 extern struct task_struct *child_reaper;

-#ifdef CONFIG_SMP

-#define idle_task(cpu) (init_tasks[cpu_number_map(cpu)])
-#define can_schedule(p,cpu) \
- ((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu))
-
-#else
-
-#define idle_task(cpu) (&init_task)
-#define can_schedule(p,cpu) (1)
-
-#endif

 void scheduling_functions_start_here(void) { }

Also find the patches sent as attachments.

=====
D.J. Barrow Linux kernel developer
eMail: dj_barrow@ariasoft.ie
Home: +353-22-47196.
Work: +353-91-758353

__________________________________________________
Do You Yahoo!?
LAUNCH - Your Yahoo! Music Experience
http://launch.yahoo.com




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



This archive was generated by hypermail 2b29 : Tue May 14 2002 - 12:00:19 EST