diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-06-10 15:45:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-06-11 19:23:59 -0400 |
commit | 8f0ea0fe3a036a47767f9c80e81b13e379a1f43b (patch) | |
tree | 6f4079c8da32f3e1ac4860ac9f90b26e9df86e3b /include/net/snmp.h | |
parent | 830a9c75514b477994fd3847f72654d3dbdfa5ca (diff) |
snmp: reduce percpu needs by 50%
SNMP mibs use two percpu arrays, one used in BH context, another in USER
context. With increasing number of cpus in machines, and fact that ipv6
uses per network device ipstats_mib, this is consuming a lot of memory
if many network devices are registered.
commit be281e554e2a (ipv6: reduce per device ICMP mib sizes) shrinked
percpu needs for ipv6, but we can reduce memory use a bit more.
With recent percpu infrastructure (irqsafe_cpu_inc() ...), we no longer
need this BH/USER separation since we can update counters in a single
x86 instruction, regardless of the BH/USER context.
Other arches than x86 might need to disable irq in their
irqsafe_cpu_inc() implementation : If this happens to be a problem, we
can make SNMP_ARRAY_SZ arch dependent, but a previous poll
( https://lkml.org/lkml/2011/3/17/174 ) to arch maintainers did not
raise strong opposition.
Only on 32bit arches, we need to disable BH for 64bit counters updates
done from USER context (currently used for IP MIB)
This also reduces vmlinux size :
1) x86_64 build
$ size vmlinux.before vmlinux.after
text data bss dec hex filename
7853650 1293772 1896448 11043870 a8841e vmlinux.before
7850578 1293772 1896448 11040798 a8781e vmlinux.after
2) i386 build
$ size vmlinux.before vmlinux.afterpatch
text data bss dec hex filename
6039335 635076 3670016 10344427 9dd7eb vmlinux.before
6037342 635076 3670016 10342434 9dd022 vmlinux.afterpatch
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Andi Kleen <andi@firstfloor.org>
CC: Ingo Molnar <mingo@elte.hu>
CC: Tejun Heo <tj@kernel.org>
CC: Christoph Lameter <cl@linux-foundation.org>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org
CC: linux-arch@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/snmp.h')
-rw-r--r-- | include/net/snmp.h | 86 |
1 files changed, 33 insertions, 53 deletions
diff --git a/include/net/snmp.h b/include/net/snmp.h index 479083a78b0c..8f0f9ac0307f 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h | |||
@@ -116,57 +116,51 @@ struct linux_xfrm_mib { | |||
116 | unsigned long mibs[LINUX_MIB_XFRMMAX]; | 116 | unsigned long mibs[LINUX_MIB_XFRMMAX]; |
117 | }; | 117 | }; |
118 | 118 | ||
119 | /* | 119 | #define SNMP_ARRAY_SZ 1 |
120 | * FIXME: On x86 and some other CPUs the split into user and softirq parts | 120 | |
121 | * is not needed because addl $1,memory is atomic against interrupts (but | ||
122 | * atomic_inc would be overkill because of the lock cycles). Wants new | ||
123 | * nonlocked_atomic_inc() primitives -AK | ||
124 | */ | ||
125 | #define DEFINE_SNMP_STAT(type, name) \ | 121 | #define DEFINE_SNMP_STAT(type, name) \ |
126 | __typeof__(type) __percpu *name[2] | 122 | __typeof__(type) __percpu *name[SNMP_ARRAY_SZ] |
127 | #define DEFINE_SNMP_STAT_ATOMIC(type, name) \ | 123 | #define DEFINE_SNMP_STAT_ATOMIC(type, name) \ |
128 | __typeof__(type) *name | 124 | __typeof__(type) *name |
129 | #define DECLARE_SNMP_STAT(type, name) \ | 125 | #define DECLARE_SNMP_STAT(type, name) \ |
130 | extern __typeof__(type) __percpu *name[2] | 126 | extern __typeof__(type) __percpu *name[SNMP_ARRAY_SZ] |
131 | |||
132 | #define SNMP_STAT_BHPTR(name) (name[0]) | ||
133 | #define SNMP_STAT_USRPTR(name) (name[1]) | ||
134 | 127 | ||
135 | #define SNMP_INC_STATS_BH(mib, field) \ | 128 | #define SNMP_INC_STATS_BH(mib, field) \ |
136 | __this_cpu_inc(mib[0]->mibs[field]) | 129 | __this_cpu_inc(mib[0]->mibs[field]) |
130 | |||
137 | #define SNMP_INC_STATS_USER(mib, field) \ | 131 | #define SNMP_INC_STATS_USER(mib, field) \ |
138 | this_cpu_inc(mib[1]->mibs[field]) | 132 | irqsafe_cpu_inc(mib[0]->mibs[field]) |
133 | |||
139 | #define SNMP_INC_STATS_ATOMIC_LONG(mib, field) \ | 134 | #define SNMP_INC_STATS_ATOMIC_LONG(mib, field) \ |
140 | atomic_long_inc(&mib->mibs[field]) | 135 | atomic_long_inc(&mib->mibs[field]) |
136 | |||
141 | #define SNMP_INC_STATS(mib, field) \ | 137 | #define SNMP_INC_STATS(mib, field) \ |
142 | this_cpu_inc(mib[!in_softirq()]->mibs[field]) | 138 | irqsafe_cpu_inc(mib[0]->mibs[field]) |
139 | |||
143 | #define SNMP_DEC_STATS(mib, field) \ | 140 | #define SNMP_DEC_STATS(mib, field) \ |
144 | this_cpu_dec(mib[!in_softirq()]->mibs[field]) | 141 | irqsafe_cpu_dec(mib[0]->mibs[field]) |
142 | |||
145 | #define SNMP_ADD_STATS_BH(mib, field, addend) \ | 143 | #define SNMP_ADD_STATS_BH(mib, field, addend) \ |
146 | __this_cpu_add(mib[0]->mibs[field], addend) | 144 | __this_cpu_add(mib[0]->mibs[field], addend) |
145 | |||
147 | #define SNMP_ADD_STATS_USER(mib, field, addend) \ | 146 | #define SNMP_ADD_STATS_USER(mib, field, addend) \ |
148 | this_cpu_add(mib[1]->mibs[field], addend) | 147 | irqsafe_cpu_add(mib[0]->mibs[field], addend) |
148 | |||
149 | #define SNMP_ADD_STATS(mib, field, addend) \ | 149 | #define SNMP_ADD_STATS(mib, field, addend) \ |
150 | this_cpu_add(mib[!in_softirq()]->mibs[field], addend) | 150 | irqsafe_cpu_add(mib[0]->mibs[field], addend) |
151 | /* | 151 | /* |
152 | * Use "__typeof__(*mib[0]) *ptr" instead of "__typeof__(mib[0]) ptr" | 152 | * Use "__typeof__(*mib[0]) *ptr" instead of "__typeof__(mib[0]) ptr" |
153 | * to make @ptr a non-percpu pointer. | 153 | * to make @ptr a non-percpu pointer. |
154 | */ | 154 | */ |
155 | #define SNMP_UPD_PO_STATS(mib, basefield, addend) \ | 155 | #define SNMP_UPD_PO_STATS(mib, basefield, addend) \ |
156 | do { \ | 156 | do { \ |
157 | __typeof__(*mib[0]) *ptr; \ | 157 | irqsafe_cpu_inc(mib[0]->mibs[basefield##PKTS]); \ |
158 | preempt_disable(); \ | 158 | irqsafe_cpu_add(mib[0]->mibs[basefield##OCTETS], addend); \ |
159 | ptr = this_cpu_ptr((mib)[!in_softirq()]); \ | ||
160 | ptr->mibs[basefield##PKTS]++; \ | ||
161 | ptr->mibs[basefield##OCTETS] += addend;\ | ||
162 | preempt_enable(); \ | ||
163 | } while (0) | 159 | } while (0) |
164 | #define SNMP_UPD_PO_STATS_BH(mib, basefield, addend) \ | 160 | #define SNMP_UPD_PO_STATS_BH(mib, basefield, addend) \ |
165 | do { \ | 161 | do { \ |
166 | __typeof__(*mib[0]) *ptr = \ | 162 | __this_cpu_inc(mib[0]->mibs[basefield##PKTS]); \ |
167 | __this_cpu_ptr((mib)[0]); \ | 163 | __this_cpu_add(mib[0]->mibs[basefield##OCTETS], addend); \ |
168 | ptr->mibs[basefield##PKTS]++; \ | ||
169 | ptr->mibs[basefield##OCTETS] += addend;\ | ||
170 | } while (0) | 164 | } while (0) |
171 | 165 | ||
172 | 166 | ||
@@ -179,40 +173,20 @@ struct linux_xfrm_mib { | |||
179 | ptr->mibs[field] += addend; \ | 173 | ptr->mibs[field] += addend; \ |
180 | u64_stats_update_end(&ptr->syncp); \ | 174 | u64_stats_update_end(&ptr->syncp); \ |
181 | } while (0) | 175 | } while (0) |
176 | |||
182 | #define SNMP_ADD_STATS64_USER(mib, field, addend) \ | 177 | #define SNMP_ADD_STATS64_USER(mib, field, addend) \ |
183 | do { \ | 178 | do { \ |
184 | __typeof__(*mib[0]) *ptr; \ | 179 | local_bh_disable(); \ |
185 | preempt_disable(); \ | 180 | SNMP_ADD_STATS64_BH(mib, field, addend); \ |
186 | ptr = __this_cpu_ptr((mib)[1]); \ | 181 | local_bh_enable(); \ |
187 | u64_stats_update_begin(&ptr->syncp); \ | ||
188 | ptr->mibs[field] += addend; \ | ||
189 | u64_stats_update_end(&ptr->syncp); \ | ||
190 | preempt_enable(); \ | ||
191 | } while (0) | 182 | } while (0) |
183 | |||
192 | #define SNMP_ADD_STATS64(mib, field, addend) \ | 184 | #define SNMP_ADD_STATS64(mib, field, addend) \ |
193 | do { \ | 185 | SNMP_ADD_STATS64_USER(mib, field, addend) |
194 | __typeof__(*mib[0]) *ptr; \ | 186 | |
195 | preempt_disable(); \ | ||
196 | ptr = __this_cpu_ptr((mib)[!in_softirq()]); \ | ||
197 | u64_stats_update_begin(&ptr->syncp); \ | ||
198 | ptr->mibs[field] += addend; \ | ||
199 | u64_stats_update_end(&ptr->syncp); \ | ||
200 | preempt_enable(); \ | ||
201 | } while (0) | ||
202 | #define SNMP_INC_STATS64_BH(mib, field) SNMP_ADD_STATS64_BH(mib, field, 1) | 187 | #define SNMP_INC_STATS64_BH(mib, field) SNMP_ADD_STATS64_BH(mib, field, 1) |
203 | #define SNMP_INC_STATS64_USER(mib, field) SNMP_ADD_STATS64_USER(mib, field, 1) | 188 | #define SNMP_INC_STATS64_USER(mib, field) SNMP_ADD_STATS64_USER(mib, field, 1) |
204 | #define SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1) | 189 | #define SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1) |
205 | #define SNMP_UPD_PO_STATS64(mib, basefield, addend) \ | ||
206 | do { \ | ||
207 | __typeof__(*mib[0]) *ptr; \ | ||
208 | preempt_disable(); \ | ||
209 | ptr = __this_cpu_ptr((mib)[!in_softirq()]); \ | ||
210 | u64_stats_update_begin(&ptr->syncp); \ | ||
211 | ptr->mibs[basefield##PKTS]++; \ | ||
212 | ptr->mibs[basefield##OCTETS] += addend; \ | ||
213 | u64_stats_update_end(&ptr->syncp); \ | ||
214 | preempt_enable(); \ | ||
215 | } while (0) | ||
216 | #define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) \ | 190 | #define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) \ |
217 | do { \ | 191 | do { \ |
218 | __typeof__(*mib[0]) *ptr; \ | 192 | __typeof__(*mib[0]) *ptr; \ |
@@ -222,6 +196,12 @@ struct linux_xfrm_mib { | |||
222 | ptr->mibs[basefield##OCTETS] += addend; \ | 196 | ptr->mibs[basefield##OCTETS] += addend; \ |
223 | u64_stats_update_end(&ptr->syncp); \ | 197 | u64_stats_update_end(&ptr->syncp); \ |
224 | } while (0) | 198 | } while (0) |
199 | #define SNMP_UPD_PO_STATS64(mib, basefield, addend) \ | ||
200 | do { \ | ||
201 | local_bh_disable(); \ | ||
202 | SNMP_UPD_PO_STATS64_BH(mib, basefield, addend); \ | ||
203 | local_bh_enable(); \ | ||
204 | } while (0) | ||
225 | #else | 205 | #else |
226 | #define SNMP_INC_STATS64_BH(mib, field) SNMP_INC_STATS_BH(mib, field) | 206 | #define SNMP_INC_STATS64_BH(mib, field) SNMP_INC_STATS_BH(mib, field) |
227 | #define SNMP_INC_STATS64_USER(mib, field) SNMP_INC_STATS_USER(mib, field) | 207 | #define SNMP_INC_STATS64_USER(mib, field) SNMP_INC_STATS_USER(mib, field) |