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