Commit 3c829c367a1a52550378584a657768217971e587

Authored by Tim Chen
Committed by Linus Torvalds
1 parent 953a7f2066

[PATCH] Reducing local_bh_enable/disable overhead in irqtrace

The recent changes from irqtrace feature has added overheads to
local_bh_disable and local_bh_enable that reduces UDP performance across
x86_64 and IA64, even though IA64 does not support the irqtrace feature.
Patch in question is

[PATCH]lockdep: irqtrace subsystem, core
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=c
ommit;h=de30a2b355ea85350ca2f58f3b9bf4e5bc007986

Prior to this patch, local_bh_disable was a short macro.  Now it is a
function which calls __local_bh_disable with added irq flags save and
restore.  The irq flags save and restore were also added to
local_bh_enable, probably for injecting the trace irqs code.

This overhead is on the generic code path across all architectures.  On a
IA_64 test machine (Itanium-2 1.6 GHz) running a benchmark like netperf's
UDP streaming test, the added overhead results in a drop of 3% in
throughput, as udp_sendmsg calls the local_bh_enable/disable several times.

Other workloads that have heavy usages of local_bh_enable/disable could
also be affected.  The patch ideally should not have affected IA-64
performance as it does not have IRQ tracing support.  A significant portion
of the overhead is in the added irq flags save and restore, which I think
is not needed if IRQ tracing is unused.  A suggested patch is attached
below that recovers the lost performance.  However, the "ifdef"s in the
patch are a bit ugly.

Signed-off-by: Tim Chen <tim.c.chen@intel.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 1 changed file with 18 additions and 0 deletions Side-by-side Diff

... ... @@ -65,6 +65,7 @@
65 65 * This one is for softirq.c-internal use,
66 66 * where hardirqs are disabled legitimately:
67 67 */
  68 +#ifdef CONFIG_TRACE_IRQFLAGS
68 69 static void __local_bh_disable(unsigned long ip)
69 70 {
70 71 unsigned long flags;
... ... @@ -80,6 +81,13 @@
80 81 trace_softirqs_off(ip);
81 82 raw_local_irq_restore(flags);
82 83 }
  84 +#else /* !CONFIG_TRACE_IRQFLAGS */
  85 +static inline void __local_bh_disable(unsigned long ip)
  86 +{
  87 + add_preempt_count(SOFTIRQ_OFFSET);
  88 + barrier();
  89 +}
  90 +#endif /* CONFIG_TRACE_IRQFLAGS */
83 91  
84 92 void local_bh_disable(void)
85 93 {
86 94  
87 95  
88 96  
... ... @@ -121,12 +129,16 @@
121 129  
122 130 void local_bh_enable(void)
123 131 {
  132 +#ifdef CONFIG_TRACE_IRQFLAGS
124 133 unsigned long flags;
125 134  
126 135 WARN_ON_ONCE(in_irq());
  136 +#endif
127 137 WARN_ON_ONCE(irqs_disabled());
128 138  
  139 +#ifdef CONFIG_TRACE_IRQFLAGS
129 140 local_irq_save(flags);
  141 +#endif
130 142 /*
131 143 * Are softirqs going to be turned on now:
132 144 */
133 145  
134 146  
135 147  
... ... @@ -142,18 +154,22 @@
142 154 do_softirq();
143 155  
144 156 dec_preempt_count();
  157 +#ifdef CONFIG_TRACE_IRQFLAGS
145 158 local_irq_restore(flags);
  159 +#endif
146 160 preempt_check_resched();
147 161 }
148 162 EXPORT_SYMBOL(local_bh_enable);
149 163  
150 164 void local_bh_enable_ip(unsigned long ip)
151 165 {
  166 +#ifdef CONFIG_TRACE_IRQFLAGS
152 167 unsigned long flags;
153 168  
154 169 WARN_ON_ONCE(in_irq());
155 170  
156 171 local_irq_save(flags);
  172 +#endif
157 173 /*
158 174 * Are softirqs going to be turned on now:
159 175 */
160 176  
... ... @@ -169,7 +185,9 @@
169 185 do_softirq();
170 186  
171 187 dec_preempt_count();
  188 +#ifdef CONFIG_TRACE_IRQFLAGS
172 189 local_irq_restore(flags);
  190 +#endif
173 191 preempt_check_resched();
174 192 }
175 193 EXPORT_SYMBOL(local_bh_enable_ip);