1 /* SPDX-License-Identifier: Apache-2.0
2 * Copyright(c) 2022 Cisco Systems, Inc.
6 #include <vlib/stats/stats.h>
8 vlib_stats_main_t vlib_stats_main;
11 vlib_stats_segment_lock (void)
13 vlib_main_t *vm = vlib_get_main ();
14 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
16 /* already locked by us */
17 if (sm->shared_header->in_progress &&
18 vm->thread_index == sm->locking_thread_index)
21 ASSERT (sm->locking_thread_index == ~0);
22 ASSERT (sm->shared_header->in_progress == 0);
23 ASSERT (sm->n_locks == 0);
25 clib_spinlock_lock (sm->stat_segment_lockp);
27 sm->shared_header->in_progress = 1;
28 sm->locking_thread_index = vm->thread_index;
34 vlib_stats_segment_unlock (void)
36 vlib_main_t *vm = vlib_get_main ();
37 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
39 ASSERT (sm->shared_header->in_progress == 1);
40 ASSERT (sm->locking_thread_index == vm->thread_index);
41 ASSERT (sm->n_locks > 0);
48 sm->shared_header->epoch++;
49 __atomic_store_n (&sm->shared_header->in_progress, 0, __ATOMIC_RELEASE);
50 sm->locking_thread_index = ~0;
51 clib_spinlock_unlock (sm->stat_segment_lockp);
55 * Change heap to the stats shared memory segment
58 vlib_stats_set_heap ()
60 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
62 ASSERT (sm && sm->shared_header);
63 return clib_mem_set_heap (sm->heap);
67 vlib_stats_find_entry_index (char *fmt, ...)
73 name = va_format (0, fmt, &va);
77 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
78 hash_pair_t *hp = hash_get_pair (sm->directory_vector_by_name, name);
80 return hp ? hp->value[0] : STAT_SEGMENT_INDEX_INVALID;
84 hash_set_str_key_alloc (uword **h, const char *key, uword v)
86 int size = strlen (key) + 1;
87 void *copy = clib_mem_alloc (size);
88 clib_memcpy_fast (copy, key, size);
89 hash_set_mem (*h, copy, v);
93 hash_unset_str_key_free (uword **h, const char *key)
95 hash_pair_t *hp = hash_get_pair_mem (*h, key);
98 void *_k = uword_to_pointer (hp->key, void *);
99 hash_unset_mem (*h, _k);
105 vlib_stats_create_counter (vlib_stats_entry_t *e)
107 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
112 oldheap = clib_mem_set_heap (sm->heap);
113 vec_foreach_index_backwards (i, sm->directory_vector)
114 if (sm->directory_vector[i].type == STAT_DIR_TYPE_EMPTY)
120 index = index == ~0 ? vec_len (sm->directory_vector) : index;
122 vec_validate (sm->directory_vector, index);
123 sm->directory_vector[index] = *e;
125 clib_mem_set_heap (oldheap);
126 hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, index);
132 vlib_stats_remove_entry (u32 entry_index)
134 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
135 vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
141 if (entry_index >= vec_len (sm->directory_vector))
144 oldheap = clib_mem_set_heap (sm->heap);
146 vlib_stats_segment_lock ();
150 case STAT_DIR_TYPE_NAME_VECTOR:
151 for (i = 0; i < vec_len (e->string_vector); i++)
152 vec_free (e->string_vector[i]);
153 vec_free (e->string_vector);
156 case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
159 for (i = 0; i < vec_len (c); i++)
164 case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
167 for (i = 0; i < vec_len (vc); i++)
172 case STAT_DIR_TYPE_SCALAR_INDEX:
173 case STAT_DIR_TYPE_SYMLINK:
179 vlib_stats_segment_unlock ();
181 clib_mem_set_heap (oldheap);
182 hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
184 memset (e, 0, sizeof (*e));
185 e->type = STAT_DIR_TYPE_EMPTY;
189 vlib_stats_set_entry_name (vlib_stats_entry_t *e, char *s)
191 u32 i, len = VLIB_STATS_MAX_NAME_SZ - 1;
193 for (i = 0; i < len; i++)
199 ASSERT (i < VLIB_STATS_MAX_NAME_SZ - 1);
204 vlib_stats_new_entry_internal (stat_directory_type_t t, u8 *name)
206 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
207 vlib_stats_shared_header_t *shared_header = sm->shared_header;
208 vlib_stats_entry_t e = { .type = t };
210 ASSERT (shared_header);
212 u32 vector_index = vlib_stats_find_entry_index ("%v", name);
213 if (vector_index != STAT_SEGMENT_INDEX_INVALID) /* Already registered */
220 vlib_stats_set_entry_name (&e, (char *) name);
222 vlib_stats_segment_lock ();
223 vector_index = vlib_stats_create_counter (&e);
225 shared_header->directory_vector = sm->directory_vector;
227 vlib_stats_segment_unlock ();
235 vlib_stats_add_gauge (char *fmt, ...)
241 name = va_format (0, fmt, &va);
243 return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
247 vlib_stats_register_error_index (u64 *em_vec, u64 index, char *fmt, ...)
249 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
250 vlib_stats_shared_header_t *shared_header = sm->shared_header;
251 vlib_stats_entry_t e = {};
256 name = va_format (0, fmt, &va);
259 ASSERT (shared_header);
261 vlib_stats_segment_lock ();
262 u32 vector_index = vlib_stats_find_entry_index ("%v", name);
264 if (vector_index == STAT_SEGMENT_INDEX_INVALID)
267 vlib_stats_set_entry_name (&e, (char *) name);
268 e.type = STAT_DIR_TYPE_ERROR_INDEX;
270 vector_index = vlib_stats_create_counter (&e);
272 /* Warn clients to refresh any pointers they might be holding */
273 shared_header->directory_vector = sm->directory_vector;
276 vlib_stats_segment_unlock ();
281 vlib_stats_update_error_vector (u64 *error_vector, u32 thread_index, int lock)
283 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
284 vlib_stats_shared_header_t *shared_header = sm->shared_header;
285 void *oldheap = clib_mem_set_heap (sm->heap);
287 ASSERT (shared_header);
290 vlib_stats_segment_lock ();
292 /* Reset the client hash table pointer, since it WILL change! */
293 vec_validate (sm->error_vector, thread_index);
294 sm->error_vector[thread_index] = error_vector;
296 shared_header->error_vector = sm->error_vector;
297 shared_header->directory_vector = sm->directory_vector;
300 vlib_stats_segment_unlock ();
301 clib_mem_set_heap (oldheap);
305 vlib_stats_set_gauge (u32 index, u64 value)
307 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
309 ASSERT (index < vec_len (sm->directory_vector));
310 sm->directory_vector[index].value = value;
314 vlib_stats_add_timestamp (char *fmt, ...)
320 name = va_format (0, fmt, &va);
322 return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
326 vlib_stats_set_timestamp (u32 entry_index, f64 value)
328 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
330 ASSERT (entry_index < vec_len (sm->directory_vector));
331 sm->directory_vector[entry_index].value = value;
335 vlib_stats_add_string_vector (char *fmt, ...)
341 name = va_format (0, fmt, &va);
343 return vlib_stats_new_entry_internal (STAT_DIR_TYPE_NAME_VECTOR, name);
347 vlib_stats_set_string_vector (u32 entry_index, u32 vector_index, char *fmt,
350 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
351 vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
355 oldheap = clib_mem_set_heap (sm->heap);
356 vlib_stats_segment_lock ();
358 vec_validate (e->string_vector, vector_index);
359 vec_reset_length (e->string_vector[vector_index]);
362 e->string_vector[vector_index] =
363 va_format (e->string_vector[vector_index], fmt, &va);
366 vlib_stats_segment_unlock ();
367 clib_mem_set_heap (oldheap);
371 vlib_stats_add_counter_vector (char *fmt, ...)
377 name = va_format (0, fmt, &va);
379 return vlib_stats_new_entry_internal (STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE,
384 vlib_stats_add_counter_pair_vector (char *fmt, ...)
390 name = va_format (0, fmt, &va);
392 return vlib_stats_new_entry_internal (STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED,
397 vlib_stats_validate_will_expand_internal (u32 entry_index, va_list *va)
399 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
400 vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
404 oldheap = clib_mem_set_heap (sm->heap);
405 if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE)
407 u32 idx0 = va_arg (*va, u32);
408 u32 idx1 = va_arg (*va, u32);
409 u64 **data = e->data;
411 if (idx0 >= vec_max_len (data))
414 for (u32 i = 0; i <= idx0; i++)
415 if (idx1 >= vec_max_len (data[i]))
418 else if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED)
420 u32 idx0 = va_arg (*va, u32);
421 u32 idx1 = va_arg (*va, u32);
422 vlib_counter_t **data = e->data;
426 if (idx0 >= vec_max_len (data))
429 for (u32 i = 0; i <= idx0; i++)
430 if (idx1 >= vec_max_len (data[i]))
438 clib_mem_set_heap (oldheap);
443 vlib_stats_validate_will_expand (u32 entry_index, ...)
448 va_start (va, entry_index);
449 rv = vlib_stats_validate_will_expand_internal (entry_index, &va);
455 vlib_stats_validate (u32 entry_index, ...)
457 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
458 vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
463 va_start (va, entry_index);
464 will_expand = vlib_stats_validate_will_expand_internal (entry_index, &va);
468 vlib_stats_segment_lock ();
470 oldheap = clib_mem_set_heap (sm->heap);
472 va_start (va, entry_index);
474 if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE)
476 u32 idx0 = va_arg (va, u32);
477 u32 idx1 = va_arg (va, u32);
478 u64 **data = e->data;
480 vec_validate_aligned (data, idx0, CLIB_CACHE_LINE_BYTES);
482 for (u32 i = 0; i <= idx0; i++)
483 vec_validate_aligned (data[i], idx1, CLIB_CACHE_LINE_BYTES);
486 else if (e->type == STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED)
488 u32 idx0 = va_arg (va, u32);
489 u32 idx1 = va_arg (va, u32);
490 vlib_counter_t **data = e->data;
492 vec_validate_aligned (data, idx0, CLIB_CACHE_LINE_BYTES);
494 for (u32 i = 0; i <= idx0; i++)
495 vec_validate_aligned (data[i], idx1, CLIB_CACHE_LINE_BYTES);
503 clib_mem_set_heap (oldheap);
506 vlib_stats_segment_unlock ();
510 vlib_stats_add_symlink (u32 entry_index, u32 vector_index, char *fmt, ...)
512 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
513 vlib_stats_shared_header_t *shared_header = sm->shared_header;
514 vlib_stats_entry_t e;
518 ASSERT (shared_header);
519 ASSERT (entry_index < vec_len (sm->directory_vector));
522 name = va_format (0, fmt, &va);
525 if (vlib_stats_find_entry_index ("%v", name) == STAT_SEGMENT_INDEX_INVALID)
528 vlib_stats_set_entry_name (&e, (char *) name);
529 e.type = STAT_DIR_TYPE_SYMLINK;
530 e.index1 = entry_index;
531 e.index2 = vector_index;
532 vector_index = vlib_stats_create_counter (&e);
534 /* Warn clients to refresh any pointers they might be holding */
535 shared_header->directory_vector = sm->directory_vector;
545 vlib_stats_rename_symlink (u64 entry_index, char *fmt, ...)
547 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
548 vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
552 hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
555 new_name = va_format (0, fmt, &va);
558 vec_add1 (new_name, 0);
559 vlib_stats_set_entry_name (e, (char *) new_name);
560 hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, entry_index);
565 vlib_stats_get_segment_update_rate (void)
567 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
568 return sm->update_interval;
572 vlib_stats_register_collector_fn (vlib_stats_collector_reg_t *reg)
574 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
575 vlib_stats_collector_t *c;
577 ASSERT (reg->entry_index != ~0);
579 pool_get_zero (sm->collectors, c);
580 c->fn = reg->collect_fn;
581 c->entry_index = reg->entry_index;
582 c->vector_index = reg->vector_index;
583 c->private_data = reg->private_data;