Reorganize source tree to use single autotools instance
[vpp.git] / src / vlib / counter.h
1 /*
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
43 /** \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 */
58
59 typedef struct
60 {
61   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. */
67
68   char *name;                   /**< The counter collection's name. */
69 } vlib_simple_counter_main_t;
70
71 /** 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 */
77 always_inline void
78 vlib_increment_simple_counter (vlib_simple_counter_main_t * cm,
79                                u32 cpu_index, u32 index, u32 increment)
80 {
81   u16 *my_minis;
82   u16 *mini;
83   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
98 /** 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 */
107 always_inline u64
108 vlib_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
118   for (i = 0; i < vec_len (cm->minis); i++)
119     {
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
136 /** 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 */
142 always_inline void
143 vlib_zero_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
144 {
145   u16 *my_minis;
146   int i;
147
148   ASSERT (index < vec_len (cm->maxi));
149
150   for (i = 0; i < vec_len (cm->minis); i++)
151     {
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
162 /** Combined counter to hold both packets and byte differences.
163  */
164 typedef struct
165 {
166   u64 packets;                  /**< packet counter */
167   u64 bytes;                    /**< byte counter  */
168 } vlib_counter_t;
169
170 /** Add two combined counters, results in the first counter
171     @param [in,out] a - (vlib_counter_t *) dst counter
172     @param b - (vlib_counter_t *) src counter
173 */
174
175 always_inline void
176 vlib_counter_add (vlib_counter_t * a, vlib_counter_t * b)
177 {
178   a->packets += b->packets;
179   a->bytes += b->bytes;
180 }
181
182 /** Subtract combined counters, results in the first counter
183     @param [in,out] a - (vlib_counter_t *) dst counter
184     @param b - (vlib_counter_t *) src counter
185 */
186 always_inline void
187 vlib_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
195 /** Clear a combined counter
196     @param a - (vlib_counter_t *) counter to clear
197 */
198 always_inline void
199 vlib_counter_zero (vlib_counter_t * a)
200 {
201   a->packets = a->bytes = 0;
202 }
203
204 /** Mini combined counter */
205 typedef struct
206 {
207   u16 packets;                  /**< Packet count */
208   i16 bytes;                    /**< Byte count */
209 } vlib_mini_counter_t;
210
211 /** A collection of combined counters */
212 typedef struct
213 {
214   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. */
220 } vlib_combined_counter_main_t;
221
222 /** Clear a collection of simple counters
223     @param cm - (vlib_simple_counter_main_t *) collection to clear
224 */
225 void vlib_clear_simple_counters (vlib_simple_counter_main_t * cm);
226
227 /** Clear a collection of combined counters
228     @param cm - (vlib_combined_counter_main_t *) collection to clear
229 */
230 void vlib_clear_combined_counters (vlib_combined_counter_main_t * cm);
231
232 /** 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
240 always_inline void
241 vlib_increment_combined_counter (vlib_combined_counter_main_t * cm,
242                                  u32 cpu_index,
243                                  u32 index,
244                                  u32 packet_increment, u32 byte_increment)
245 {
246   vlib_mini_counter_t *my_minis, *mini;
247   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     {
266       vlib_counter_t *maxi = vec_elt_at_index (cm->maxi, index);
267
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
276 /** 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
286 static inline void
287 vlib_get_combined_counter (vlib_combined_counter_main_t * cm,
288                            u32 index, vlib_counter_t * result)
289 {
290   vlib_mini_counter_t *my_minis, *mini;
291   vlib_counter_t *maxi;
292   int i;
293
294   result->packets = 0;
295   result->bytes = 0;
296
297   for (i = 0; i < vec_len (cm->minis); i++)
298     {
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
314 /** 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 */
320 always_inline void
321 vlib_zero_combined_counter (vlib_combined_counter_main_t * cm, u32 index)
322 {
323   vlib_mini_counter_t *mini, *my_minis;
324   int i;
325
326   for (i = 0; i < vec_len (cm->minis); i++)
327     {
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
340 /** 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
345 void vlib_validate_simple_counter (vlib_simple_counter_main_t * cm,
346                                    u32 index);
347 /** 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
353 void vlib_validate_combined_counter (vlib_combined_counter_main_t * cm,
354                                      u32 index);
355
356 /** 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 */
364 #define vlib_counter_len(cm) vec_len((cm)->maxi)
365
366 serialize_function_t serialize_vlib_simple_counter_main,
367   unserialize_vlib_simple_counter_main;
368 serialize_function_t serialize_vlib_combined_counter_main,
369   unserialize_vlib_combined_counter_main;
370
371 #endif /* included_vlib_counter_h */
372
373 /*
374  * fd.io coding-style-patch-verification: ON
375  *
376  * Local Variables:
377  * eval: (c-set-style "gnu")
378  * End:
379  */