Line data Source code
1 : /* SPDX-License-Identifier: Apache-2.0
2 : * Copyright(c) 2022 Cisco Systems, Inc.
3 : */
4 :
5 : #include <vlib/vlib.h>
6 : #include <vlib/stats/stats.h>
7 :
8 : vlib_stats_main_t vlib_stats_main;
9 :
10 : void
11 691943 : vlib_stats_segment_lock (void)
12 : {
13 691943 : vlib_main_t *vm = vlib_get_main ();
14 691943 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
15 :
16 : /* already locked by us */
17 691943 : if (sm->shared_header->in_progress &&
18 94734 : vm->thread_index == sm->locking_thread_index)
19 94734 : goto done;
20 :
21 597209 : ASSERT (sm->locking_thread_index == ~0);
22 597209 : ASSERT (sm->shared_header->in_progress == 0);
23 597209 : ASSERT (sm->n_locks == 0);
24 :
25 597209 : clib_spinlock_lock (sm->stat_segment_lockp);
26 :
27 597209 : sm->shared_header->in_progress = 1;
28 597209 : sm->locking_thread_index = vm->thread_index;
29 691943 : done:
30 691943 : sm->n_locks++;
31 691943 : }
32 :
33 : void
34 691943 : vlib_stats_segment_unlock (void)
35 : {
36 691943 : vlib_main_t *vm = vlib_get_main ();
37 691943 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
38 :
39 691943 : ASSERT (sm->shared_header->in_progress == 1);
40 691943 : ASSERT (sm->locking_thread_index == vm->thread_index);
41 691943 : ASSERT (sm->n_locks > 0);
42 :
43 691943 : sm->n_locks--;
44 :
45 691943 : if (sm->n_locks > 0)
46 94734 : return;
47 :
48 597209 : sm->shared_header->epoch++;
49 597209 : __atomic_store_n (&sm->shared_header->in_progress, 0, __ATOMIC_RELEASE);
50 597209 : sm->locking_thread_index = ~0;
51 597209 : clib_spinlock_unlock (sm->stat_segment_lockp);
52 : }
53 :
54 : /*
55 : * Change heap to the stats shared memory segment
56 : */
57 : void *
58 100814 : vlib_stats_set_heap ()
59 : {
60 100814 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
61 :
62 100814 : ASSERT (sm && sm->shared_header);
63 100814 : return clib_mem_set_heap (sm->heap);
64 : }
65 :
66 : u32
67 2494820 : vlib_stats_find_entry_index (char *fmt, ...)
68 : {
69 : u8 *name;
70 : va_list va;
71 :
72 2494820 : va_start (va, fmt);
73 2494820 : name = va_format (0, fmt, &va);
74 2494820 : va_end (va);
75 2494820 : vec_add1 (name, 0);
76 :
77 2494820 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
78 2494820 : hash_pair_t *hp = hash_get_pair (sm->directory_vector_by_name, name);
79 2494820 : vec_free (name);
80 2494820 : return hp ? hp->value[0] : STAT_SEGMENT_INDEX_INVALID;
81 : }
82 :
83 : static void
84 2485050 : hash_set_str_key_alloc (uword **h, const char *key, uword v)
85 : {
86 2485050 : int size = strlen (key) + 1;
87 2485050 : void *copy = clib_mem_alloc (size);
88 2485050 : clib_memcpy_fast (copy, key, size);
89 4970100 : hash_set_mem (*h, copy, v);
90 2485050 : }
91 :
92 : static void
93 76359 : hash_unset_str_key_free (uword **h, const char *key)
94 : {
95 76359 : hash_pair_t *hp = hash_get_pair_mem (*h, key);
96 76359 : if (hp)
97 : {
98 76359 : void *_k = uword_to_pointer (hp->key, void *);
99 76359 : hash_unset_mem (*h, _k);
100 76359 : clib_mem_free (_k);
101 : }
102 76359 : }
103 :
104 : u32
105 2485050 : vlib_stats_create_counter (vlib_stats_entry_t *e)
106 : {
107 2485050 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
108 : u32 index;
109 :
110 2485050 : if (sm->dir_vector_first_free_elt != CLIB_U32_MAX)
111 : {
112 64847 : index = sm->dir_vector_first_free_elt;
113 64847 : sm->dir_vector_first_free_elt = sm->directory_vector[index].index;
114 : }
115 : else
116 : {
117 2420200 : index = vec_len (sm->directory_vector);
118 2420200 : vec_validate (sm->directory_vector, index);
119 : }
120 :
121 2485050 : sm->directory_vector[index] = *e;
122 :
123 2485050 : hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, index);
124 :
125 2485050 : return index;
126 : }
127 :
128 : void
129 76359 : vlib_stats_remove_entry (u32 entry_index)
130 : {
131 76359 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
132 76359 : vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
133 : counter_t **c;
134 : vlib_counter_t **vc;
135 : void *oldheap;
136 : u32 i;
137 :
138 76359 : if (entry_index >= vec_len (sm->directory_vector))
139 0 : return;
140 :
141 76359 : vlib_stats_segment_lock ();
142 :
143 76359 : switch (e->type)
144 : {
145 0 : case STAT_DIR_TYPE_NAME_VECTOR:
146 0 : for (i = 0; i < vec_len (e->string_vector); i++)
147 0 : vec_free (e->string_vector[i]);
148 0 : vec_free (e->string_vector);
149 0 : break;
150 :
151 1 : case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
152 1 : c = e->data;
153 1 : e->data = 0;
154 1 : oldheap = clib_mem_set_heap (sm->heap);
155 2 : for (i = 0; i < vec_len (c); i++)
156 1 : vec_free (c[i]);
157 1 : vec_free (c);
158 1 : clib_mem_set_heap (oldheap);
159 1 : break;
160 :
161 1 : case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
162 1 : vc = e->data;
163 1 : e->data = 0;
164 1 : oldheap = clib_mem_set_heap (sm->heap);
165 2 : for (i = 0; i < vec_len (vc); i++)
166 1 : vec_free (vc[i]);
167 1 : vec_free (vc);
168 1 : clib_mem_set_heap (oldheap);
169 1 : break;
170 :
171 76357 : case STAT_DIR_TYPE_SCALAR_INDEX:
172 : case STAT_DIR_TYPE_SYMLINK:
173 76357 : break;
174 0 : default:
175 0 : ASSERT (0);
176 : }
177 :
178 76359 : vlib_stats_segment_unlock ();
179 :
180 76359 : hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
181 :
182 76359 : memset (e, 0, sizeof (*e));
183 76359 : e->type = STAT_DIR_TYPE_EMPTY;
184 :
185 76359 : e->value = sm->dir_vector_first_free_elt;
186 76359 : sm->dir_vector_first_free_elt = entry_index;
187 : }
188 :
189 : static void
190 2485050 : vlib_stats_set_entry_name (vlib_stats_entry_t *e, char *s)
191 : {
192 2485050 : u32 i, len = VLIB_STATS_MAX_NAME_SZ - 1;
193 :
194 97628500 : for (i = 0; i < len; i++)
195 : {
196 97628500 : e->name[i] = s[i];
197 97628500 : if (s[i] == 0)
198 2485050 : return;
199 : }
200 0 : ASSERT (i < VLIB_STATS_MAX_NAME_SZ - 1);
201 0 : s[i] = 0;
202 : }
203 :
204 : static u32
205 71212 : vlib_stats_new_entry_internal (stat_directory_type_t t, u8 *name)
206 : {
207 71212 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
208 71212 : vlib_stats_shared_header_t *shared_header = sm->shared_header;
209 71212 : vlib_stats_entry_t e = { .type = t };
210 :
211 71212 : ASSERT (shared_header);
212 :
213 71212 : u32 vector_index = vlib_stats_find_entry_index ("%v", name);
214 71212 : if (vector_index != STAT_SEGMENT_INDEX_INVALID) /* Already registered */
215 : {
216 0 : vector_index = ~0;
217 0 : goto done;
218 : }
219 :
220 71212 : vec_add1 (name, 0);
221 71212 : vlib_stats_set_entry_name (&e, (char *) name);
222 :
223 71212 : vlib_stats_segment_lock ();
224 71212 : vector_index = vlib_stats_create_counter (&e);
225 :
226 71212 : shared_header->directory_vector = sm->directory_vector;
227 :
228 71212 : vlib_stats_segment_unlock ();
229 :
230 71212 : done:
231 71212 : vec_free (name);
232 71212 : return vector_index;
233 : }
234 :
235 : u32
236 5246 : vlib_stats_add_gauge (char *fmt, ...)
237 : {
238 : va_list va;
239 : u8 *name;
240 :
241 5246 : va_start (va, fmt);
242 5246 : name = va_format (0, fmt, &va);
243 5246 : va_end (va);
244 5246 : return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
245 : }
246 :
247 : void
248 3301 : vlib_stats_set_gauge (u32 index, u64 value)
249 : {
250 3301 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
251 :
252 3301 : ASSERT (index < vec_len (sm->directory_vector));
253 3301 : sm->directory_vector[index].value = value;
254 3301 : }
255 :
256 : u32
257 575 : vlib_stats_add_timestamp (char *fmt, ...)
258 : {
259 : va_list va;
260 : u8 *name;
261 :
262 575 : va_start (va, fmt);
263 575 : name = va_format (0, fmt, &va);
264 575 : va_end (va);
265 575 : return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
266 : }
267 :
268 : void
269 1 : vlib_stats_set_timestamp (u32 entry_index, f64 value)
270 : {
271 1 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
272 :
273 1 : ASSERT (entry_index < vec_len (sm->directory_vector));
274 1 : sm->directory_vector[entry_index].value = value;
275 1 : }
276 :
277 : vlib_stats_string_vector_t
278 576 : vlib_stats_add_string_vector (char *fmt, ...)
279 : {
280 576 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
281 : va_list va;
282 : vlib_stats_header_t *sh;
283 : vlib_stats_string_vector_t sv;
284 : u32 index;
285 : u8 *name;
286 :
287 576 : va_start (va, fmt);
288 576 : name = va_format (0, fmt, &va);
289 576 : va_end (va);
290 :
291 576 : index = vlib_stats_new_entry_internal (STAT_DIR_TYPE_NAME_VECTOR, name);
292 576 : if (index == CLIB_U32_MAX)
293 0 : return 0;
294 :
295 576 : sv = vec_new_generic (vlib_stats_string_vector_t, 0,
296 : sizeof (vlib_stats_header_t), 0, sm->heap);
297 576 : sh = vec_header (sv);
298 576 : sh->entry_index = index;
299 576 : sm->directory_vector[index].string_vector = sv;
300 576 : return sv;
301 : }
302 :
303 : void
304 12557 : vlib_stats_set_string_vector (vlib_stats_string_vector_t *svp,
305 : u32 vector_index, char *fmt, ...)
306 : {
307 12557 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
308 12557 : vlib_stats_header_t *sh = vec_header (*svp);
309 12557 : vlib_stats_entry_t *e = vlib_stats_get_entry (sm, sh->entry_index);
310 : va_list va;
311 : u8 *s;
312 :
313 12557 : if (fmt[0] == 0)
314 : {
315 0 : if (vec_len (e->string_vector) <= vector_index)
316 0 : return;
317 :
318 0 : if (e->string_vector[vector_index] == 0)
319 0 : return;
320 :
321 0 : vlib_stats_segment_lock ();
322 0 : vec_free (e->string_vector[vector_index]);
323 0 : vlib_stats_segment_unlock ();
324 0 : return;
325 : }
326 :
327 12557 : vlib_stats_segment_lock ();
328 :
329 12557 : ASSERT (e->string_vector);
330 :
331 12557 : vec_validate (e->string_vector, vector_index);
332 12557 : svp[0] = e->string_vector;
333 :
334 12557 : s = e->string_vector[vector_index];
335 :
336 12557 : if (s == 0)
337 4689 : s = vec_new_heap (u8 *, 0, sm->heap);
338 :
339 12557 : vec_reset_length (s);
340 :
341 12557 : va_start (va, fmt);
342 12557 : s = va_format (s, fmt, &va);
343 12557 : va_end (va);
344 12557 : vec_add1 (s, 0);
345 :
346 12557 : e->string_vector[vector_index] = s;
347 :
348 12557 : vlib_stats_segment_unlock ();
349 : }
350 :
351 : void
352 0 : vlib_stats_free_string_vector (vlib_stats_string_vector_t *sv)
353 : {
354 0 : vlib_stats_header_t *sh = vec_header (*sv);
355 0 : vlib_stats_remove_entry (sh->entry_index);
356 0 : }
357 :
358 : u32
359 56862 : vlib_stats_add_counter_vector (char *fmt, ...)
360 : {
361 : va_list va;
362 : u8 *name;
363 :
364 56862 : va_start (va, fmt);
365 56862 : name = va_format (0, fmt, &va);
366 56862 : va_end (va);
367 56862 : return vlib_stats_new_entry_internal (STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE,
368 : name);
369 : }
370 :
371 : u32
372 7953 : vlib_stats_add_counter_pair_vector (char *fmt, ...)
373 : {
374 : va_list va;
375 : u8 *name;
376 :
377 7953 : va_start (va, fmt);
378 7953 : name = va_format (0, fmt, &va);
379 7953 : va_end (va);
380 7953 : return vlib_stats_new_entry_internal (STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED,
381 : name);
382 : }
383 :
384 : static int
385 838799 : vlib_stats_validate_will_expand_internal (u32 entry_index, va_list *va)
386 : {
387 838799 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
388 838799 : vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
389 : void *oldheap;
390 838799 : int rv = 1;
391 :
392 838799 : oldheap = clib_mem_set_heap (sm->heap);
393 838799 : if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE)
394 : {
395 614124 : u32 idx0 = va_arg (*va, u32);
396 614124 : u32 idx1 = va_arg (*va, u32);
397 614124 : u64 **data = e->data;
398 :
399 614124 : if (idx0 >= vec_len (data))
400 56917 : goto done;
401 :
402 1114300 : for (u32 i = 0; i <= idx0; i++)
403 576791 : if (idx1 >= vec_max_len (data[i]))
404 19698 : goto done;
405 : }
406 224675 : else if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED)
407 : {
408 224675 : u32 idx0 = va_arg (*va, u32);
409 224675 : u32 idx1 = va_arg (*va, u32);
410 224675 : vlib_counter_t **data = e->data;
411 :
412 224675 : va_end (*va);
413 :
414 224675 : if (idx0 >= vec_len (data))
415 7953 : goto done;
416 :
417 425009 : for (u32 i = 0; i <= idx0; i++)
418 225644 : if (idx1 >= vec_max_len (data[i]))
419 17357 : goto done;
420 : }
421 : else
422 0 : ASSERT (0);
423 :
424 736874 : rv = 0;
425 838799 : done:
426 838799 : clib_mem_set_heap (oldheap);
427 838799 : return rv;
428 : }
429 :
430 : int
431 0 : vlib_stats_validate_will_expand (u32 entry_index, ...)
432 : {
433 : va_list va;
434 : int rv;
435 :
436 0 : va_start (va, entry_index);
437 0 : rv = vlib_stats_validate_will_expand_internal (entry_index, &va);
438 0 : va_end (va);
439 0 : return rv;
440 : }
441 :
442 : void
443 838799 : vlib_stats_validate (u32 entry_index, ...)
444 : {
445 838799 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
446 838799 : vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
447 : void *oldheap;
448 : va_list va;
449 : int will_expand;
450 :
451 838799 : va_start (va, entry_index);
452 838799 : will_expand = vlib_stats_validate_will_expand_internal (entry_index, &va);
453 838799 : va_end (va);
454 :
455 838799 : if (will_expand)
456 101925 : vlib_stats_segment_lock ();
457 :
458 838799 : oldheap = clib_mem_set_heap (sm->heap);
459 :
460 838799 : va_start (va, entry_index);
461 :
462 838799 : if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE)
463 : {
464 614124 : u32 idx0 = va_arg (va, u32);
465 614124 : u32 idx1 = va_arg (va, u32);
466 614124 : u64 **data = e->data;
467 :
468 614124 : vec_validate_aligned (data, idx0, CLIB_CACHE_LINE_BYTES);
469 :
470 1254100 : for (u32 i = 0; i <= idx0; i++)
471 639975 : vec_validate_aligned (data[i], idx1, CLIB_CACHE_LINE_BYTES);
472 614124 : e->data = data;
473 : }
474 224675 : else if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED)
475 : {
476 224675 : u32 idx0 = va_arg (va, u32);
477 224675 : u32 idx1 = va_arg (va, u32);
478 224675 : vlib_counter_t **data = e->data;
479 :
480 224675 : vec_validate_aligned (data, idx0, CLIB_CACHE_LINE_BYTES);
481 :
482 460663 : for (u32 i = 0; i <= idx0; i++)
483 235988 : vec_validate_aligned (data[i], idx1, CLIB_CACHE_LINE_BYTES);
484 224675 : e->data = data;
485 : }
486 : else
487 0 : ASSERT (0);
488 :
489 838799 : va_end (va);
490 :
491 838799 : clib_mem_set_heap (oldheap);
492 :
493 838799 : if (will_expand)
494 101925 : vlib_stats_segment_unlock ();
495 838799 : }
496 :
497 : u32
498 2413840 : vlib_stats_add_symlink (u32 entry_index, u32 vector_index, char *fmt, ...)
499 : {
500 2413840 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
501 2413840 : vlib_stats_shared_header_t *shared_header = sm->shared_header;
502 : vlib_stats_entry_t e;
503 : va_list va;
504 : u8 *name;
505 :
506 2413840 : ASSERT (shared_header);
507 2413840 : ASSERT (entry_index < vec_len (sm->directory_vector));
508 :
509 2413840 : va_start (va, fmt);
510 2413840 : name = va_format (0, fmt, &va);
511 2413840 : va_end (va);
512 :
513 2413840 : if (vlib_stats_find_entry_index ("%v", name) == STAT_SEGMENT_INDEX_INVALID)
514 : {
515 2413840 : vec_add1 (name, 0);
516 2413840 : vlib_stats_set_entry_name (&e, (char *) name);
517 2413840 : e.type = STAT_DIR_TYPE_SYMLINK;
518 2413840 : e.index1 = entry_index;
519 2413840 : e.index2 = vector_index;
520 2413840 : vector_index = vlib_stats_create_counter (&e);
521 :
522 : /* Warn clients to refresh any pointers they might be holding */
523 2413840 : shared_header->directory_vector = sm->directory_vector;
524 : }
525 : else
526 0 : vector_index = ~0;
527 :
528 2413840 : vec_free (name);
529 2413840 : return vector_index;
530 : }
531 :
532 : void
533 0 : vlib_stats_rename_symlink (u64 entry_index, char *fmt, ...)
534 : {
535 0 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
536 0 : vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
537 : va_list va;
538 : u8 *new_name;
539 :
540 0 : hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
541 :
542 0 : va_start (va, fmt);
543 0 : new_name = va_format (0, fmt, &va);
544 0 : va_end (va);
545 :
546 0 : vec_add1 (new_name, 0);
547 0 : vlib_stats_set_entry_name (e, (char *) new_name);
548 0 : hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, entry_index);
549 0 : vec_free (new_name);
550 0 : }
551 :
552 : f64
553 1967 : vlib_stats_get_segment_update_rate (void)
554 : {
555 1967 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
556 1967 : return sm->update_interval;
557 : }
558 :
559 : void
560 4123 : vlib_stats_register_collector_fn (vlib_stats_collector_reg_t *reg)
561 : {
562 4123 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
563 : vlib_stats_collector_t *c;
564 :
565 4123 : ASSERT (reg->entry_index != ~0);
566 :
567 4123 : pool_get_zero (sm->collectors, c);
568 4123 : c->fn = reg->collect_fn;
569 4123 : c->entry_index = reg->entry_index;
570 4123 : c->vector_index = reg->vector_index;
571 4123 : c->private_data = reg->private_data;
572 :
573 4123 : return;
574 : }
|