aboutsummaryrefslogtreecommitdiffstats
path: root/include/net/snmp.h
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-06-10 15:45:51 -0400
committerDavid S. Miller <davem@davemloft.net>2011-06-11 19:23:59 -0400
commit8f0ea0fe3a036a47767f9c80e81b13e379a1f43b (patch)
tree6f4079c8da32f3e1ac4860ac9f90b26e9df86e3b /include/net/snmp.h
parent830a9c75514b477994fd3847f72654d3dbdfa5ca (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.h86
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)