blob: a79032065d97b83bcdcff384dc90cfe8b19668ba [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
Dave Barach63539202016-08-11 17:21:02 -0400276/** Get the value of a combined counter, never called in the speed path
277 Scrapes the entire set of mini counters. Innacurate unless
278 worker threads which might increment the counter are
279 barrier-synchronized
280
281 @param cm - (vlib_combined_counter_main_t *) combined counter main pointer
282 @param index - (u32) index of the combined counter to fetch
283 @param result [out] - (vlib_counter_t *) result stored here
284*/
285
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286static inline void
287vlib_get_combined_counter (vlib_combined_counter_main_t * cm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400288 u32 index, vlib_counter_t * result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400290 vlib_mini_counter_t *my_minis, *mini;
291 vlib_counter_t *maxi;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 int i;
293
294 result->packets = 0;
295 result->bytes = 0;
296
Dave Barach9b8ffd92016-07-08 08:13:45 -0400297 for (i = 0; i < vec_len (cm->minis); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298 {
299 my_minis = cm->minis[i];
300
301 mini = vec_elt_at_index (my_minis, index);
302 result->packets += mini->packets;
303 result->bytes += mini->bytes;
304 }
305
306 maxi = vec_elt_at_index (cm->maxi, index);
307 result->packets += maxi->packets;
308 result->bytes += maxi->bytes;
309
310 if (index < vec_len (cm->value_at_last_clear))
311 vlib_counter_sub (result, &cm->value_at_last_clear[index]);
312}
313
Dave Barach63539202016-08-11 17:21:02 -0400314/** Clear a combined counter
315 Clears the set of per-thread u16 counters, and the shared vlib_counter_t
316
317 @param cm - (vlib_combined_counter_main_t *) combined counter main pointer
318 @param index - (u32) index of the counter to clear
319*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400321vlib_zero_combined_counter (vlib_combined_counter_main_t * cm, u32 index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700322{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400323 vlib_mini_counter_t *mini, *my_minis;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324 int i;
325
Dave Barach9b8ffd92016-07-08 08:13:45 -0400326 for (i = 0; i < vec_len (cm->minis); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327 {
328 my_minis = cm->minis[i];
329
330 mini = vec_elt_at_index (my_minis, index);
331 mini->packets = 0;
332 mini->bytes = 0;
333 }
334
335 vlib_counter_zero (&cm->maxi[index]);
336 if (index < vec_len (cm->value_at_last_clear))
337 vlib_counter_zero (&cm->value_at_last_clear[index]);
338}
339
Dave Barach63539202016-08-11 17:21:02 -0400340/** validate a simple counter
341 @param cm - (vlib_simple_counter_main_t *) pointer to the counter collection
342 @param index - (u32) index of the counter to validate
343*/
344
Dave Barach9b8ffd92016-07-08 08:13:45 -0400345void vlib_validate_simple_counter (vlib_simple_counter_main_t * cm,
346 u32 index);
Dave Barach63539202016-08-11 17:21:02 -0400347/** validate a combined counter
348 @param cm - (vlib_combined_counter_main_t *) pointer to the counter
349 collection
350 @param index - (u32) index of the counter to validate
351*/
352
Dave Barach9b8ffd92016-07-08 08:13:45 -0400353void vlib_validate_combined_counter (vlib_combined_counter_main_t * cm,
354 u32 index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700355
Dave Barach63539202016-08-11 17:21:02 -0400356/** Obtain the number of simple or combined counters allocated.
357 A macro which reduces to to vec_len(cm->maxi), the answer in either
358 case.
359
360 @param cm - (vlib_simple_counter_main_t) or
361 (vlib_combined_counter_main_t) the counter collection to interrogate
362 @returns vec_len(cm->maxi)
363*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364#define vlib_counter_len(cm) vec_len((cm)->maxi)
365
Dave Barach9b8ffd92016-07-08 08:13:45 -0400366serialize_function_t serialize_vlib_simple_counter_main,
367 unserialize_vlib_simple_counter_main;
368serialize_function_t serialize_vlib_combined_counter_main,
369 unserialize_vlib_combined_counter_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370
371#endif /* included_vlib_counter_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400372
373/*
374 * fd.io coding-style-patch-verification: ON
375 *
376 * Local Variables:
377 * eval: (c-set-style "gnu")
378 * End:
379 */