diff options
author | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | 2010-10-27 18:34:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-27 21:03:13 -0400 |
commit | 478735e38887077ac77a9756121b6ce0cb956e2f (patch) | |
tree | 7b42110f71b1711f56cbbc0a01f00894b221337d | |
parent | f2c66cd8eeddedb440f33bc0f5cec1ed7ae376cb (diff) |
/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>
-rw-r--r-- | fs/proc/stat.c | 10 | ||||
-rw-r--r-- | include/linux/kernel_stat.h | 4 | ||||
-rw-r--r-- | kernel/irq/irqdesc.c | 15 |
3 files changed, 21 insertions, 8 deletions
diff --git a/fs/proc/stat.c b/fs/proc/stat.c index b80c620565bf..e15a19c93bae 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c | |||
@@ -31,7 +31,6 @@ static int show_stat(struct seq_file *p, void *v) | |||
31 | u64 sum_softirq = 0; | 31 | u64 sum_softirq = 0; |
32 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; | 32 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; |
33 | struct timespec boottime; | 33 | struct timespec boottime; |
34 | unsigned int per_irq_sum; | ||
35 | 34 | ||
36 | user = nice = system = idle = iowait = | 35 | user = nice = system = idle = iowait = |
37 | irq = softirq = steal = cputime64_zero; | 36 | irq = softirq = steal = cputime64_zero; |
@@ -108,13 +107,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
108 | seq_printf(p, "intr %llu", (unsigned long long)sum); | 107 | seq_printf(p, "intr %llu", (unsigned long long)sum); |
109 | 108 | ||
110 | /* sum again ? it could be updated? */ | 109 | /* sum again ? it could be updated? */ |
111 | for_each_irq_nr(j) { | 110 | for_each_irq_nr(j) |
112 | per_irq_sum = 0; | 111 | seq_printf(p, " %u", kstat_irqs(j)); |
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 | } | ||
118 | 112 | ||
119 | seq_printf(p, | 113 | seq_printf(p, |
120 | "\nctxt %llu\n" | 114 | "\nctxt %llu\n" |
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 8b9b89085530..ad54c846911b 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h | |||
@@ -86,6 +86,7 @@ static inline unsigned int kstat_softirqs_cpu(unsigned int irq, int cpu) | |||
86 | /* | 86 | /* |
87 | * Number of interrupts per specific IRQ source, since bootup | 87 | * Number of interrupts per specific IRQ source, since bootup |
88 | */ | 88 | */ |
89 | #ifndef CONFIG_GENERIC_HARDIRQS | ||
89 | static inline unsigned int kstat_irqs(unsigned int irq) | 90 | static inline unsigned int kstat_irqs(unsigned int irq) |
90 | { | 91 | { |
91 | unsigned int sum = 0; | 92 | unsigned int sum = 0; |
@@ -96,6 +97,9 @@ static inline unsigned int kstat_irqs(unsigned int irq) | |||
96 | 97 | ||
97 | return sum; | 98 | return sum; |
98 | } | 99 | } |
100 | #else | ||
101 | extern unsigned int kstat_irqs(unsigned int irq); | ||
102 | #endif | ||
99 | 103 | ||
100 | /* | 104 | /* |
101 | * Number of interrupts per cpu, since bootup | 105 | * Number of interrupts per cpu, since bootup |
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 9d917ff72675..9988d03797f5 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c | |||
@@ -393,3 +393,18 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) | |||
393 | struct irq_desc *desc = irq_to_desc(irq); | 393 | struct irq_desc *desc = irq_to_desc(irq); |
394 | return desc ? desc->kstat_irqs[cpu] : 0; | 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 */ | ||