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 666868 : vlib_stats_segment_lock (void)
12 : {
13 666868 : vlib_main_t *vm = vlib_get_main ();
14 666868 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
15 :
16 : /* already locked by us */
17 666868 : if (sm->shared_header->in_progress &&
18 88841 : vm->thread_index == sm->locking_thread_index)
19 88841 : goto done;
20 :
21 578027 : ASSERT (sm->locking_thread_index == ~0);
22 578027 : ASSERT (sm->shared_header->in_progress == 0);
23 578027 : ASSERT (sm->n_locks == 0);
24 :
25 578027 : clib_spinlock_lock (sm->stat_segment_lockp);
26 :
27 578027 : sm->shared_header->in_progress = 1;
28 578027 : sm->locking_thread_index = vm->thread_index;
29 666868 : done:
30 666868 : sm->n_locks++;
31 666868 : }
32 :
33 : void
34 666868 : vlib_stats_segment_unlock (void)
35 : {
36 666868 : vlib_main_t *vm = vlib_get_main ();
37 666868 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
38 :
39 666868 : ASSERT (sm->shared_header->in_progress == 1);
40 666868 : ASSERT (sm->locking_thread_index == vm->thread_index);
41 666868 : ASSERT (sm->n_locks > 0);
42 :
43 666868 : sm->n_locks--;
44 :
45 666868 : if (sm->n_locks > 0)
46 88841 : return;
47 :
48 578027 : sm->shared_header->epoch++;
49 578027 : __atomic_store_n (&sm->shared_header->in_progress, 0, __ATOMIC_RELEASE);
50 578027 : sm->locking_thread_index = ~0;
51 578027 : clib_spinlock_unlock (sm->stat_segment_lockp);
52 : }
53 :
54 : /*
55 : * Change heap to the stats shared memory segment
56 : */
57 : void *
58 100488 : vlib_stats_set_heap ()
59 : {
60 100488 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
61 :
62 100488 : ASSERT (sm && sm->shared_header);
63 100488 : return clib_mem_set_heap (sm->heap);
64 : }
65 :
66 : u32
67 2414080 : vlib_stats_find_entry_index (char *fmt, ...)
68 : {
69 : u8 *name;
70 : va_list va;
71 :
72 2414080 : va_start (va, fmt);
73 2414080 : name = va_format (0, fmt, &va);
74 2414080 : va_end (va);
75 2414080 : vec_add1 (name, 0);
76 :
77 2414080 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
78 2414080 : hash_pair_t *hp = hash_get_pair (sm->directory_vector_by_name, name);
79 2414080 : vec_free (name);
80 2414080 : return hp ? hp->value[0] : STAT_SEGMENT_INDEX_INVALID;
81 : }
82 :
83 : static void
84 2404580 : hash_set_str_key_alloc (uword **h, const char *key, uword v)
85 : {
86 2404580 : int size = strlen (key) + 1;
87 2404580 : void *copy = clib_mem_alloc (size);
88 2404580 : clib_memcpy_fast (copy, key, size);
89 4809160 : hash_set_mem (*h, copy, v);
90 2404580 : }
91 :
92 : static void
93 74634 : hash_unset_str_key_free (uword **h, const char *key)
94 : {
95 74634 : hash_pair_t *hp = hash_get_pair_mem (*h, key);
96 74634 : if (hp)
97 : {
98 74634 : void *_k = uword_to_pointer (hp->key, void *);
99 74634 : hash_unset_mem (*h, _k);
100 74634 : clib_mem_free (_k);
101 : }
102 74634 : }
103 :
104 : u32
105 2404580 : vlib_stats_create_counter (vlib_stats_entry_t *e)
106 : {
107 2404580 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
108 : u32 index;
109 :
110 2404580 : if (sm->dir_vector_first_free_elt != CLIB_U32_MAX)
111 : {
112 63119 : index = sm->dir_vector_first_free_elt;
113 63119 : sm->dir_vector_first_free_elt = sm->directory_vector[index].index;
114 : }
115 : else
116 : {
117 2341460 : index = vec_len (sm->directory_vector);
118 2341460 : vec_validate (sm->directory_vector, index);
119 : }
120 :
121 2404580 : sm->directory_vector[index] = *e;
122 :
123 2404580 : hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, index);
124 :
125 2404580 : return index;
126 : }
127 :
128 : void
129 74634 : vlib_stats_remove_entry (u32 entry_index)
130 : {
131 74634 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
132 74634 : 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 74634 : if (entry_index >= vec_len (sm->directory_vector))
139 0 : return;
140 :
141 74634 : vlib_stats_segment_lock ();
142 :
143 74634 : 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 74632 : case STAT_DIR_TYPE_SCALAR_INDEX:
172 : case STAT_DIR_TYPE_SYMLINK:
173 74632 : break;
174 0 : default:
175 0 : ASSERT (0);
176 : }
177 :
178 74634 : vlib_stats_segment_unlock ();
179 :
180 74634 : hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
181 :
182 74634 : memset (e, 0, sizeof (*e));
183 74634 : e->type = STAT_DIR_TYPE_EMPTY;
184 :
185 74634 : e->value = sm->dir_vector_first_free_elt;
186 74634 : sm->dir_vector_first_free_elt = entry_index;
187 : }
188 :
189 : static void
190 2404580 : vlib_stats_set_entry_name (vlib_stats_entry_t *e, char *s)
191 : {
192 2404580 : u32 i, len = VLIB_STATS_MAX_NAME_SZ - 1;
193 :
194 94421800 : for (i = 0; i < len; i++)
195 : {
196 94421800 : e->name[i] = s[i];
197 94421800 : if (s[i] == 0)
198 2404580 : return;
199 : }
200 0 : ASSERT (i < VLIB_STATS_MAX_NAME_SZ - 1);
201 0 : s[i] = 0;
202 : }
203 :
204 : static u32
205 69124 : vlib_stats_new_entry_internal (stat_directory_type_t t, u8 *name)
206 : {
207 69124 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
208 69124 : vlib_stats_shared_header_t *shared_header = sm->shared_header;
209 69124 : vlib_stats_entry_t e = { .type = t };
210 :
211 69124 : ASSERT (shared_header);
212 :
213 69124 : u32 vector_index = vlib_stats_find_entry_index ("%v", name);
214 69124 : if (vector_index != STAT_SEGMENT_INDEX_INVALID) /* Already registered */
215 : {
216 0 : vector_index = ~0;
217 0 : goto done;
218 : }
219 :
220 69124 : vec_add1 (name, 0);
221 69124 : vlib_stats_set_entry_name (&e, (char *) name);
222 :
223 69124 : vlib_stats_segment_lock ();
224 69124 : vector_index = vlib_stats_create_counter (&e);
225 :
226 69124 : shared_header->directory_vector = sm->directory_vector;
227 :
228 69124 : vlib_stats_segment_unlock ();
229 :
230 69124 : done:
231 69124 : vec_free (name);
232 69124 : return vector_index;
233 : }
234 :
235 : u32
236 5102 : vlib_stats_add_gauge (char *fmt, ...)
237 : {
238 : va_list va;
239 : u8 *name;
240 :
241 5102 : va_start (va, fmt);
242 5102 : name = va_format (0, fmt, &va);
243 5102 : va_end (va);
244 5102 : return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
245 : }
246 :
247 : void
248 3254 : vlib_stats_set_gauge (u32 index, u64 value)
249 : {
250 3254 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
251 :
252 3254 : ASSERT (index < vec_len (sm->directory_vector));
253 3254 : sm->directory_vector[index].value = value;
254 3254 : }
255 :
256 : u32
257 559 : vlib_stats_add_timestamp (char *fmt, ...)
258 : {
259 : va_list va;
260 : u8 *name;
261 :
262 559 : va_start (va, fmt);
263 559 : name = va_format (0, fmt, &va);
264 559 : va_end (va);
265 559 : return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
266 : }
267 :
268 : void
269 0 : vlib_stats_set_timestamp (u32 entry_index, f64 value)
270 : {
271 0 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
272 :
273 0 : ASSERT (entry_index < vec_len (sm->directory_vector));
274 0 : sm->directory_vector[entry_index].value = value;
275 0 : }
276 :
277 : vlib_stats_string_vector_t
278 560 : vlib_stats_add_string_vector (char *fmt, ...)
279 : {
280 560 : 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 560 : va_start (va, fmt);
288 560 : name = va_format (0, fmt, &va);
289 560 : va_end (va);
290 :
291 560 : index = vlib_stats_new_entry_internal (STAT_DIR_TYPE_NAME_VECTOR, name);
292 560 : if (index == CLIB_U32_MAX)
293 0 : return 0;
294 :
295 560 : sv = vec_new_generic (vlib_stats_string_vector_t, 0,
296 : sizeof (vlib_stats_header_t), 0, sm->heap);
297 560 : sh = vec_header (sv);
298 560 : sh->entry_index = index;
299 560 : sm->directory_vector[index].string_vector = sv;
300 560 : return sv;
301 : }
302 :
303 : void
304 8174 : vlib_stats_set_string_vector (vlib_stats_string_vector_t *svp,
305 : u32 vector_index, char *fmt, ...)
306 : {
307 8174 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
308 8174 : vlib_stats_header_t *sh = vec_header (*svp);
309 8174 : vlib_stats_entry_t *e = vlib_stats_get_entry (sm, sh->entry_index);
310 : va_list va;
311 : u8 *s;
312 :
313 8174 : 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 8174 : vlib_stats_segment_lock ();
328 :
329 8174 : ASSERT (e->string_vector);
330 :
331 8174 : vec_validate (e->string_vector, vector_index);
332 8174 : svp[0] = e->string_vector;
333 :
334 8174 : s = e->string_vector[vector_index];
335 :
336 8174 : if (s == 0)
337 4629 : s = vec_new_heap (u8 *, 0, sm->heap);
338 :
339 8174 : vec_reset_length (s);
340 :
341 8174 : va_start (va, fmt);
342 8174 : s = va_format (s, fmt, &va);
343 8174 : va_end (va);
344 8174 : vec_add1 (s, 0);
345 :
346 8174 : e->string_vector[vector_index] = s;
347 :
348 8174 : 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 55182 : vlib_stats_add_counter_vector (char *fmt, ...)
360 : {
361 : va_list va;
362 : u8 *name;
363 :
364 55182 : va_start (va, fmt);
365 55182 : name = va_format (0, fmt, &va);
366 55182 : va_end (va);
367 55182 : return vlib_stats_new_entry_internal (STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE,
368 : name);
369 : }
370 :
371 : u32
372 7721 : vlib_stats_add_counter_pair_vector (char *fmt, ...)
373 : {
374 : va_list va;
375 : u8 *name;
376 :
377 7721 : va_start (va, fmt);
378 7721 : name = va_format (0, fmt, &va);
379 7721 : va_end (va);
380 7721 : return vlib_stats_new_entry_internal (STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED,
381 : name);
382 : }
383 :
384 : static int
385 819035 : vlib_stats_validate_will_expand_internal (u32 entry_index, va_list *va)
386 : {
387 819035 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
388 819035 : vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
389 : void *oldheap;
390 819035 : int rv = 1;
391 :
392 819035 : oldheap = clib_mem_set_heap (sm->heap);
393 819035 : if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE)
394 : {
395 597570 : u32 idx0 = va_arg (*va, u32);
396 597570 : u32 idx1 = va_arg (*va, u32);
397 597570 : u64 **data = e->data;
398 :
399 597570 : if (idx0 >= vec_len (data))
400 55236 : goto done;
401 :
402 1085080 : for (u32 i = 0; i <= idx0; i++)
403 561909 : if (idx1 >= vec_max_len (data[i]))
404 19163 : goto done;
405 : }
406 221465 : else if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED)
407 : {
408 221465 : u32 idx0 = va_arg (*va, u32);
409 221465 : u32 idx1 = va_arg (*va, u32);
410 221465 : vlib_counter_t **data = e->data;
411 :
412 221465 : va_end (*va);
413 :
414 221465 : if (idx0 >= vec_len (data))
415 7721 : goto done;
416 :
417 420275 : for (u32 i = 0; i <= idx0; i++)
418 222943 : if (idx1 >= vec_max_len (data[i]))
419 16412 : goto done;
420 : }
421 : else
422 0 : ASSERT (0);
423 :
424 720503 : rv = 0;
425 819035 : done:
426 819035 : clib_mem_set_heap (oldheap);
427 819035 : 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 819035 : vlib_stats_validate (u32 entry_index, ...)
444 : {
445 819035 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
446 819035 : 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 819035 : va_start (va, entry_index);
452 819035 : will_expand = vlib_stats_validate_will_expand_internal (entry_index, &va);
453 819035 : va_end (va);
454 :
455 819035 : if (will_expand)
456 98532 : vlib_stats_segment_lock ();
457 :
458 819035 : oldheap = clib_mem_set_heap (sm->heap);
459 :
460 819035 : va_start (va, entry_index);
461 :
462 819035 : if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE)
463 : {
464 597570 : u32 idx0 = va_arg (va, u32);
465 597570 : u32 idx1 = va_arg (va, u32);
466 597570 : u64 **data = e->data;
467 :
468 597570 : vec_validate_aligned (data, idx0, CLIB_CACHE_LINE_BYTES);
469 :
470 1220800 : for (u32 i = 0; i <= idx0; i++)
471 623233 : vec_validate_aligned (data[i], idx1, CLIB_CACHE_LINE_BYTES);
472 597570 : e->data = data;
473 : }
474 221465 : else if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED)
475 : {
476 221465 : u32 idx0 = va_arg (va, u32);
477 221465 : u32 idx1 = va_arg (va, u32);
478 221465 : vlib_counter_t **data = e->data;
479 :
480 221465 : vec_validate_aligned (data, idx0, CLIB_CACHE_LINE_BYTES);
481 :
482 454541 : for (u32 i = 0; i <= idx0; i++)
483 233076 : vec_validate_aligned (data[i], idx1, CLIB_CACHE_LINE_BYTES);
484 221465 : e->data = data;
485 : }
486 : else
487 0 : ASSERT (0);
488 :
489 819035 : va_end (va);
490 :
491 819035 : clib_mem_set_heap (oldheap);
492 :
493 819035 : if (will_expand)
494 98532 : vlib_stats_segment_unlock ();
495 819035 : }
496 :
497 : u32
498 2335460 : vlib_stats_add_symlink (u32 entry_index, u32 vector_index, char *fmt, ...)
499 : {
500 2335460 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
501 2335460 : 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 2335460 : ASSERT (shared_header);
507 2335460 : ASSERT (entry_index < vec_len (sm->directory_vector));
508 :
509 2335460 : va_start (va, fmt);
510 2335460 : name = va_format (0, fmt, &va);
511 2335460 : va_end (va);
512 :
513 2335460 : if (vlib_stats_find_entry_index ("%v", name) == STAT_SEGMENT_INDEX_INVALID)
514 : {
515 2335460 : vec_add1 (name, 0);
516 2335460 : vlib_stats_set_entry_name (&e, (char *) name);
517 2335460 : e.type = STAT_DIR_TYPE_SYMLINK;
518 2335460 : e.index1 = entry_index;
519 2335460 : e.index2 = vector_index;
520 2335460 : vector_index = vlib_stats_create_counter (&e);
521 :
522 : /* Warn clients to refresh any pointers they might be holding */
523 2335460 : shared_header->directory_vector = sm->directory_vector;
524 : }
525 : else
526 0 : vector_index = ~0;
527 :
528 2335460 : vec_free (name);
529 2335460 : 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 1958 : vlib_stats_get_segment_update_rate (void)
554 : {
555 1958 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
556 1958 : return sm->update_interval;
557 : }
558 :
559 : void
560 4011 : vlib_stats_register_collector_fn (vlib_stats_collector_reg_t *reg)
561 : {
562 4011 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
563 : vlib_stats_collector_t *c;
564 :
565 4011 : ASSERT (reg->entry_index != ~0);
566 :
567 4011 : pool_get_zero (sm->collectors, c);
568 4011 : c->fn = reg->collect_fn;
569 4011 : c->entry_index = reg->entry_index;
570 4011 : c->vector_index = reg->vector_index;
571 4011 : c->private_data = reg->private_data;
572 :
573 4011 : return;
574 : }
|