blob: e4793b5c7363077cd1b24d14385e967f3c2d6fc5 [file] [log] [blame]
/*
* Copyright Runtime.io 2018. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Statistics.
*
* Statistics are per-module event counters for troubleshooting, maintenance,
* and usage monitoring. Statistics are organized into named "groups", with
* each group consisting of a set of "entries". An entry corresponds to an
* individual counter. Each entry can optionally be named if the STATS_NAMES
* setting is enabled. Statistics can be retrieved with the mcumgr management
* subsystem.
*
* There are two, largely duplicated, statistics sections here, in order to
* provide the optional ability to name statistics.
*
* STATS_SECT_START/END actually declare the statistics structure definition,
* STATS_SECT_DECL() creates the structure declaration so you can declare
* these statistics as a global structure, and STATS_NAME_START/END are how
* you name the statistics themselves.
*
* Statistics entries can be declared as any of several integer types.
* However, all statistics in a given structure must be of the same size, and
* they are all unsigned.
*
* - STATS_SECT_ENTRY(): default statistic entry, 32-bits.
*
* - STATS_SECT_ENTRY16(): 16-bits. Smaller statistics if you need to fit into
* specific RAM or code size numbers.
*
* - STATS_SECT_ENTRY32(): 32-bits.
*
* - STATS_SECT_ENTRY64(): 64-bits. Useful for storing chunks of data.
*
* Following the static entry declaration is the statistic names declaration.
* This is compiled out when the CONFIGURE_STATS_NAME setting is undefined.
*
* When CONFIG_STATS_NAMES is defined, the statistics names are stored and
* returned to the management APIs. When the setting is undefined, temporary
* names are generated as needed with the following format:
*
* s<stat-idx>
*
* E.g., "s0", "s1", etc.
*/
#ifndef ZEPHYR_INCLUDE_STATS_STATS_H_
#define ZEPHYR_INCLUDE_STATS_STATS_H_
#include <stddef.h>
#include <zephyr/types.h>
#ifdef __cplusplus
extern "C" {
#endif
struct stats_name_map {
uint16_t snm_off;
const char *snm_name;
} __attribute__((packed));
struct stats_hdr {
const char *s_name;
uint8_t s_size;
uint16_t s_cnt;
uint8_t s_pad1;
#ifdef CONFIG_STATS_NAMES
const struct stats_name_map *s_map;
int s_map_cnt;
#endif
struct stats_hdr *s_next;
};
/**
* @brief Declares a stat group struct.
*
* @param group__ The name to assign to the structure tag.
*/
#define STATS_SECT_DECL(group__) \
struct stats_ ## group__
/**
* @brief Ends a stats group struct definition.
*/
#define STATS_SECT_END }
/* The following macros depend on whether CONFIG_STATS is defined. If it is
* not defined, then invocations of these macros get compiled out.
*/
#ifdef CONFIG_STATS
/**
* @brief Begins a stats group struct definition.
*
* @param group__ The stats group struct name.
*/
#define STATS_SECT_START(group__) \
STATS_SECT_DECL(group__) { \
struct stats_hdr s_hdr;
/**
* @brief Declares a 32-bit stat entry inside a group struct.
*
* @param var__ The name to assign to the entry.
*/
#define STATS_SECT_ENTRY(var__) uint32_t var__;
/**
* @brief Declares a 16-bit stat entry inside a group struct.
*
* @param var__ The name to assign to the entry.
*/
#define STATS_SECT_ENTRY16(var__) uint16_t var__;
/**
* @brief Declares a 32-bit stat entry inside a group struct.
*
* @param var__ The name to assign to the entry.
*/
#define STATS_SECT_ENTRY32(var__) uint32_t var__;
/**
* @brief Declares a 64-bit stat entry inside a group struct.
*
* @param var__ The name to assign to the entry.
*/
#define STATS_SECT_ENTRY64(var__) uint64_t var__;
/**
* @brief Increases a statistic entry by the specified amount.
*
* Increases a statistic entry by the specified amount. Compiled out if
* CONFIG_STATS is not defined.
*
* @param group__ The group containing the entry to increase.
* @param var__ The statistic entry to increase.
* @param n__ The amount to increase the statistic entry by.
*/
#define STATS_INCN(group__, var__, n__) \
((group__).var__ += (n__))
/**
* @brief Increments a statistic entry.
*
* Increments a statistic entry by one. Compiled out if CONFIG_STATS is not
* defined.
*
* @param group__ The group containing the entry to increase.
* @param var__ The statistic entry to increase.
*/
#define STATS_INC(group__, var__) \
STATS_INCN(group__, var__, 1)
/**
* @brief Set a statistic entry to the specified amount.
*
* Set a statistic entry to the specified amount. Compiled out if
* CONFIG_STATS is not defined.
*
* @param group__ The group containing the entry to increase.
* @param var__ The statistic entry to increase.
* @param n__ The amount to set the statistic entry to.
*/
#define STATS_SET(group__, var__, n__) \
((group__).var__ = (n__))
/**
* @brief Sets a statistic entry to zero.
*
* Sets a statistic entry to zero. Compiled out if CONFIG_STATS is not
* defined.
*
* @param group__ The group containing the entry to clear.
* @param var__ The statistic entry to clear.
*/
#define STATS_CLEAR(group__, var__) \
((group__).var__ = 0)
#define STATS_SIZE_16 (sizeof(uint16_t))
#define STATS_SIZE_32 (sizeof(uint32_t))
#define STATS_SIZE_64 (sizeof(uint64_t))
#define STATS_SIZE_INIT_PARMS(group__, size__) \
(size__), \
((sizeof(group__)) - sizeof(struct stats_hdr)) / (size__)
/**
* @brief Initializes and registers a statistics group.
*
* @param group__ The statistics group to initialize and
* register.
* @param size__ The size of each entry in the statistics group,
* in bytes. Must be one of: 2 (16-bits), 4
* (32-bits) or 8 (64-bits).
* @param name__ The name of the statistics group to register.
* This name must be unique among all
* statistics groups.
*
* @return 0 on success; negative error code on failure.
*/
#define STATS_INIT_AND_REG(group__, size__, name__) \
stats_init_and_reg( \
&(group__).s_hdr, \
(size__), \
(sizeof(group__) - sizeof(struct stats_hdr)) / (size__), \
STATS_NAME_INIT_PARMS(group__), \
(name__))
/**
* @brief Initializes a statistics group.
*
* @param hdr The header of the statistics structure,
* contains things like statistic section
* name, size of statistics entries, number of
* statistics, etc.
* @param size The size of each individual statistics
* element, in bytes. Must be one of: 2
* (16-bits), 4 (32-bits) or 8 (64-bits).
* @param cnt The number of elements in the stats group.
* @param map The mapping of stat offset to name.
* @param map_cnt The number of items in the statistics map
*
* @param group__ The group containing the entry to clear.
* @param var__ The statistic entry to clear.
*/
void stats_init(struct stats_hdr *shdr, uint8_t size, uint16_t cnt,
const struct stats_name_map *map, uint16_t map_cnt);
/**
* @brief Registers a statistics group to be managed.
*
* @param name The name of the statistics group to register.
* This name must be unique among all
* statistics groups. If the name is a
* duplicate, this function will return
* -EALREADY.
* @param shdr The statistics group to register.
*
* @return 0 on success, non-zero error code on failure.
*/
int stats_register(const char *name, struct stats_hdr *shdr);
/**
* @brief Initializes and registers a statistics group.
*
* Initializes and registers a statistics group. Note: it is recommended to
* use the STATS_INIT_AND_REG macro instead of this function.
*
* @param hdr The header of the statistics group to
* initialize and register.
* @param size The size of each individual statistics
* element, in bytes. Must be one of: 2
* (16-bits), 4 (32-bits) or 8 (64-bits).
* @param cnt The number of elements in the stats group.
* @param map The mapping of stat offset to name.
* @param map_cnt The number of items in the statistics map
* @param name The name of the statistics group to register.
* This name must be unique among all
* statistics groups. If the name is a
* duplicate, this function will return
* -EALREADY.
*
* @return 0 on success; negative error code on failure.
*
* @see STATS_INIT_AND_REG
*/
int stats_init_and_reg(struct stats_hdr *hdr, uint8_t size, uint16_t cnt,
const struct stats_name_map *map, uint16_t map_cnt,
const char *name);
/**
* Zeroes the specified statistics group.
*
* @param shdr The statistics group to clear.
*/
void stats_reset(struct stats_hdr *shdr);
/** @typedef stats_walk_fn
* @brief Function that gets applied to every stat entry during a walk.
*
* @param hdr The group containing the stat entry being
* walked.
* @param arg Optional argument.
* @param name The name of the statistic entry to process
* @param off The offset of the entry, from `hdr`.
*
* @return 0 if the walk should proceed;
* nonzero to abort the walk.
*/
typedef int stats_walk_fn(struct stats_hdr *hdr, void *arg,
const char *name, uint16_t off);
/**
* @brief Applies a function to every stat entry in a group.
*
* @param hdr The stats group to operate on.
* @param walk_cb The function to apply to each stat entry.
* @param arg Optional argument to pass to the callback.
*
* @return 0 if the walk completed;
* nonzero if the walk was aborted.
*/
int stats_walk(struct stats_hdr *hdr, stats_walk_fn *walk_cb, void *arg);
/** @typedef stats_group_walk_fn
* @brief Function that gets applied to every registered stats group.
*
* @param hdr The stats group being walked.
* @param arg Optional argument.
*
* @return 0 if the walk should proceed;
* nonzero to abort the walk.
*/
typedef int stats_group_walk_fn(struct stats_hdr *hdr, void *arg);
/**
* @brief Applies a function every registered statistics group.
*
* @param walk_cb The function to apply to each stat group.
* @param arg Optional argument to pass to the callback.
*
* @return 0 if the walk completed;
* nonzero if the walk was aborted.
*/
int stats_group_walk(stats_group_walk_fn *walk_cb, void *arg);
/**
* @brief Retrieves the next registered statistics group.
*
* @param cur The group whose successor is being retrieved, or
* NULL to retrieve the first group.
*
* @return Pointer to the retrieved group on success;
* NULL if no more groups remain.
*/
struct stats_hdr *stats_group_get_next(const struct stats_hdr *cur);
/**
* @brief Retrieves the statistics group with the specified name.
*
* @param name The name of the statistics group to look up.
*
* @return Pointer to the retrieved group on success;
* NULL if there is no matching registered group.
*/
struct stats_hdr *stats_group_find(const char *name);
#else /* CONFIG_STATS */
#define STATS_SECT_START(group__) \
STATS_SECT_DECL(group__) {
#define STATS_SECT_ENTRY(var__)
#define STATS_SECT_ENTRY16(var__)
#define STATS_SECT_ENTRY32(var__)
#define STATS_SECT_ENTRY64(var__)
#define STATS_RESET(var__)
#define STATS_SIZE_INIT_PARMS(group__, size__)
#define STATS_INCN(group__, var__, n__)
#define STATS_INC(group__, var__)
#define STATS_SET(group__, var__)
#define STATS_CLEAR(group__, var__)
#define STATS_INIT_AND_REG(group__, size__, name__) (0)
#endif /* !CONFIG_STATS */
#ifdef CONFIG_STATS_NAMES
#define STATS_NAME_MAP_NAME(sectname__) stats_map_ ## sectname__
#define STATS_NAME_START(sectname__) \
static const struct stats_name_map STATS_NAME_MAP_NAME(sectname__)[] = {
#define STATS_NAME(sectname__, entry__) \
{ offsetof(STATS_SECT_DECL(sectname__), entry__), #entry__ },
#define STATS_NAME_END(sectname__) }
#define STATS_NAME_INIT_PARMS(name__) \
&(STATS_NAME_MAP_NAME(name__)[0]), \
(sizeof(STATS_NAME_MAP_NAME(name__)) / sizeof(struct stats_name_map))
#else /* CONFIG_STATS_NAMES */
#define STATS_NAME_START(name__)
#define STATS_NAME(name__, entry__)
#define STATS_NAME_END(name__)
#define STATS_NAME_INIT_PARMS(name__) NULL, 0
#endif /* CONFIG_STATS_NAMES */
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_STATS_STATS_H_ */