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