Commit 478735e38887077ac77a9756121b6ce0cb956e2f
Committed by
Linus Torvalds
1 parent
f2c66cd8ee
Exists in
master
and in
7 other branches
/proc/stat: fix scalability of irq sum of all cpu
In /proc/stat, the number of per-IRQ event is shown by making a sum each irq's events on all cpus. But we can make use of kstat_irqs(). kstat_irqs() do the same calculation, If !CONFIG_GENERIC_HARDIRQ, it's not a big cost. (Both of the number of cpus and irqs are small.) If a system is very big and CONFIG_GENERIC_HARDIRQ, it does for_each_irq() for_each_cpu() - look up a radix tree - read desc->irq_stat[cpu] This seems not efficient. This patch adds kstat_irqs() for CONFIG_GENRIC_HARDIRQ and change the calculation as for_each_irq() look up radix tree for_each_cpu() - read desc->irq_stat[cpu] This reduces cost. A test on (4096cpusp, 256 nodes, 4592 irqs) host (by Jack Steiner) %time cat /proc/stat > /dev/null Before Patch: 2.459 sec After Patch : .561 sec [akpm@linux-foundation.org: unexport kstat_irqs, coding-style tweaks] [akpm@linux-foundation.org: fix unused variable 'per_irq_sum'] Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Tested-by: Jack Steiner <steiner@sgi.com> Acked-by: Jack Steiner <steiner@sgi.com> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 3 changed files with 21 additions and 8 deletions Side-by-side Diff
fs/proc/stat.c
... | ... | @@ -31,7 +31,6 @@ |
31 | 31 | u64 sum_softirq = 0; |
32 | 32 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; |
33 | 33 | struct timespec boottime; |
34 | - unsigned int per_irq_sum; | |
35 | 34 | |
36 | 35 | user = nice = system = idle = iowait = |
37 | 36 | irq = softirq = steal = cputime64_zero; |
... | ... | @@ -108,13 +107,8 @@ |
108 | 107 | seq_printf(p, "intr %llu", (unsigned long long)sum); |
109 | 108 | |
110 | 109 | /* sum again ? it could be updated? */ |
111 | - for_each_irq_nr(j) { | |
112 | - per_irq_sum = 0; | |
113 | - for_each_possible_cpu(i) | |
114 | - per_irq_sum += kstat_irqs_cpu(j, i); | |
115 | - | |
116 | - seq_printf(p, " %u", per_irq_sum); | |
117 | - } | |
110 | + for_each_irq_nr(j) | |
111 | + seq_printf(p, " %u", kstat_irqs(j)); | |
118 | 112 | |
119 | 113 | seq_printf(p, |
120 | 114 | "\nctxt %llu\n" |
include/linux/kernel_stat.h
... | ... | @@ -86,6 +86,7 @@ |
86 | 86 | /* |
87 | 87 | * Number of interrupts per specific IRQ source, since bootup |
88 | 88 | */ |
89 | +#ifndef CONFIG_GENERIC_HARDIRQS | |
89 | 90 | static inline unsigned int kstat_irqs(unsigned int irq) |
90 | 91 | { |
91 | 92 | unsigned int sum = 0; |
... | ... | @@ -96,6 +97,9 @@ |
96 | 97 | |
97 | 98 | return sum; |
98 | 99 | } |
100 | +#else | |
101 | +extern unsigned int kstat_irqs(unsigned int irq); | |
102 | +#endif | |
99 | 103 | |
100 | 104 | /* |
101 | 105 | * Number of interrupts per cpu, since bootup |
kernel/irq/irqdesc.c
... | ... | @@ -393,4 +393,19 @@ |
393 | 393 | struct irq_desc *desc = irq_to_desc(irq); |
394 | 394 | return desc ? desc->kstat_irqs[cpu] : 0; |
395 | 395 | } |
396 | + | |
397 | +#ifdef CONFIG_GENERIC_HARDIRQS | |
398 | +unsigned int kstat_irqs(unsigned int irq) | |
399 | +{ | |
400 | + struct irq_desc *desc = irq_to_desc(irq); | |
401 | + int cpu; | |
402 | + int sum = 0; | |
403 | + | |
404 | + if (!desc) | |
405 | + return 0; | |
406 | + for_each_possible_cpu(cpu) | |
407 | + sum += desc->kstat_irqs[cpu]; | |
408 | + return sum; | |
409 | +} | |
410 | +#endif /* CONFIG_GENERIC_HARDIRQS */ |