xref: /dpdk/lib/metrics/rte_metrics.c (revision 6d03ef606bf50258d2b299fcb6df64e3c03fd216)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2017 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
572b452c5SDmitry Kozlyuk #include <stdlib.h>
699a2dd95SBruce Richardson #include <string.h>
799a2dd95SBruce Richardson 
8*6d03ef60SBruce Richardson #include <rte_errno.h>
999a2dd95SBruce Richardson #include <rte_common.h>
1099a2dd95SBruce Richardson #include <rte_string_fns.h>
1199a2dd95SBruce Richardson #include <rte_metrics.h>
1299a2dd95SBruce Richardson #include <rte_memzone.h>
1399a2dd95SBruce Richardson #include <rte_spinlock.h>
1499a2dd95SBruce Richardson 
1599a2dd95SBruce Richardson int metrics_initialized;
1699a2dd95SBruce Richardson 
1799a2dd95SBruce Richardson #define RTE_METRICS_MEMZONE_NAME "RTE_METRICS"
1899a2dd95SBruce Richardson 
1999a2dd95SBruce Richardson /**
2099a2dd95SBruce Richardson  * Internal stats metadata and value entry.
2199a2dd95SBruce Richardson  *
2299a2dd95SBruce Richardson  * @internal
2399a2dd95SBruce Richardson  */
2499a2dd95SBruce Richardson struct rte_metrics_meta_s {
2599a2dd95SBruce Richardson 	/** Name of metric */
2699a2dd95SBruce Richardson 	char name[RTE_METRICS_MAX_NAME_LEN];
2799a2dd95SBruce Richardson 	/** Current value for metric */
2899a2dd95SBruce Richardson 	uint64_t value[RTE_MAX_ETHPORTS];
2999a2dd95SBruce Richardson 	/** Used for global metrics */
3099a2dd95SBruce Richardson 	uint64_t global_value;
3199a2dd95SBruce Richardson 	/** Index of next root element (zero for none) */
3299a2dd95SBruce Richardson 	uint16_t idx_next_set;
3399a2dd95SBruce Richardson 	/** Index of next metric in set (zero for none) */
3499a2dd95SBruce Richardson 	uint16_t idx_next_stat;
3599a2dd95SBruce Richardson };
3699a2dd95SBruce Richardson 
3799a2dd95SBruce Richardson /**
3899a2dd95SBruce Richardson  * Internal stats info structure.
3999a2dd95SBruce Richardson  *
4099a2dd95SBruce Richardson  * @internal
4199a2dd95SBruce Richardson  * Offsets into metadata are used instead of pointers because ASLR
4299a2dd95SBruce Richardson  * means that having the same physical addresses in different
4399a2dd95SBruce Richardson  * processes is not guaranteed.
4499a2dd95SBruce Richardson  */
4599a2dd95SBruce Richardson struct rte_metrics_data_s {
4699a2dd95SBruce Richardson 	/**   Index of last metadata entry with valid data.
4799a2dd95SBruce Richardson 	 * This value is not valid if cnt_stats is zero.
4899a2dd95SBruce Richardson 	 */
4999a2dd95SBruce Richardson 	uint16_t idx_last_set;
5099a2dd95SBruce Richardson 	/**   Number of metrics. */
5199a2dd95SBruce Richardson 	uint16_t cnt_stats;
5299a2dd95SBruce Richardson 	/** Metric data memory block. */
5399a2dd95SBruce Richardson 	struct rte_metrics_meta_s metadata[RTE_METRICS_MAX_METRICS];
5499a2dd95SBruce Richardson 	/** Metric data access lock */
5599a2dd95SBruce Richardson 	rte_spinlock_t lock;
5699a2dd95SBruce Richardson };
5799a2dd95SBruce Richardson 
58*6d03ef60SBruce Richardson int
rte_metrics_init(int socket_id)5999a2dd95SBruce Richardson rte_metrics_init(int socket_id)
6099a2dd95SBruce Richardson {
6199a2dd95SBruce Richardson 	struct rte_metrics_data_s *stats;
6299a2dd95SBruce Richardson 	const struct rte_memzone *memzone;
6399a2dd95SBruce Richardson 
6499a2dd95SBruce Richardson 	if (metrics_initialized)
65*6d03ef60SBruce Richardson 		return 0;
6699a2dd95SBruce Richardson 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
67*6d03ef60SBruce Richardson 		return -E_RTE_SECONDARY;
6899a2dd95SBruce Richardson 
6999a2dd95SBruce Richardson 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
7099a2dd95SBruce Richardson 	if (memzone != NULL)
71*6d03ef60SBruce Richardson 		return -EEXIST;
7299a2dd95SBruce Richardson 	memzone = rte_memzone_reserve(RTE_METRICS_MEMZONE_NAME,
7399a2dd95SBruce Richardson 		sizeof(struct rte_metrics_data_s), socket_id, 0);
7499a2dd95SBruce Richardson 	if (memzone == NULL)
75*6d03ef60SBruce Richardson 		return -ENOMEM;
7699a2dd95SBruce Richardson 	stats = memzone->addr;
7799a2dd95SBruce Richardson 	memset(stats, 0, sizeof(struct rte_metrics_data_s));
7899a2dd95SBruce Richardson 	rte_spinlock_init(&stats->lock);
7999a2dd95SBruce Richardson 	metrics_initialized = 1;
80*6d03ef60SBruce Richardson 	return 0;
8199a2dd95SBruce Richardson }
8299a2dd95SBruce Richardson 
8399a2dd95SBruce Richardson int
rte_metrics_deinit(void)8499a2dd95SBruce Richardson rte_metrics_deinit(void)
8599a2dd95SBruce Richardson {
8699a2dd95SBruce Richardson 	struct rte_metrics_data_s *stats;
8799a2dd95SBruce Richardson 	const struct rte_memzone *memzone;
8899a2dd95SBruce Richardson 	int ret;
8999a2dd95SBruce Richardson 
9099a2dd95SBruce Richardson 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
9199a2dd95SBruce Richardson 		return -EINVAL;
9299a2dd95SBruce Richardson 
9399a2dd95SBruce Richardson 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
9499a2dd95SBruce Richardson 	if (memzone == NULL)
9599a2dd95SBruce Richardson 		return -EIO;
9699a2dd95SBruce Richardson 
9799a2dd95SBruce Richardson 	stats = memzone->addr;
9899a2dd95SBruce Richardson 	memset(stats, 0, sizeof(struct rte_metrics_data_s));
9999a2dd95SBruce Richardson 
10099a2dd95SBruce Richardson 	ret = rte_memzone_free(memzone);
10199a2dd95SBruce Richardson 	if (ret == 0)
10299a2dd95SBruce Richardson 		metrics_initialized = 0;
10399a2dd95SBruce Richardson 	return ret;
10499a2dd95SBruce Richardson }
10599a2dd95SBruce Richardson 
10699a2dd95SBruce Richardson int
rte_metrics_reg_name(const char * name)10799a2dd95SBruce Richardson rte_metrics_reg_name(const char *name)
10899a2dd95SBruce Richardson {
10999a2dd95SBruce Richardson 	const char * const list_names[] = {name};
11099a2dd95SBruce Richardson 
11199a2dd95SBruce Richardson 	return rte_metrics_reg_names(list_names, 1);
11299a2dd95SBruce Richardson }
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson int
rte_metrics_reg_names(const char * const * names,uint16_t cnt_names)11599a2dd95SBruce Richardson rte_metrics_reg_names(const char * const *names, uint16_t cnt_names)
11699a2dd95SBruce Richardson {
11799a2dd95SBruce Richardson 	struct rte_metrics_meta_s *entry = NULL;
11899a2dd95SBruce Richardson 	struct rte_metrics_data_s *stats;
11999a2dd95SBruce Richardson 	const struct rte_memzone *memzone;
12099a2dd95SBruce Richardson 	uint16_t idx_name;
12199a2dd95SBruce Richardson 	uint16_t idx_base;
12299a2dd95SBruce Richardson 
12399a2dd95SBruce Richardson 	/* Some sanity checks */
12499a2dd95SBruce Richardson 	if (cnt_names < 1 || names == NULL)
12599a2dd95SBruce Richardson 		return -EINVAL;
12699a2dd95SBruce Richardson 	for (idx_name = 0; idx_name < cnt_names; idx_name++)
12799a2dd95SBruce Richardson 		if (names[idx_name] == NULL)
12899a2dd95SBruce Richardson 			return -EINVAL;
12999a2dd95SBruce Richardson 
13099a2dd95SBruce Richardson 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
13199a2dd95SBruce Richardson 	if (memzone == NULL)
13299a2dd95SBruce Richardson 		return -EIO;
13399a2dd95SBruce Richardson 	stats = memzone->addr;
13499a2dd95SBruce Richardson 
13599a2dd95SBruce Richardson 	if (stats->cnt_stats + cnt_names >= RTE_METRICS_MAX_METRICS)
13699a2dd95SBruce Richardson 		return -ENOMEM;
13799a2dd95SBruce Richardson 
13899a2dd95SBruce Richardson 	rte_spinlock_lock(&stats->lock);
13999a2dd95SBruce Richardson 
14099a2dd95SBruce Richardson 	/* Overwritten later if this is actually first set.. */
14199a2dd95SBruce Richardson 	stats->metadata[stats->idx_last_set].idx_next_set = stats->cnt_stats;
14299a2dd95SBruce Richardson 
14399a2dd95SBruce Richardson 	stats->idx_last_set = idx_base = stats->cnt_stats;
14499a2dd95SBruce Richardson 
14599a2dd95SBruce Richardson 	for (idx_name = 0; idx_name < cnt_names; idx_name++) {
14699a2dd95SBruce Richardson 		entry = &stats->metadata[idx_name + stats->cnt_stats];
14799a2dd95SBruce Richardson 		strlcpy(entry->name, names[idx_name], RTE_METRICS_MAX_NAME_LEN);
14899a2dd95SBruce Richardson 		memset(entry->value, 0, sizeof(entry->value));
14999a2dd95SBruce Richardson 		entry->idx_next_stat = idx_name + stats->cnt_stats + 1;
15099a2dd95SBruce Richardson 	}
15199a2dd95SBruce Richardson 	entry->idx_next_stat = 0;
15299a2dd95SBruce Richardson 	entry->idx_next_set = 0;
15399a2dd95SBruce Richardson 	stats->cnt_stats += cnt_names;
15499a2dd95SBruce Richardson 
15599a2dd95SBruce Richardson 	rte_spinlock_unlock(&stats->lock);
15699a2dd95SBruce Richardson 
15799a2dd95SBruce Richardson 	return idx_base;
15899a2dd95SBruce Richardson }
15999a2dd95SBruce Richardson 
16099a2dd95SBruce Richardson int
rte_metrics_update_value(int port_id,uint16_t key,const uint64_t value)16199a2dd95SBruce Richardson rte_metrics_update_value(int port_id, uint16_t key, const uint64_t value)
16299a2dd95SBruce Richardson {
16399a2dd95SBruce Richardson 	return rte_metrics_update_values(port_id, key, &value, 1);
16499a2dd95SBruce Richardson }
16599a2dd95SBruce Richardson 
16699a2dd95SBruce Richardson int
rte_metrics_update_values(int port_id,uint16_t key,const uint64_t * values,uint32_t count)16799a2dd95SBruce Richardson rte_metrics_update_values(int port_id,
16899a2dd95SBruce Richardson 	uint16_t key,
16999a2dd95SBruce Richardson 	const uint64_t *values,
17099a2dd95SBruce Richardson 	uint32_t count)
17199a2dd95SBruce Richardson {
17299a2dd95SBruce Richardson 	struct rte_metrics_meta_s *entry;
17399a2dd95SBruce Richardson 	struct rte_metrics_data_s *stats;
17499a2dd95SBruce Richardson 	const struct rte_memzone *memzone;
17599a2dd95SBruce Richardson 	uint16_t idx_metric;
17699a2dd95SBruce Richardson 	uint16_t idx_value;
17799a2dd95SBruce Richardson 	uint16_t cnt_setsize;
17899a2dd95SBruce Richardson 
17999a2dd95SBruce Richardson 	if (port_id != RTE_METRICS_GLOBAL &&
18099a2dd95SBruce Richardson 			(port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
18199a2dd95SBruce Richardson 		return -EINVAL;
18299a2dd95SBruce Richardson 
18399a2dd95SBruce Richardson 	if (values == NULL)
18499a2dd95SBruce Richardson 		return -EINVAL;
18599a2dd95SBruce Richardson 
18699a2dd95SBruce Richardson 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
18799a2dd95SBruce Richardson 	if (memzone == NULL)
18899a2dd95SBruce Richardson 		return -EIO;
18999a2dd95SBruce Richardson 	stats = memzone->addr;
19099a2dd95SBruce Richardson 
19199a2dd95SBruce Richardson 	rte_spinlock_lock(&stats->lock);
19299a2dd95SBruce Richardson 
19399a2dd95SBruce Richardson 	if (key >= stats->cnt_stats) {
19499a2dd95SBruce Richardson 		rte_spinlock_unlock(&stats->lock);
19599a2dd95SBruce Richardson 		return -EINVAL;
19699a2dd95SBruce Richardson 	}
19799a2dd95SBruce Richardson 	idx_metric = key;
19899a2dd95SBruce Richardson 	cnt_setsize = 1;
19999a2dd95SBruce Richardson 	while (idx_metric < stats->cnt_stats) {
20099a2dd95SBruce Richardson 		entry = &stats->metadata[idx_metric];
20199a2dd95SBruce Richardson 		if (entry->idx_next_stat == 0)
20299a2dd95SBruce Richardson 			break;
20399a2dd95SBruce Richardson 		cnt_setsize++;
20499a2dd95SBruce Richardson 		idx_metric++;
20599a2dd95SBruce Richardson 	}
20699a2dd95SBruce Richardson 	/* Check update does not cross set border */
20799a2dd95SBruce Richardson 	if (count > cnt_setsize) {
20899a2dd95SBruce Richardson 		rte_spinlock_unlock(&stats->lock);
20999a2dd95SBruce Richardson 		return -ERANGE;
21099a2dd95SBruce Richardson 	}
21199a2dd95SBruce Richardson 
21299a2dd95SBruce Richardson 	if (port_id == RTE_METRICS_GLOBAL)
21399a2dd95SBruce Richardson 		for (idx_value = 0; idx_value < count; idx_value++) {
21499a2dd95SBruce Richardson 			idx_metric = key + idx_value;
21599a2dd95SBruce Richardson 			stats->metadata[idx_metric].global_value =
21699a2dd95SBruce Richardson 				values[idx_value];
21799a2dd95SBruce Richardson 		}
21899a2dd95SBruce Richardson 	else
21999a2dd95SBruce Richardson 		for (idx_value = 0; idx_value < count; idx_value++) {
22099a2dd95SBruce Richardson 			idx_metric = key + idx_value;
22199a2dd95SBruce Richardson 			stats->metadata[idx_metric].value[port_id] =
22299a2dd95SBruce Richardson 				values[idx_value];
22399a2dd95SBruce Richardson 		}
22499a2dd95SBruce Richardson 	rte_spinlock_unlock(&stats->lock);
22599a2dd95SBruce Richardson 	return 0;
22699a2dd95SBruce Richardson }
22799a2dd95SBruce Richardson 
22899a2dd95SBruce Richardson int
rte_metrics_get_names(struct rte_metric_name * names,uint16_t capacity)22999a2dd95SBruce Richardson rte_metrics_get_names(struct rte_metric_name *names,
23099a2dd95SBruce Richardson 	uint16_t capacity)
23199a2dd95SBruce Richardson {
23299a2dd95SBruce Richardson 	struct rte_metrics_data_s *stats;
23399a2dd95SBruce Richardson 	const struct rte_memzone *memzone;
23499a2dd95SBruce Richardson 	uint16_t idx_name;
23599a2dd95SBruce Richardson 	int return_value;
23699a2dd95SBruce Richardson 
23799a2dd95SBruce Richardson 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
23899a2dd95SBruce Richardson 	if (memzone == NULL)
23999a2dd95SBruce Richardson 		return -EIO;
24099a2dd95SBruce Richardson 
24199a2dd95SBruce Richardson 	stats = memzone->addr;
24299a2dd95SBruce Richardson 	rte_spinlock_lock(&stats->lock);
24399a2dd95SBruce Richardson 	if (names != NULL) {
24499a2dd95SBruce Richardson 		if (capacity < stats->cnt_stats) {
24599a2dd95SBruce Richardson 			return_value = stats->cnt_stats;
24699a2dd95SBruce Richardson 			rte_spinlock_unlock(&stats->lock);
24799a2dd95SBruce Richardson 			return return_value;
24899a2dd95SBruce Richardson 		}
24999a2dd95SBruce Richardson 		for (idx_name = 0; idx_name < stats->cnt_stats; idx_name++)
25099a2dd95SBruce Richardson 			strlcpy(names[idx_name].name,
25199a2dd95SBruce Richardson 				stats->metadata[idx_name].name,
25299a2dd95SBruce Richardson 				RTE_METRICS_MAX_NAME_LEN);
25399a2dd95SBruce Richardson 	}
25499a2dd95SBruce Richardson 	return_value = stats->cnt_stats;
25599a2dd95SBruce Richardson 	rte_spinlock_unlock(&stats->lock);
25699a2dd95SBruce Richardson 	return return_value;
25799a2dd95SBruce Richardson }
25899a2dd95SBruce Richardson 
25999a2dd95SBruce Richardson int
rte_metrics_get_values(int port_id,struct rte_metric_value * values,uint16_t capacity)26099a2dd95SBruce Richardson rte_metrics_get_values(int port_id,
26199a2dd95SBruce Richardson 	struct rte_metric_value *values,
26299a2dd95SBruce Richardson 	uint16_t capacity)
26399a2dd95SBruce Richardson {
26499a2dd95SBruce Richardson 	struct rte_metrics_meta_s *entry;
26599a2dd95SBruce Richardson 	struct rte_metrics_data_s *stats;
26699a2dd95SBruce Richardson 	const struct rte_memzone *memzone;
26799a2dd95SBruce Richardson 	uint16_t idx_name;
26899a2dd95SBruce Richardson 	int return_value;
26999a2dd95SBruce Richardson 
27099a2dd95SBruce Richardson 	if (port_id != RTE_METRICS_GLOBAL &&
27199a2dd95SBruce Richardson 			(port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
27299a2dd95SBruce Richardson 		return -EINVAL;
27399a2dd95SBruce Richardson 
27499a2dd95SBruce Richardson 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
27599a2dd95SBruce Richardson 	if (memzone == NULL)
27699a2dd95SBruce Richardson 		return -EIO;
27799a2dd95SBruce Richardson 
27899a2dd95SBruce Richardson 	stats = memzone->addr;
27999a2dd95SBruce Richardson 	rte_spinlock_lock(&stats->lock);
28099a2dd95SBruce Richardson 
28199a2dd95SBruce Richardson 	if (values != NULL) {
28299a2dd95SBruce Richardson 		if (capacity < stats->cnt_stats) {
28399a2dd95SBruce Richardson 			return_value = stats->cnt_stats;
28499a2dd95SBruce Richardson 			rte_spinlock_unlock(&stats->lock);
28599a2dd95SBruce Richardson 			return return_value;
28699a2dd95SBruce Richardson 		}
28799a2dd95SBruce Richardson 		if (port_id == RTE_METRICS_GLOBAL)
28899a2dd95SBruce Richardson 			for (idx_name = 0;
28999a2dd95SBruce Richardson 					idx_name < stats->cnt_stats;
29099a2dd95SBruce Richardson 					idx_name++) {
29199a2dd95SBruce Richardson 				entry = &stats->metadata[idx_name];
29299a2dd95SBruce Richardson 				values[idx_name].key = idx_name;
29399a2dd95SBruce Richardson 				values[idx_name].value = entry->global_value;
29499a2dd95SBruce Richardson 			}
29599a2dd95SBruce Richardson 		else
29699a2dd95SBruce Richardson 			for (idx_name = 0;
29799a2dd95SBruce Richardson 					idx_name < stats->cnt_stats;
29899a2dd95SBruce Richardson 					idx_name++) {
29999a2dd95SBruce Richardson 				entry = &stats->metadata[idx_name];
30099a2dd95SBruce Richardson 				values[idx_name].key = idx_name;
30199a2dd95SBruce Richardson 				values[idx_name].value = entry->value[port_id];
30299a2dd95SBruce Richardson 			}
30399a2dd95SBruce Richardson 	}
30499a2dd95SBruce Richardson 	return_value = stats->cnt_stats;
30599a2dd95SBruce Richardson 	rte_spinlock_unlock(&stats->lock);
30699a2dd95SBruce Richardson 	return return_value;
30799a2dd95SBruce Richardson }
308