fd-io-styleify pass
[vpp.git] / vlib / 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 /*
44  * Annoyingly enough, counters are created long before
45  * the CPU configuration is available, so we have to
46  * preallocate the mini-counter per-cpu vectors
47  */
48
49 typedef struct
50 {
51   /* Compact counters that (rarely) can overflow. */
52   u16 **minis;
53
54   /* Counters to hold overflow. */
55   u64 *maxi;
56
57   /* Counter values as of last clear. */
58   u64 *value_at_last_clear;
59
60   /* Values as of last serialize. */
61   u64 *value_at_last_serialize;
62
63   /* Last counter index serialized incrementally. */
64   u32 last_incremental_serialize_index;
65
66   /* Counter name. */
67   char *name;
68 } vlib_simple_counter_main_t;
69
70 always_inline void
71 vlib_increment_simple_counter (vlib_simple_counter_main_t * cm,
72                                u32 cpu_index, u32 index, u32 increment)
73 {
74   u16 *my_minis;
75   u16 *mini;
76   u32 old, new;
77
78   my_minis = cm->minis[cpu_index];
79   mini = vec_elt_at_index (my_minis, index);
80   old = mini[0];
81   new = old + increment;
82   mini[0] = new;
83
84   if (PREDICT_FALSE (mini[0] != new))
85     {
86       __sync_fetch_and_add (&cm->maxi[index], new);
87       my_minis[index] = 0;
88     }
89 }
90
91 always_inline u64
92 vlib_get_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
93 {
94   u16 *my_minis, *mini;
95   u64 v;
96   int i;
97
98   ASSERT (index < vec_len (cm->maxi));
99
100   v = 0;
101
102   for (i = 0; i < vec_len (cm->minis); i++)
103     {
104       my_minis = cm->minis[i];
105       mini = vec_elt_at_index (my_minis, index);
106       v += mini[0];
107     }
108
109   v += cm->maxi[index];
110
111   if (index < vec_len (cm->value_at_last_clear))
112     {
113       ASSERT (v >= cm->value_at_last_clear[index]);
114       v -= cm->value_at_last_clear[index];
115     }
116
117   return v;
118 }
119
120 always_inline void
121 vlib_zero_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
122 {
123   u16 *my_minis;
124   int i;
125
126   ASSERT (index < vec_len (cm->maxi));
127
128   for (i = 0; i < vec_len (cm->minis); i++)
129     {
130       my_minis = cm->minis[i];
131       my_minis[index] = 0;
132     }
133
134   cm->maxi[index] = 0;
135
136   if (index < vec_len (cm->value_at_last_clear))
137     cm->value_at_last_clear[index] = 0;
138 }
139
140 /* Combined counters hold both packets and byte differences. */
141 /* Maxi-packet/byte counter. */
142 typedef struct
143 {
144   u64 packets, bytes;
145 } vlib_counter_t;
146
147 always_inline void
148 vlib_counter_add (vlib_counter_t * a, vlib_counter_t * b)
149 {
150   a->packets += b->packets;
151   a->bytes += b->bytes;
152 }
153
154 always_inline void
155 vlib_counter_sub (vlib_counter_t * a, vlib_counter_t * b)
156 {
157   ASSERT (a->packets >= b->packets);
158   ASSERT (a->bytes >= b->bytes);
159   a->packets -= b->packets;
160   a->bytes -= b->bytes;
161 }
162
163 always_inline void
164 vlib_counter_zero (vlib_counter_t * a)
165 {
166   a->packets = a->bytes = 0;
167 }
168
169 /* Micro-counter: 16 bits of packets and 16 bits of byte difference. */
170 typedef struct
171 {
172   /* Packet count. */
173   u16 packets;
174
175   /* The average packet size hack doesn't work in a multi-core config */
176   i16 bytes;
177 } vlib_mini_counter_t;
178
179 typedef struct
180 {
181   /* Compact counters that (rarely) can overflow. */
182   vlib_mini_counter_t **minis;
183
184   /* Counters to hold overflow. */
185   vlib_counter_t *maxi;
186
187   /* Debug counters for testing. */
188   vlib_counter_t *debug;
189
190   /* Counter values as of last clear. */
191   vlib_counter_t *value_at_last_clear;
192
193   /* Counter values as of last serialize. */
194   vlib_counter_t *value_at_last_serialize;
195
196   /* Last counter index serialized incrementally. */
197   u32 last_incremental_serialize_index;
198
199   /* Average packet sizes used in mini-counter byte differences. */
200   u32 ave_packet_size;
201
202   /* Current summed packets and bytes for average computation. */
203   u32 ave_packets, ave_bytes;
204
205   /* Counter name. */
206   char *name;
207
208 } vlib_combined_counter_main_t;
209
210 void vlib_clear_simple_counters (vlib_simple_counter_main_t * cm);
211 void vlib_clear_combined_counters (vlib_combined_counter_main_t * cm);
212
213 always_inline void
214 vlib_increment_combined_counter (vlib_combined_counter_main_t * cm,
215                                  u32 cpu_index,
216                                  u32 index,
217                                  u32 packet_increment, u32 byte_increment)
218 {
219   vlib_mini_counter_t *my_minis, *mini;
220   u32 old_packets, new_packets;
221   i32 old_bytes, new_bytes;
222
223   /* Use this CPU's mini counter array */
224   my_minis = cm->minis[cpu_index];
225
226   mini = vec_elt_at_index (my_minis, index);
227   old_packets = mini->packets;
228   old_bytes = mini->bytes;
229
230   new_packets = old_packets + packet_increment;
231   new_bytes = old_bytes + byte_increment;
232
233   mini->packets = new_packets;
234   mini->bytes = new_bytes;
235
236   /* Bytes always overflow before packets.. */
237   if (PREDICT_FALSE (mini->bytes != new_bytes))
238     {
239       vlib_counter_t *maxi = vec_elt_at_index (cm->maxi, index);
240
241       __sync_fetch_and_add (&maxi->packets, new_packets);
242       __sync_fetch_and_add (&maxi->bytes, new_bytes);
243
244       mini->packets = 0;
245       mini->bytes = 0;
246     }
247 }
248
249 /* This is never done in the speed path */
250 static inline void
251 vlib_get_combined_counter (vlib_combined_counter_main_t * cm,
252                            u32 index, vlib_counter_t * result)
253 {
254   vlib_mini_counter_t *my_minis, *mini;
255   vlib_counter_t *maxi;
256   int i;
257
258   result->packets = 0;
259   result->bytes = 0;
260
261   for (i = 0; i < vec_len (cm->minis); i++)
262     {
263       my_minis = cm->minis[i];
264
265       mini = vec_elt_at_index (my_minis, index);
266       result->packets += mini->packets;
267       result->bytes += mini->bytes;
268     }
269
270   maxi = vec_elt_at_index (cm->maxi, index);
271   result->packets += maxi->packets;
272   result->bytes += maxi->bytes;
273
274   if (index < vec_len (cm->value_at_last_clear))
275     vlib_counter_sub (result, &cm->value_at_last_clear[index]);
276 }
277
278 always_inline void
279 vlib_zero_combined_counter (vlib_combined_counter_main_t * cm, u32 index)
280 {
281   vlib_mini_counter_t *mini, *my_minis;
282   int i;
283
284   for (i = 0; i < vec_len (cm->minis); i++)
285     {
286       my_minis = cm->minis[i];
287
288       mini = vec_elt_at_index (my_minis, index);
289       mini->packets = 0;
290       mini->bytes = 0;
291     }
292
293   vlib_counter_zero (&cm->maxi[index]);
294   if (index < vec_len (cm->value_at_last_clear))
295     vlib_counter_zero (&cm->value_at_last_clear[index]);
296 }
297
298 void vlib_validate_simple_counter (vlib_simple_counter_main_t * cm,
299                                    u32 index);
300 void vlib_validate_combined_counter (vlib_combined_counter_main_t * cm,
301                                      u32 index);
302
303 /* Number of simple/combined counters allocated. */
304 #define vlib_counter_len(cm) vec_len((cm)->maxi)
305
306 serialize_function_t serialize_vlib_simple_counter_main,
307   unserialize_vlib_simple_counter_main;
308 serialize_function_t serialize_vlib_combined_counter_main,
309   unserialize_vlib_combined_counter_main;
310
311 #endif /* included_vlib_counter_h */
312
313 /*
314  * fd.io coding-style-patch-verification: ON
315  *
316  * Local Variables:
317  * eval: (c-set-style "gnu")
318  * End:
319  */