1 /*
2  * Copyright Runtime.io 2018. All rights reserved.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Statistics.
10  *
11  * Statistics are per-module event counters for troubleshooting, maintenance,
12  * and usage monitoring.  Statistics are organized into named "groups", with
13  * each group consisting of a set of "entries".  An entry corresponds to an
14  * individual counter.  Each entry can optionally be named if the STATS_NAMES
15  * setting is enabled.  Statistics can be retrieved with the mcumgr management
16  * subsystem.
17  *
18  * There are two, largely duplicated, statistics sections here, in order to
19  * provide the optional ability to name statistics.
20  *
21  * STATS_SECT_START/END actually declare the statistics structure definition,
22  * STATS_SECT_DECL() creates the structure declaration so you can declare
23  * these statistics as a global structure, and STATS_NAME_START/END are how
24  * you name the statistics themselves.
25  *
26  * Statistics entries can be declared as any of several integer types.
27  * However, all statistics in a given structure must be of the same size, and
28  * they are all unsigned.
29  *
30  * - STATS_SECT_ENTRY(): default statistic entry, 32-bits.
31  *
32  * - STATS_SECT_ENTRY16(): 16-bits.  Smaller statistics if you need to fit into
33  *   specific RAM or code size numbers.
34  *
35  * - STATS_SECT_ENTRY32(): 32-bits.
36  *
37  * - STATS_SECT_ENTRY64(): 64-bits.  Useful for storing chunks of data.
38  *
39  * Following the static entry declaration is the statistic names declaration.
40  * This is compiled out when the CONFIGURE_STATS_NAME setting is undefined.
41  *
42  * When CONFIG_STATS_NAMES is defined, the statistics names are stored and
43  * returned to the management APIs.  When the setting is undefined, temporary
44  * names are generated as needed with the following format:
45  *
46  *     s<stat-idx>
47  *
48  * E.g., "s0", "s1", etc.
49  */
50 
51 #ifndef ZEPHYR_INCLUDE_STATS_STATS_H_
52 #define ZEPHYR_INCLUDE_STATS_STATS_H_
53 
54 #include <stddef.h>
55 #include <zephyr/types.h>
56 
57 #ifdef __cplusplus
58 extern "C" {
59 #endif
60 
61 struct stats_name_map {
62 	uint16_t snm_off;
63 	const char *snm_name;
64 } __attribute__((packed));
65 
66 struct stats_hdr {
67 	const char *s_name;
68 	uint8_t s_size;
69 	uint16_t s_cnt;
70 	uint8_t s_pad1;
71 #ifdef CONFIG_STATS_NAMES
72 	const struct stats_name_map *s_map;
73 	int s_map_cnt;
74 #endif
75 	struct stats_hdr *s_next;
76 };
77 
78 /**
79  * @brief Declares a stat group struct.
80  *
81  * @param group__               The name to assign to the structure tag.
82  */
83 #define STATS_SECT_DECL(group__) \
84 	struct stats_ ## group__
85 
86 /**
87  * @brief Ends a stats group struct definition.
88  */
89 #define STATS_SECT_END }
90 
91 /* The following macros depend on whether CONFIG_STATS is defined.  If it is
92  * not defined, then invocations of these macros get compiled out.
93  */
94 #ifdef CONFIG_STATS
95 
96 /**
97  * @brief Begins a stats group struct definition.
98  *
99  * @param group__               The stats group struct name.
100  */
101 #define STATS_SECT_START(group__)  \
102 	STATS_SECT_DECL(group__) { \
103 		struct stats_hdr s_hdr;
104 
105 /**
106  * @brief Declares a 32-bit stat entry inside a group struct.
107  *
108  * @param var__                 The name to assign to the entry.
109  */
110 #define STATS_SECT_ENTRY(var__) uint32_t var__;
111 
112 /**
113  * @brief Declares a 16-bit stat entry inside a group struct.
114  *
115  * @param var__                 The name to assign to the entry.
116  */
117 #define STATS_SECT_ENTRY16(var__) uint16_t var__;
118 
119 /**
120  * @brief Declares a 32-bit stat entry inside a group struct.
121  *
122  * @param var__                 The name to assign to the entry.
123  */
124 #define STATS_SECT_ENTRY32(var__) uint32_t var__;
125 
126 /**
127  * @brief Declares a 64-bit stat entry inside a group struct.
128  *
129  * @param var__                 The name to assign to the entry.
130  */
131 #define STATS_SECT_ENTRY64(var__) uint64_t var__;
132 
133 /**
134  * @brief Increases a statistic entry by the specified amount.
135  *
136  * Increases a statistic entry by the specified amount.  Compiled out if
137  * CONFIG_STATS is not defined.
138  *
139  * @param group__               The group containing the entry to increase.
140  * @param var__                 The statistic entry to increase.
141  * @param n__                   The amount to increase the statistic entry by.
142  */
143 #define STATS_INCN(group__, var__, n__)	\
144 	((group__).var__ += (n__))
145 
146 /**
147  * @brief Increments a statistic entry.
148  *
149  * Increments a statistic entry by one.  Compiled out if CONFIG_STATS is not
150  * defined.
151  *
152  * @param group__               The group containing the entry to increase.
153  * @param var__                 The statistic entry to increase.
154  */
155 #define STATS_INC(group__, var__) \
156 	STATS_INCN(group__, var__, 1)
157 
158 /**
159  * @brief Set a statistic entry to the specified amount.
160  *
161  * Set a statistic entry to the specified amount.  Compiled out if
162  * CONFIG_STATS is not defined.
163  *
164  * @param group__               The group containing the entry to increase.
165  * @param var__                 The statistic entry to increase.
166  * @param n__                   The amount to set the statistic entry to.
167  */
168 #define STATS_SET(group__, var__, n__)	\
169 	((group__).var__ = (n__))
170 
171 /**
172  * @brief Sets a statistic entry to zero.
173  *
174  * Sets a statistic entry to zero.  Compiled out if CONFIG_STATS is not
175  * defined.
176  *
177  * @param group__               The group containing the entry to clear.
178  * @param var__                 The statistic entry to clear.
179  */
180 #define STATS_CLEAR(group__, var__) \
181 	((group__).var__ = 0)
182 
183 #define STATS_SIZE_16 (sizeof(uint16_t))
184 #define STATS_SIZE_32 (sizeof(uint32_t))
185 #define STATS_SIZE_64 (sizeof(uint64_t))
186 
187 #define STATS_SIZE_INIT_PARMS(group__, size__) \
188 	(size__),			       \
189 	((sizeof(group__)) - sizeof(struct stats_hdr)) / (size__)
190 
191 /**
192  * @brief Initializes and registers a statistics group.
193  *
194  * @param group__               The statistics group to initialize and
195  *                                  register.
196  * @param size__                The size of each entry in the statistics group,
197  *                                  in bytes.  Must be one of: 2 (16-bits), 4
198  *                                  (32-bits) or 8 (64-bits).
199  * @param name__                The name of the statistics group to register.
200  *                                  This name must be unique among all
201  *                                  statistics groups.
202  *
203  * @return                      0 on success; negative error code on failure.
204  */
205 #define STATS_INIT_AND_REG(group__, size__, name__)			 \
206 	stats_init_and_reg(						 \
207 		&(group__).s_hdr,					 \
208 		(size__),						 \
209 		(sizeof(group__) - sizeof(struct stats_hdr)) / (size__), \
210 		STATS_NAME_INIT_PARMS(group__),				 \
211 		(name__))
212 
213 /**
214  * @brief Initializes a statistics group.
215  *
216  * @param hdr                   The header of the statistics structure,
217  *                                  contains things like statistic section
218  *                                  name, size of statistics entries, number of
219  *                                  statistics, etc.
220  * @param size                  The size of each individual statistics
221  *                                  element, in bytes.  Must be one of: 2
222  *                                  (16-bits), 4 (32-bits) or 8 (64-bits).
223  * @param cnt                   The number of elements in the stats group.
224  * @param map                   The mapping of stat offset to name.
225  * @param map_cnt               The number of items in the statistics map
226  *
227  * @param group__               The group containing the entry to clear.
228  * @param var__                 The statistic entry to clear.
229  */
230 void stats_init(struct stats_hdr *shdr, uint8_t size, uint16_t cnt,
231 		const struct stats_name_map *map, uint16_t map_cnt);
232 
233 /**
234  * @brief Registers a statistics group to be managed.
235  *
236  * @param name                  The name of the statistics group to register.
237  *                                 This name must be unique among all
238  *                                 statistics groups.  If the name is a
239  *                                 duplicate, this function will return
240  *                                 -EALREADY.
241  * @param shdr                  The statistics group to register.
242  *
243  * @return 0 on success, non-zero error code on failure.
244  */
245 int stats_register(const char *name, struct stats_hdr *shdr);
246 
247 /**
248  * @brief Initializes and registers a statistics group.
249  *
250  * Initializes and registers a statistics group.  Note: it is recommended to
251  * use the STATS_INIT_AND_REG macro instead of this function.
252  *
253  * @param hdr                   The header of the statistics group to
254  *                                  initialize and register.
255  * @param size                  The size of each individual statistics
256  *                                  element, in bytes.  Must be one of: 2
257  *                                  (16-bits), 4 (32-bits) or 8 (64-bits).
258  * @param cnt                   The number of elements in the stats group.
259  * @param map                   The mapping of stat offset to name.
260  * @param map_cnt               The number of items in the statistics map
261  * @param name                  The name of the statistics group to register.
262  *                                  This name must be unique among all
263  *                                  statistics groups.  If the name is a
264  *                                  duplicate, this function will return
265  *                                  -EALREADY.
266  *
267  * @return                      0 on success; negative error code on failure.
268  *
269  * @see STATS_INIT_AND_REG
270  */
271 int stats_init_and_reg(struct stats_hdr *hdr, uint8_t size, uint16_t cnt,
272 		       const struct stats_name_map *map, uint16_t map_cnt,
273 		       const char *name);
274 
275 /**
276  * Zeroes the specified statistics group.
277  *
278  * @param shdr                  The statistics group to clear.
279  */
280 void stats_reset(struct stats_hdr *shdr);
281 
282 /** @typedef stats_walk_fn
283  * @brief Function that gets applied to every stat entry during a walk.
284  *
285  * @param hdr                   The group containing the stat entry being
286  *                                  walked.
287  * @param arg                   Optional argument.
288  * @param name                  The name of the statistic entry to process
289  * @param off                   The offset of the entry, from `hdr`.
290  *
291  * @return                      0 if the walk should proceed;
292  *                              nonzero to abort the walk.
293  */
294 typedef int stats_walk_fn(struct stats_hdr *hdr, void *arg,
295 			  const char *name, uint16_t off);
296 
297 /**
298  * @brief Applies a function to every stat entry in a group.
299  *
300  * @param hdr                   The stats group to operate on.
301  * @param walk_cb               The function to apply to each stat entry.
302  * @param arg                   Optional argument to pass to the callback.
303  *
304  * @return                      0 if the walk completed;
305  *                              nonzero if the walk was aborted.
306  */
307 int stats_walk(struct stats_hdr *hdr, stats_walk_fn *walk_cb, void *arg);
308 
309 /** @typedef stats_group_walk_fn
310  * @brief Function that gets applied to every registered stats group.
311  *
312  * @param hdr                   The stats group being walked.
313  * @param arg                   Optional argument.
314  *
315  * @return                      0 if the walk should proceed;
316  *                              nonzero to abort the walk.
317  */
318 typedef int stats_group_walk_fn(struct stats_hdr *hdr, void *arg);
319 
320 /**
321  * @brief Applies a function every registered statistics group.
322  *
323  * @param walk_cb               The function to apply to each stat group.
324  * @param arg                   Optional argument to pass to the callback.
325  *
326  * @return                      0 if the walk completed;
327  *                              nonzero if the walk was aborted.
328  */
329 int stats_group_walk(stats_group_walk_fn *walk_cb, void *arg);
330 
331 /**
332  * @brief Retrieves the next registered statistics group.
333  *
334  * @param cur                   The group whose successor is being retrieved, or
335  *                                  NULL to retrieve the first group.
336  *
337  * @return                      Pointer to the retrieved group on success;
338  *                              NULL if no more groups remain.
339  */
340 struct stats_hdr *stats_group_get_next(const struct stats_hdr *cur);
341 
342 /**
343  * @brief Retrieves the statistics group with the specified name.
344  *
345  * @param name                  The name of the statistics group to look up.
346  *
347  * @return                      Pointer to the retrieved group on success;
348  *                              NULL if there is no matching registered group.
349  */
350 struct stats_hdr *stats_group_find(const char *name);
351 
352 #else /* CONFIG_STATS */
353 
354 #define STATS_SECT_START(group__) \
355 	STATS_SECT_DECL(group__) {
356 
357 #define STATS_SECT_ENTRY(var__)
358 #define STATS_SECT_ENTRY16(var__)
359 #define STATS_SECT_ENTRY32(var__)
360 #define STATS_SECT_ENTRY64(var__)
361 #define STATS_RESET(var__)
362 #define STATS_SIZE_INIT_PARMS(group__, size__)
363 #define STATS_INCN(group__, var__, n__)
364 #define STATS_INC(group__, var__)
365 #define STATS_SET(group__, var__)
366 #define STATS_CLEAR(group__, var__)
367 #define STATS_INIT_AND_REG(group__, size__, name__) (0)
368 
369 #endif /* !CONFIG_STATS */
370 
371 #ifdef CONFIG_STATS_NAMES
372 
373 #define STATS_NAME_MAP_NAME(sectname__) stats_map_ ## sectname__
374 
375 #define STATS_NAME_START(sectname__) \
376 	static const struct stats_name_map STATS_NAME_MAP_NAME(sectname__)[] = {
377 
378 #define STATS_NAME(sectname__, entry__)	\
379 	{ offsetof(STATS_SECT_DECL(sectname__), entry__), #entry__ },
380 
381 #define STATS_NAME_END(sectname__) }
382 
383 #define STATS_NAME_INIT_PARMS(name__)	    \
384 	&(STATS_NAME_MAP_NAME(name__)[0]), \
385 	(sizeof(STATS_NAME_MAP_NAME(name__)) / sizeof(struct stats_name_map))
386 
387 #else /* CONFIG_STATS_NAMES */
388 
389 #define STATS_NAME_START(name__)
390 #define STATS_NAME(name__, entry__)
391 #define STATS_NAME_END(name__)
392 #define STATS_NAME_INIT_PARMS(name__) NULL, 0
393 
394 #endif /* CONFIG_STATS_NAMES */
395 
396 #ifdef __cplusplus
397 }
398 #endif
399 
400 #endif /* ZEPHYR_INCLUDE_STATS_STATS_H_ */
401