kernel: Add initial k_obj_core_stats infrastructure

Adds the infrastructure to integrate statistics into
the object core.

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
This commit is contained in:
Peter Mitsis 2023-06-09 14:23:25 -04:00 committed by Johan Hedberg
commit 1d5d674e0d
3 changed files with 417 additions and 0 deletions

View file

@ -88,18 +88,42 @@ struct k_obj_core;
*/
extern sys_slist_t z_obj_type_list;
/** Object core statistics descriptor */
struct k_obj_core_stats_desc {
size_t raw_size; /**< Internal representation stats buffer size */
size_t query_size; /**< Stats buffer size used for reporting */
/** Function pointer to retrieve internal representation of stats */
int (*raw)(struct k_obj_core *obj_core, void *stats);
/** Function pointer to retrieve reported statistics */
int (*query)(struct k_obj_core *obj_core, void *stats);
/** Function pointer to reset object's statistics */
int (*reset)(struct k_obj_core *obj_core);
/** Function pointer to disable object's statistics gathering */
int (*disable)(struct k_obj_core *obj_core);
/** Function pointer to enable object's statistics gathering */
int (*enable)(struct k_obj_core *obj_core);
};
/** Object type structure */
struct k_obj_type {
sys_snode_t node; /**< Node within list of object types */
sys_slist_t list; /**< List of objects of this object type */
uint32_t id; /**< Unique type ID */
size_t obj_core_offset; /**< Offset to obj_core field */
#ifdef CONFIG_OBJ_CORE_STATS
/** Pointer to object core statistics descriptor */
struct k_obj_core_stats_desc *stats_desc;
#endif
};
/** Object core structure */
struct k_obj_core {
sys_snode_t node; /**< Object node within object type's list */
struct k_obj_type *type; /**< Object type to which object belongs */
#ifdef CONFIG_OBJ_CORE_STATS
void *stats; /**< Pointer to kernel object's stats */
#endif
};
/**
@ -219,5 +243,152 @@ void k_obj_core_init_and_link(struct k_obj_core *obj_core,
*/
void k_obj_core_unlink(struct k_obj_core *obj_core);
/** @} */
/**
* @defgroup obj_core_stats_apis Object Core Statistics APIs
* @ingroup kernel_apis
* @{
*/
#ifdef CONFIG_OBJ_CORE_STATS
/**
* @brief Initialize the object type's stats descriptor
*
* This routine initializes the object type's stats descriptor.
*
* @param type Pointer to the object type
* @param stats_desc Pointer to the object core statistics descriptor
*/
static inline void k_obj_type_stats_init(struct k_obj_type *type,
struct k_obj_core_stats_desc *stats_desc)
{
type->stats_desc = stats_desc;
}
/**
* @brief Initialize the object core for statistics
*
* This routine initializes the object core to operate within the object core
* statistics framework.
*
* @param obj_core Pointer to the object core
* @param stats Pointer to the object's raw statistics
*/
static inline void k_obj_core_stats_init(struct k_obj_core *obj_core,
void *stats)
{
obj_core->stats = stats;
}
#endif
/**
* @brief Register kernel object for gathering statistics
*
* Before a kernel object can gather statistics, it must be registered to do
* so. Registering will also automatically enable the kernel object to gather
* its statistics.
*
* @param obj_core Pointer to kernel object core
* @param stats Pointer to raw kernel statistics
* @param stats_len Size of raw kernel statistics buffer
*
* @retval 0 on success
* @retval -errno on failure
*/
int k_obj_core_stats_register(struct k_obj_core *obj_core, void *stats,
size_t stats_len);
/**
* @brief Deregister kernel object from gathering statistics
*
* Deregistering a kernel object core from gathering statistics prevents it
* from gathering any more statistics. It is expected to be invoked at the end
* of a kernel object's life cycle.
*
* @param obj_core Pointer to kernel object core
*
* @retval 0 on success
* @retval -errno on failure
*/
int k_obj_core_stats_deregister(struct k_obj_core *obj_core);
/**
* @brief Retrieve the raw statistics associated with the kernel object
*
* This function copies the raw statistics associated with the kernel object
* core specified by @a obj_core into the buffer @a stats. Note that the size
* of the buffer (@a stats_len) must match the size specified by the kernel
* object type's statistics descriptor.
*
* @param obj_core Pointer to kernel object core
* @param stats Pointer to memory buffer into which to copy raw stats
* @param stats_len Length of the memory buffer
*
* @retval 0 on success
* @retval -errno on failure
*/
int k_obj_core_stats_raw(struct k_obj_core *obj_core, void *stats,
size_t stats_len);
/**
* @brief Retrieve the statistics associated with the kernel object
*
* This function copies the statistics associated with the kernel object core
* specified by @a obj_core into the buffer @a stats. Unlike the raw statistics
* this may report calculated values such as averages. Note that the size of
* the buffer (@a stats_len) must match the size specified by the kernel object
* type's statistics descriptor.
*
* @param obj_core Pointer to kernel object core
* @param stats Pointer to memory buffer into which to copy the queried stats
* @param stats_len Length of the memory buffer
*
* @retval 0 on success
* @retval -errno on failure
*/
int k_obj_core_stats_query(struct k_obj_core *obj_core, void *stats,
size_t stats_len);
/**
* @brief Reset the stats associated with the kernel object
*
* This function resets the statistics associated with the kernel object core
* specified by @a obj_core.
*
* @param obj_core Pointer to kernel object core
*
* @retval 0 on success
* @retval -errno on failure
*/
int k_obj_core_stats_reset(struct k_obj_core *obj_core);
/**
* @brief Stop gathering the stats associated with the kernel object
*
* This function temporarily stops the gathering of statistics associated with
* the kernel object core specified by @a obj_core. The gathering of statistics
* can be resumed by invoking :c:func :`k_obj_core_stats_enable`.
*
* @param obj_core Pointer to kernel object core
*
* @retval 0 on success
* @retval -errno on failure
*/
int k_obj_core_stats_disable(struct k_obj_core *obj_core);
/**
* @brief Reset the stats associated with the kernel object
*
* This function resumes the gathering of statistics associated with the kernel
* object core specified by @a obj_core.
*
* @param obj_core Pointer to kernel object core
*
* @retval 0 on success
* @retval -errno on failure
*/
int k_obj_core_stats_enable(struct k_obj_core *obj_core);
/** @} */
#endif /* __KERNEL_OBJ_CORE_H__ */

