telemetry: move some functions to metrics library
[dpdk.git] / lib / librte_metrics / rte_metrics.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4
5 #include <string.h>
6 #include <sys/queue.h>
7
8 #include <rte_common.h>
9 #include <rte_string_fns.h>
10 #include <rte_malloc.h>
11 #include <rte_metrics.h>
12 #include <rte_lcore.h>
13 #include <rte_memzone.h>
14 #include <rte_spinlock.h>
15
16 #define RTE_METRICS_MEMZONE_NAME "RTE_METRICS"
17
18 /**
19  * Internal stats metadata and value entry.
20  *
21  * @internal
22  */
23 struct rte_metrics_meta_s {
24         /** Name of metric */
25         char name[RTE_METRICS_MAX_NAME_LEN];
26         /** Current value for metric */
27         uint64_t value[RTE_MAX_ETHPORTS];
28         /** Used for global metrics */
29         uint64_t global_value;
30         /** Index of next root element (zero for none) */
31         uint16_t idx_next_set;
32         /** Index of next metric in set (zero for none) */
33         uint16_t idx_next_stat;
34 };
35
36 /**
37  * Internal stats info structure.
38  *
39  * @internal
40  * Offsets into metadata are used instead of pointers because ASLR
41  * means that having the same physical addresses in different
42  * processes is not guaranteed.
43  */
44 struct rte_metrics_data_s {
45         /**   Index of last metadata entry with valid data.
46          * This value is not valid if cnt_stats is zero.
47          */
48         uint16_t idx_last_set;
49         /**   Number of metrics. */
50         uint16_t cnt_stats;
51         /** Metric data memory block. */
52         struct rte_metrics_meta_s metadata[RTE_METRICS_MAX_METRICS];
53         /** Metric data access lock */
54         rte_spinlock_t lock;
55 };
56
57 void
58 rte_metrics_init(int socket_id)
59 {
60         struct rte_metrics_data_s *stats;
61         const struct rte_memzone *memzone;
62
63         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
64                 return;
65
66         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
67         if (memzone != NULL)
68                 return;
69         memzone = rte_memzone_reserve(RTE_METRICS_MEMZONE_NAME,
70                 sizeof(struct rte_metrics_data_s), socket_id, 0);
71         if (memzone == NULL)
72                 rte_exit(EXIT_FAILURE, "Unable to allocate stats memzone\n");
73         stats = memzone->addr;
74         memset(stats, 0, sizeof(struct rte_metrics_data_s));
75         rte_spinlock_init(&stats->lock);
76 }
77
78 int
79 rte_metrics_deinit(void)
80 {
81         struct rte_metrics_data_s *stats;
82         const struct rte_memzone *memzone;
83
84         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
85                 return -EINVAL;
86
87         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
88         if (memzone == NULL)
89                 return -EIO;
90
91         stats = memzone->addr;
92         memset(stats, 0, sizeof(struct rte_metrics_data_s));
93
94         return rte_memzone_free(memzone);
95
96 }
97
98 int
99 rte_metrics_reg_name(const char *name)
100 {
101         const char * const list_names[] = {name};
102
103         return rte_metrics_reg_names(list_names, 1);
104 }
105
106 int
107 rte_metrics_reg_names(const char * const *names, uint16_t cnt_names)
108 {
109         struct rte_metrics_meta_s *entry = NULL;
110         struct rte_metrics_data_s *stats;
111         const struct rte_memzone *memzone;
112         uint16_t idx_name;
113         uint16_t idx_base;
114
115         /* Some sanity checks */
116         if (cnt_names < 1 || names == NULL)
117                 return -EINVAL;
118         for (idx_name = 0; idx_name < cnt_names; idx_name++)
119                 if (names[idx_name] == NULL)
120                         return -EINVAL;
121
122         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
123         if (memzone == NULL)
124                 return -EIO;
125         stats = memzone->addr;
126
127         if (stats->cnt_stats + cnt_names >= RTE_METRICS_MAX_METRICS)
128                 return -ENOMEM;
129
130         rte_spinlock_lock(&stats->lock);
131
132         /* Overwritten later if this is actually first set.. */
133         stats->metadata[stats->idx_last_set].idx_next_set = stats->cnt_stats;
134
135         stats->idx_last_set = idx_base = stats->cnt_stats;
136
137         for (idx_name = 0; idx_name < cnt_names; idx_name++) {
138                 entry = &stats->metadata[idx_name + stats->cnt_stats];
139                 strlcpy(entry->name, names[idx_name], RTE_METRICS_MAX_NAME_LEN);
140                 memset(entry->value, 0, sizeof(entry->value));
141                 entry->idx_next_stat = idx_name + stats->cnt_stats + 1;
142         }
143         entry->idx_next_stat = 0;
144         entry->idx_next_set = 0;
145         stats->cnt_stats += cnt_names;
146
147         rte_spinlock_unlock(&stats->lock);
148
149         return idx_base;
150 }
151
152 int
153 rte_metrics_update_value(int port_id, uint16_t key, const uint64_t value)
154 {
155         return rte_metrics_update_values(port_id, key, &value, 1);
156 }
157
158 int
159 rte_metrics_update_values(int port_id,
160         uint16_t key,
161         const uint64_t *values,
162         uint32_t count)
163 {
164         struct rte_metrics_meta_s *entry;
165         struct rte_metrics_data_s *stats;
166         const struct rte_memzone *memzone;
167         uint16_t idx_metric;
168         uint16_t idx_value;
169         uint16_t cnt_setsize;
170
171         if (port_id != RTE_METRICS_GLOBAL &&
172                         (port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
173                 return -EINVAL;
174
175         if (values == NULL)
176                 return -EINVAL;
177
178         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
179         if (memzone == NULL)
180                 return -EIO;
181         stats = memzone->addr;
182
183         rte_spinlock_lock(&stats->lock);
184
185         if (key >= stats->cnt_stats) {
186                 rte_spinlock_unlock(&stats->lock);
187                 return -EINVAL;
188         }
189         idx_metric = key;
190         cnt_setsize = 1;
191         while (idx_metric < stats->cnt_stats) {
192                 entry = &stats->metadata[idx_metric];
193                 if (entry->idx_next_stat == 0)
194                         break;
195                 cnt_setsize++;
196                 idx_metric++;
197         }
198         /* Check update does not cross set border */
199         if (count > cnt_setsize) {
200                 rte_spinlock_unlock(&stats->lock);
201                 return -ERANGE;
202         }
203
204         if (port_id == RTE_METRICS_GLOBAL)
205                 for (idx_value = 0; idx_value < count; idx_value++) {
206                         idx_metric = key + idx_value;
207                         stats->metadata[idx_metric].global_value =
208                                 values[idx_value];
209                 }
210         else
211                 for (idx_value = 0; idx_value < count; idx_value++) {
212                         idx_metric = key + idx_value;
213                         stats->metadata[idx_metric].value[port_id] =
214                                 values[idx_value];
215                 }
216         rte_spinlock_unlock(&stats->lock);
217         return 0;
218 }
219
220 int
221 rte_metrics_get_names(struct rte_metric_name *names,
222         uint16_t capacity)
223 {
224         struct rte_metrics_data_s *stats;
225         const struct rte_memzone *memzone;
226         uint16_t idx_name;
227         int return_value;
228
229         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
230         if (memzone == NULL)
231                 return -EIO;
232
233         stats = memzone->addr;
234         rte_spinlock_lock(&stats->lock);
235         if (names != NULL) {
236                 if (capacity < stats->cnt_stats) {
237                         return_value = stats->cnt_stats;
238                         rte_spinlock_unlock(&stats->lock);
239                         return return_value;
240                 }
241                 for (idx_name = 0; idx_name < stats->cnt_stats; idx_name++)
242                         strlcpy(names[idx_name].name,
243                                 stats->metadata[idx_name].name,
244                                 RTE_METRICS_MAX_NAME_LEN);
245         }
246         return_value = stats->cnt_stats;
247         rte_spinlock_unlock(&stats->lock);
248         return return_value;
249 }
250
251 int
252 rte_metrics_get_values(int port_id,
253         struct rte_metric_value *values,
254         uint16_t capacity)
255 {
256         struct rte_metrics_meta_s *entry;
257         struct rte_metrics_data_s *stats;
258         const struct rte_memzone *memzone;
259         uint16_t idx_name;
260         int return_value;
261
262         if (port_id != RTE_METRICS_GLOBAL &&
263                         (port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
264                 return -EINVAL;
265
266         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
267         if (memzone == NULL)
268                 return -EIO;
269
270         stats = memzone->addr;
271         rte_spinlock_lock(&stats->lock);
272
273         if (values != NULL) {
274                 if (capacity < stats->cnt_stats) {
275                         return_value = stats->cnt_stats;
276                         rte_spinlock_unlock(&stats->lock);
277                         return return_value;
278                 }
279                 if (port_id == RTE_METRICS_GLOBAL)
280                         for (idx_name = 0;
281                                         idx_name < stats->cnt_stats;
282                                         idx_name++) {
283                                 entry = &stats->metadata[idx_name];
284                                 values[idx_name].key = idx_name;
285                                 values[idx_name].value = entry->global_value;
286                         }
287                 else
288                         for (idx_name = 0;
289                                         idx_name < stats->cnt_stats;
290                                         idx_name++) {
291                                 entry = &stats->metadata[idx_name];
292                                 values[idx_name].key = idx_name;
293                                 values[idx_name].value = entry->value[port_id];
294                         }
295         }
296         return_value = stats->cnt_stats;
297         rte_spinlock_unlock(&stats->lock);
298         return return_value;
299 }