Initial commit of vpp code.
[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 #define VLIB_COUNTER_MAX_CPUS   32
49
50 typedef struct {
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,
73                                u32 index,
74                                u32 increment)
75 {
76   u16 * my_minis;
77   u16 * mini;
78   u32 old, new;
79
80   my_minis = cm->minis[cpu_index];
81   mini = vec_elt_at_index (my_minis, index);
82   old = mini[0];
83   new = old + increment;
84   mini[0] = new;
85
86   if (PREDICT_FALSE (mini[0] != new))
87     {
88       __sync_fetch_and_add (&cm->maxi[index], new);
89       my_minis[index] = 0;
90     }
91 }
92
93 always_inline u64
94 vlib_get_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
95 {
96   u16 *my_minis, *mini;
97   u64 v;
98   int i;
99
100   ASSERT (index < vec_len (cm->maxi));
101
102   v = 0;
103
104   for (i = 0; i < VLIB_COUNTER_MAX_CPUS; i++)
105     {
106       my_minis = cm->minis[i];
107       mini = vec_elt_at_index (my_minis, index);
108       v += mini[0];
109     }
110
111   v += cm->maxi[index];
112
113   if (index < vec_len (cm->value_at_last_clear))
114     {
115       ASSERT (v >= cm->value_at_last_clear[index]);
116       v -= cm->value_at_last_clear[index];
117     }
118
119   return v;
120 }
121
122 always_inline void
123 vlib_zero_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
124 {
125   u16 * my_minis;
126   int i;
127
128   ASSERT (index < vec_len (cm->maxi));
129
130   for (i = 0; i < VLIB_COUNTER_MAX_CPUS; i++)
131     {
132       my_minis = cm->minis[i];
133       my_minis[index] = 0;
134     }
135
136   cm->maxi[index] = 0;
137
138   if (index < vec_len (cm->value_at_last_clear))
139     cm->value_at_last_clear[index] = 0;
140 }
141
142 /* Combined counters hold both packets and byte differences. */
143 /* Maxi-packet/byte counter. */
144 typedef struct {
145   u64 packets, bytes;
146 } vlib_counter_t;
147
148 always_inline void
149 vlib_counter_add (vlib_counter_t * a, vlib_counter_t * b)
150 {
151   a->packets += b->packets;
152   a->bytes += b->bytes;
153 }
154
155 always_inline void
156 vlib_counter_sub (vlib_counter_t * a, vlib_counter_t * b)
157 {
158   ASSERT (a->packets >= b->packets);
159   ASSERT (a->bytes >= b->bytes);
160   a->packets -= b->packets;
161   a->bytes -= b->bytes;
162 }
163
164 always_inline void
165 vlib_counter_zero (vlib_counter_t * a)
166 { a->packets = a->bytes = 0; }
167
168 /* Micro-counter: 16 bits of packets and 16 bits of byte difference. */
169 typedef struct {
170   /* Packet count. */
171   u16 packets;
172
173   /* The average packet size hack doesn't work in a multi-core config */
174   i16 bytes;
175 } vlib_mini_counter_t;
176
177 typedef struct {
178   /* Compact counters that (rarely) can overflow. */
179   vlib_mini_counter_t ** minis;
180
181   /* Counters to hold overflow. */
182   vlib_counter_t * maxi;
183
184   /* Debug counters for testing. */
185   vlib_counter_t * debug;
186
187   /* Counter values as of last clear. */
188   vlib_counter_t * value_at_last_clear;
189
190   /* Counter values as of last serialize. */
191   vlib_counter_t * value_at_last_serialize;
192
193   /* Last counter index serialized incrementally. */
194   u32 last_incremental_serialize_index;
195
196   /* Average packet sizes used in mini-counter byte differences. */
197   u32 ave_packet_size;
198
199   /* Current summed packets and bytes for average computation. */
200   u32 ave_packets, ave_bytes;
201
202   /* Counter name. */
203   char * name;
204
205 } vlib_combined_counter_main_t;
206
207 void vlib_clear_simple_counters (vlib_simple_counter_main_t * cm);
208 void vlib_clear_combined_counters (vlib_combined_counter_main_t * cm);
209
210 always_inline void
211 vlib_increment_combined_counter (vlib_combined_counter_main_t * cm,
212                                  u32 cpu_index,
213                                  u32 index,
214                                  u32 packet_increment,
215                                  u32 byte_increment)
216 {
217   vlib_mini_counter_t * my_minis, * mini;
218   u32 old_packets, new_packets;
219   i32 old_bytes, new_bytes;
220
221   /* Use this CPU's mini counter array */
222   my_minis = cm->minis[cpu_index];
223
224   mini = vec_elt_at_index (my_minis, index);
225   old_packets = mini->packets;
226   old_bytes = mini->bytes;
227
228   new_packets = old_packets + packet_increment;
229   new_bytes = old_bytes + byte_increment;
230
231   mini->packets = new_packets;
232   mini->bytes = new_bytes;
233
234   /* Bytes always overflow before packets.. */
235   if (PREDICT_FALSE (mini->bytes != new_bytes))
236     {
237       vlib_counter_t * maxi = vec_elt_at_index (cm->maxi, index);
238
239       __sync_fetch_and_add (&maxi->packets, new_packets);
240       __sync_fetch_and_add (&maxi->bytes, new_bytes);
241
242       mini->packets = 0;
243       mini->bytes = 0;
244     }
245 }
246
247 /* This is never done in the speed path */
248 static inline void
249 vlib_get_combined_counter (vlib_combined_counter_main_t * cm,
250                            u32 index,
251                            vlib_counter_t * result)
252 {
253   vlib_mini_counter_t * my_minis, * mini;
254   vlib_counter_t * maxi;
255   int i;
256
257   result->packets = 0;
258   result->bytes = 0;
259
260   for (i = 0; i < VLIB_COUNTER_MAX_CPUS; i++)
261     {
262       my_minis = cm->minis[i];
263
264       mini = vec_elt_at_index (my_minis, index);
265       result->packets += mini->packets;
266       result->bytes += mini->bytes;
267     }
268
269   maxi = vec_elt_at_index (cm->maxi, index);
270   result->packets += maxi->packets;
271   result->bytes += maxi->bytes;
272
273   if (index < vec_len (cm->value_at_last_clear))
274     vlib_counter_sub (result, &cm->value_at_last_clear[index]);
275 }
276
277 always_inline void
278 vlib_zero_combined_counter (vlib_combined_counter_main_t * cm,
279                             u32 index)
280 {
281   vlib_mini_counter_t * mini, * my_minis;
282   int i;
283
284   for (i = 0; i < VLIB_COUNTER_MAX_CPUS; 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 /* Initialize/allocate given counter index.
299    Works for both simple and combined counters. */
300 #define vlib_validate_counter_DEPRECATED(cm,index)              \
301   do {                                                          \
302     int i;                                                      \
303                                                                 \
304     vec_validate ((cm)->minis, VLIB_COUNTER_MAX_CPUS-1);        \
305     for (i = 0; i < VLIB_COUNTER_MAX_CPUS; i++)                 \
306       vec_validate ((cm)->minis[i], (index));                   \
307     vec_validate ((cm)->maxi, (index));                         \
308   } while (0)
309
310 static inline void
311 vlib_validate_simple_counter (vlib_simple_counter_main_t *cm, u32 index)
312 {
313   int i;
314   vec_validate (cm->minis, VLIB_COUNTER_MAX_CPUS-1);
315   for (i = 0; i < VLIB_COUNTER_MAX_CPUS; i++)
316     vec_validate_aligned (cm->minis[i], index, CLIB_CACHE_LINE_BYTES);
317   vec_validate_aligned (cm->maxi, index, CLIB_CACHE_LINE_BYTES);
318 }
319
320 static inline void
321 vlib_validate_combined_counter (vlib_combined_counter_main_t *cm, u32 index)
322 {
323   int i;
324   vec_validate (cm->minis, VLIB_COUNTER_MAX_CPUS-1);
325   for (i = 0; i < VLIB_COUNTER_MAX_CPUS; i++)
326     vec_validate_aligned (cm->minis[i], index, CLIB_CACHE_LINE_BYTES);
327   vec_validate_aligned (cm->maxi, index, CLIB_CACHE_LINE_BYTES);
328 }
329
330 /* Number of simple/combined counters allocated. */
331 #define vlib_counter_len(cm) vec_len((cm)->maxi)
332
333 serialize_function_t serialize_vlib_simple_counter_main, unserialize_vlib_simple_counter_main;
334 serialize_function_t serialize_vlib_combined_counter_main, unserialize_vlib_combined_counter_main;
335
336 #endif /* included_vlib_counter_h */