View file

@ -612,6 +612,16 @@ config OBJ_CORE_SYSTEM
structures, this option is hidden by default and only available to
advanced users.
menuconfig OBJ_CORE_STATS
bool "Object core statistics"
default n
help
This option integrates statistics gathering into the object core
framework.
if OBJ_CORE_STATS
endif # OBJ_CORE_STATS
endif # OBJ_CORE
menu "Work Queue Options"

View file

@ -26,6 +26,9 @@ void k_obj_core_init(struct k_obj_core *obj_core, struct k_obj_type *type)
{
obj_core->node.next = NULL;
obj_core->type = type;
#ifdef CONFIG_OBJ_CORE_STATS
obj_core->stats = NULL;
#endif
}
void k_obj_core_link(struct k_obj_core *obj_core)
@ -117,3 +120,236 @@ int k_obj_type_walk_unlocked(struct k_obj_type *type,
return status;
}
#ifdef CONFIG_OBJ_CORE_STATS
int k_obj_core_stats_register(struct k_obj_core *obj_core, void *stats,
size_t stats_len)
{
__ASSERT((obj_core != NULL) && (stats != NULL), "NULL parameter");
k_spinlock_key_t key = k_spin_lock(&lock);
__ASSERT(obj_core->type != NULL, "Object core not initialized");
if (obj_core->type->stats_desc == NULL) {
/* Object type not configured for statistics. */
k_spin_unlock(&lock, key);
return -ENOTSUP;
}
if (obj_core->type->stats_desc->raw_size != stats_len) {
/* Buffer size mismatch */
k_spin_unlock(&lock, key);
return -EINVAL;
}
obj_core->stats = stats;
k_spin_unlock(&lock, key);
return 0;
}
int k_obj_core_stats_deregister(struct k_obj_core *obj_core)
{
__ASSERT((obj_core != NULL), "NULL parameter");
k_spinlock_key_t key = k_spin_lock(&lock);
__ASSERT(obj_core->type != NULL, "Object core not initialized");
if (obj_core->type->stats_desc == NULL) {
/* Object type not configured for statistics. */
k_spin_unlock(&lock, key);
return -ENOTSUP;
}
obj_core->stats = NULL;
k_spin_unlock(&lock, key);
return 0;
}
int k_obj_core_stats_raw(struct k_obj_core *obj_core, void *stats,
size_t stats_len)
{
int rv;
struct k_obj_core_stats_desc *desc;
__ASSERT((obj_core != NULL) && (stats != NULL), "NULL parameter");
k_spinlock_key_t key = k_spin_lock(&lock);
__ASSERT(obj_core->type != NULL, "Object core not initialized");
desc = obj_core->type->stats_desc;
if ((desc == NULL) || (desc->raw == NULL)) {
/* The object type is not configured for this operation */
k_spin_unlock(&lock, key);
return -ENOTSUP;
}
if ((desc->raw_size != stats_len) || (obj_core->stats == NULL)) {
/*
* Either the size of the stats buffer is wrong or
* the kernel object was not registered for statistics.
*/
k_spin_unlock(&lock, key);
return -EINVAL;
}
rv = desc->raw(obj_core, stats);
k_spin_unlock(&lock, key);
return rv;
}
int k_obj_core_stats_query(struct k_obj_core *obj_core, void *stats,
size_t stats_len)
{
int rv;
struct k_obj_core_stats_desc *desc;
__ASSERT((obj_core != NULL) && (stats != NULL), "NULL parameter");
k_spinlock_key_t key = k_spin_lock(&lock);
__ASSERT(obj_core->type != NULL, "Object core not initialized");
desc = obj_core->type->stats_desc;
if ((desc == NULL) || (desc->query == NULL)) {
/* The object type is not configured for this operation */
k_spin_unlock(&lock, key);
return -ENOTSUP;
}
if ((desc->query_size != stats_len) || (obj_core->stats == NULL)) {
/*
* Either the size of the stats buffer is wrong or
* the kernel object was not registered for statistics.
*/
k_spin_unlock(&lock, key);
return -EINVAL;
}
rv = desc->query(obj_core, stats);
k_spin_unlock(&lock, key);
return rv;
}
int k_obj_core_stats_reset(struct k_obj_core *obj_core)
{
int rv;
struct k_obj_core_stats_desc *desc;
__ASSERT((obj_core != NULL), "NULL parameter");
k_spinlock_key_t key = k_spin_lock(&lock);
__ASSERT(obj_core->type != NULL, "Object core not initialized");
desc = obj_core->type->stats_desc;
if ((desc == NULL) || (desc->reset == NULL)) {
/* The object type is not configured for this operation */
k_spin_unlock(&lock, key);
return -ENOTSUP;
}
if (obj_core->stats == NULL) {
/* This kernel object is not configured for statistics */
k_spin_unlock(&lock, key);
return -EINVAL;
}
rv = desc->reset(obj_core);
k_spin_unlock(&lock, key);
return rv;
}
int k_obj_core_stats_disable(struct k_obj_core *obj_core)
{
int rv;
struct k_obj_core_stats_desc *desc;
__ASSERT((obj_core != NULL), "NULL parameter");
k_spinlock_key_t key = k_spin_lock(&lock);
__ASSERT(obj_core->type != NULL, "Object core not initialized");
desc = obj_core->type->stats_desc;
if ((desc == NULL) || (desc->disable == NULL)) {
/* The object type is not configured for this operation */
k_spin_unlock(&lock, key);
return -ENOTSUP;
}
if (obj_core->stats == NULL) {
/* This kernel object is not configured for statistics */
k_spin_unlock(&lock, key);
return -EINVAL;
}
rv = desc->disable(obj_core);
k_spin_unlock(&lock, key);
return rv;
}
int k_obj_core_stats_enable(struct k_obj_core *obj_core)
{
int rv;
struct k_obj_core_stats_desc *desc;
__ASSERT((obj_core != NULL), "NULL parameter");
k_spinlock_key_t key = k_spin_lock(&lock);
__ASSERT(obj_core->type != NULL, "Object core not initialized");
desc = obj_core->type->stats_desc;
if ((desc == NULL) || (desc->enable == NULL)) {
/* The object type is not configured for this operation */
k_spin_unlock(&lock, key);
return -ENOTSUP;
}
if (obj_core->stats == NULL) {
/* This kernel object is not configured for statistics */
k_spin_unlock(&lock, key);
return -EINVAL;
}
rv = desc->enable(obj_core);
k_spin_unlock(&lock, key);
return rv;
}
#endif