blob: abfa89eea6d271d879649fe9c3b6f2628236629a [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * counter.h: simple and packet/byte counters
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#ifndef included_vlib_counter_h
41#define included_vlib_counter_h
42
Dave Barach63539202016-08-11 17:21:02 -040043/** \file
44
45 Optimized thread-safe counters.
46
47 Each vlib_[simple|combined]_counter_main_t consists of a single
48 vector of thread-safe / atomically-updated u64 counters [the
49 "maxi" vector], and a (u16 **) per-thread vector [the "minis"
50 vector] of narrow, per-thread counters.
51
52 The idea is to drastically reduce the number of atomic operations.
53 In the case of packet counts, we divide the number of atomic ops
54 by 2**16, etc.
55*/
56
57/** A collection of simple counters */
Ed Warnickecb9cada2015-12-08 15:45:58 -070058
Dave Barach9b8ffd92016-07-08 08:13:45 -040059typedef struct
60{
Dave Barach63539202016-08-11 17:21:02 -040061 u16 **minis; /**< Per-thread u16 non-atomic counters */
62 u64 *maxi; /**< Shared wide counters */
63 u64 *value_at_last_clear; /**< Counter values as of last clear. */
64 u64 *value_at_last_serialize; /**< Values as of last serialize. */
65 u32 last_incremental_serialize_index; /**< Last counter index
66 serialized incrementally. */
Ed Warnickecb9cada2015-12-08 15:45:58 -070067
Dave Barach63539202016-08-11 17:21:02 -040068 char *name; /**< The counter collection's name. */
Ed Warnickecb9cada2015-12-08 15:45:58 -070069} vlib_simple_counter_main_t;
70
Dave Barach63539202016-08-11 17:21:02 -040071/** Increment a simple counter
72 @param cm - (vlib_simple_counter_main_t *) simple counter main pointer
73 @param cpu_index - (u32) the current cpu index
74 @param index - (u32) index of the counter to increment
75 @param increment - (u32) quantitiy to add to the counter
76*/
Ed Warnickecb9cada2015-12-08 15:45:58 -070077always_inline void
78vlib_increment_simple_counter (vlib_simple_counter_main_t * cm,
Dave Barach9b8ffd92016-07-08 08:13:45 -040079 u32 cpu_index, u32 index, u32 increment)
Ed Warnickecb9cada2015-12-08 15:45:58 -070080{
Dave Barach9b8ffd92016-07-08 08:13:45 -040081 u16 *my_minis;
82 u16 *mini;
Ed Warnickecb9cada2015-12-08 15:45:58 -070083 u32 old, new;
84
85 my_minis = cm->minis[cpu_index];
86 mini = vec_elt_at_index (my_minis, index);
87 old = mini[0];
88 new = old + increment;
89 mini[0] = new;
90
91 if (PREDICT_FALSE (mini[0] != new))
92 {
93 __sync_fetch_and_add (&cm->maxi[index], new);
94 my_minis[index] = 0;
95 }
96}
97
Dave Barach63539202016-08-11 17:21:02 -040098/** Get the value of a simple counter
99 Scrapes the entire set of mini counters. Innacurate unless
100 worker threads which might increment the counter are
101 barrier-synchronized
102
103 @param cm - (vlib_simple_counter_main_t *) simple counter main pointer
104 @param index - (u32) index of the counter to fetch
105 @returns - (u64) current counter value
106*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107always_inline u64
108vlib_get_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
109{
110 u16 *my_minis, *mini;
111 u64 v;
112 int i;
113
114 ASSERT (index < vec_len (cm->maxi));
115
116 v = 0;
117
Dave Barach9b8ffd92016-07-08 08:13:45 -0400118 for (i = 0; i < vec_len (cm->minis); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119 {
120 my_minis = cm->minis[i];
121 mini = vec_elt_at_index (my_minis, index);
122 v += mini[0];
123 }
124
125 v += cm->maxi[index];
126
127 if (index < vec_len (cm->value_at_last_clear))
128 {
129 ASSERT (v >= cm->value_at_last_clear[index]);
130 v -= cm->value_at_last_clear[index];
131 }
132
133 return v;
134}
135
Dave Barach63539202016-08-11 17:21:02 -0400136/** Clear a simple counter
137 Clears the set of per-thread u16 counters, and the u64 counter
138
139 @param cm - (vlib_simple_counter_main_t *) simple counter main pointer
140 @param index - (u32) index of the counter to clear
141*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142always_inline void
143vlib_zero_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
144{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400145 u16 *my_minis;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146 int i;
147
148 ASSERT (index < vec_len (cm->maxi));
149
Dave Barach9b8ffd92016-07-08 08:13:45 -0400150 for (i = 0; i < vec_len (cm->minis); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151 {
152 my_minis = cm->minis[i];
153 my_minis[index] = 0;
154 }
155
156 cm->maxi[index] = 0;
157
158 if (index < vec_len (cm->value_at_last_clear))
159 cm->value_at_last_clear[index] = 0;
160}
161
Dave Barach63539202016-08-11 17:21:02 -0400162/** Combined counter to hold both packets and byte differences.
163 */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400164typedef struct
165{
Dave Barach63539202016-08-11 17:21:02 -0400166 u64 packets; /**< packet counter */
167 u64 bytes; /**< byte counter */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168} vlib_counter_t;
169
Dave Barach63539202016-08-11 17:21:02 -0400170/** Add two combined counters, results in the first counter
Chris Luked4024f52016-09-06 09:32:36 -0400171 @param [in,out] a - (vlib_counter_t *) dst counter
Dave Barach63539202016-08-11 17:21:02 -0400172 @param b - (vlib_counter_t *) src counter
173*/
174
Ed Warnickecb9cada2015-12-08 15:45:58 -0700175always_inline void
176vlib_counter_add (vlib_counter_t * a, vlib_counter_t * b)
177{
178 a->packets += b->packets;
179 a->bytes += b->bytes;
180}
181
Dave Barach63539202016-08-11 17:21:02 -0400182/** Subtract combined counters, results in the first counter
Chris Luked4024f52016-09-06 09:32:36 -0400183 @param [in,out] a - (vlib_counter_t *) dst counter
Dave Barach63539202016-08-11 17:21:02 -0400184 @param b - (vlib_counter_t *) src counter
185*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186always_inline void
187vlib_counter_sub (vlib_counter_t * a, vlib_counter_t * b)
188{
189 ASSERT (a->packets >= b->packets);
190 ASSERT (a->bytes >= b->bytes);
191 a->packets -= b->packets;
192 a->bytes -= b->bytes;
193}
194
Dave Barach63539202016-08-11 17:21:02 -0400195/** Clear a combined counter
196 @param a - (vlib_counter_t *) counter to clear
197*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198always_inline void
199vlib_counter_zero (vlib_counter_t * a)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400200{
201 a->packets = a->bytes = 0;
202}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203
Dave Barach63539202016-08-11 17:21:02 -0400204/** Mini combined counter */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400205typedef struct
206{
Dave Barach63539202016-08-11 17:21:02 -0400207 u16 packets; /**< Packet count */
208 i16 bytes; /**< Byte count */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209} vlib_mini_counter_t;
210
Dave Barach63539202016-08-11 17:21:02 -0400211/** A collection of combined counters */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400212typedef struct
213{
Dave Barach63539202016-08-11 17:21:02 -0400214 vlib_mini_counter_t **minis; /**< Per-thread u16 non-atomic counter pairs */
215 vlib_counter_t *maxi; /**< Shared wide counter pairs */
216 vlib_counter_t *value_at_last_clear; /**< Counter values as of last clear. */
217 vlib_counter_t *value_at_last_serialize; /**< Counter values as of last serialize. */
218 u32 last_incremental_serialize_index; /**< Last counter index serialized incrementally. */
219 char *name; /**< The counter collection's name. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220} vlib_combined_counter_main_t;
221
Dave Barach63539202016-08-11 17:21:02 -0400222/** Clear a collection of simple counters
223 @param cm - (vlib_simple_counter_main_t *) collection to clear
224*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225void vlib_clear_simple_counters (vlib_simple_counter_main_t * cm);
Dave Barach63539202016-08-11 17:21:02 -0400226
227/** Clear a collection of combined counters
228 @param cm - (vlib_combined_counter_main_t *) collection to clear
229*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230void vlib_clear_combined_counters (vlib_combined_counter_main_t * cm);
231
Dave Barach63539202016-08-11 17:21:02 -0400232/** Increment a combined counter
233 @param cm - (vlib_combined_counter_main_t *) comined counter main pointer
234 @param cpu_index - (u32) the current cpu index
235 @param index - (u32) index of the counter to increment
236 @param packet_increment - (u32) number of packets to add to the counter
237 @param byte_increment - (u32) number of bytes to add to the counter
238*/
239
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240always_inline void
241vlib_increment_combined_counter (vlib_combined_counter_main_t * cm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400242 u32 cpu_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 u32 index,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400244 u32 packet_increment, u32 byte_increment)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400246 vlib_mini_counter_t *my_minis, *mini;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 u32 old_packets, new_packets;
248 i32 old_bytes, new_bytes;
249
250 /* Use this CPU's mini counter array */
251 my_minis = cm->minis[cpu_index];
252
253 mini = vec_elt_at_index (my_minis, index);
254 old_packets = mini->packets;
255 old_bytes = mini->bytes;
256
257 new_packets = old_packets + packet_increment;
258 new_bytes = old_bytes + byte_increment;
259
260 mini->packets = new_packets;
261 mini->bytes = new_bytes;
262
263 /* Bytes always overflow before packets.. */
264 if (PREDICT_FALSE (mini->bytes != new_bytes))
265 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400266 vlib_counter_t *maxi = vec_elt_at_index (cm->maxi, index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
268 __sync_fetch_and_add (&maxi->packets, new_packets);
269 __sync_fetch_and_add (&maxi->bytes, new_bytes);
270
271 mini->packets = 0;
272 mini->bytes = 0;
273 }
274}
275
Neale Ranns044183f2017-01-24 01:34:25 -0800276#define vlib_prefetch_combined_counter(_cm, _cpu_index, _index) \
277{ \
278 vlib_mini_counter_t *_cpu_minis; \
279 \
280 /* \
281 * This CPU's mini index is assumed to already be in cache \
282 */ \
283 _cpu_minis = (_cm)->minis[(_cpu_index)]; \
284 CLIB_PREFETCH(_cpu_minis + (_index), \
285 sizeof(*_cpu_minis), \
286 STORE); \
287}
288
289
Dave Barach63539202016-08-11 17:21:02 -0400290/** Get the value of a combined counter, never called in the speed path
291 Scrapes the entire set of mini counters. Innacurate unless
292 worker threads which might increment the counter are
293 barrier-synchronized
294
295 @param cm - (vlib_combined_counter_main_t *) combined counter main pointer
296 @param index - (u32) index of the combined counter to fetch
297 @param result [out] - (vlib_counter_t *) result stored here
298*/
299
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300static inline void
301vlib_get_combined_counter (vlib_combined_counter_main_t * cm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400302 u32 index, vlib_counter_t * result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400304 vlib_mini_counter_t *my_minis, *mini;
305 vlib_counter_t *maxi;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306 int i;
307
308 result->packets = 0;
309 result->bytes = 0;
310
Dave Barach9b8ffd92016-07-08 08:13:45 -0400311 for (i = 0; i < vec_len (cm->minis); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700312 {
313 my_minis = cm->minis[i];
314
315 mini = vec_elt_at_index (my_minis, index);
316 result->packets += mini->packets;
317 result->bytes += mini->bytes;
318 }
319
320 maxi = vec_elt_at_index (cm->maxi, index);
321 result->packets += maxi->packets;
322 result->bytes += maxi->bytes;
323
324 if (index < vec_len (cm->value_at_last_clear))
325 vlib_counter_sub (result, &cm->value_at_last_clear[index]);
326}
327
Dave Barach63539202016-08-11 17:21:02 -0400328/** Clear a combined counter
329 Clears the set of per-thread u16 counters, and the shared vlib_counter_t
330
331 @param cm - (vlib_combined_counter_main_t *) combined counter main pointer
332 @param index - (u32) index of the counter to clear
333*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400335vlib_zero_combined_counter (vlib_combined_counter_main_t * cm, u32 index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700336{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400337 vlib_mini_counter_t *mini, *my_minis;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338 int i;
339
Dave Barach9b8ffd92016-07-08 08:13:45 -0400340 for (i = 0; i < vec_len (cm->minis); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700341 {
342 my_minis = cm->minis[i];
343
344 mini = vec_elt_at_index (my_minis, index);
345 mini->packets = 0;
346 mini->bytes = 0;
347 }
348
349 vlib_counter_zero (&cm->maxi[index]);
350 if (index < vec_len (cm->value_at_last_clear))
351 vlib_counter_zero (&cm->value_at_last_clear[index]);
352}
353
Dave Barach63539202016-08-11 17:21:02 -0400354/** validate a simple counter
355 @param cm - (vlib_simple_counter_main_t *) pointer to the counter collection
356 @param index - (u32) index of the counter to validate
357*/
358
Dave Barach9b8ffd92016-07-08 08:13:45 -0400359void vlib_validate_simple_counter (vlib_simple_counter_main_t * cm,
360 u32 index);
Dave Barach63539202016-08-11 17:21:02 -0400361/** validate a combined counter
362 @param cm - (vlib_combined_counter_main_t *) pointer to the counter
363 collection
364 @param index - (u32) index of the counter to validate
365*/
366
Dave Barach9b8ffd92016-07-08 08:13:45 -0400367void vlib_validate_combined_counter (vlib_combined_counter_main_t * cm,
368 u32 index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700369
Dave Barach63539202016-08-11 17:21:02 -0400370/** Obtain the number of simple or combined counters allocated.
371 A macro which reduces to to vec_len(cm->maxi), the answer in either
372 case.
373
374 @param cm - (vlib_simple_counter_main_t) or
375 (vlib_combined_counter_main_t) the counter collection to interrogate
376 @returns vec_len(cm->maxi)
377*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378#define vlib_counter_len(cm) vec_len((cm)->maxi)
379
Dave Barach9b8ffd92016-07-08 08:13:45 -0400380serialize_function_t serialize_vlib_simple_counter_main,
381 unserialize_vlib_simple_counter_main;
382serialize_function_t serialize_vlib_combined_counter_main,
383 unserialize_vlib_combined_counter_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384
385#endif /* included_vlib_counter_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400386
387/*
388 * fd.io coding-style-patch-verification: ON
389 *
390 * Local Variables:
391 * eval: (c-set-style "gnu")
392 * End:
393 */