概述 链接到标题
Object Cores 是 Zephyr 提供的一种内核调试工具,用于标识注册对象并对其执行统计操作。大多数 RTOS 的内核对象都建立有各自的 list 用于收集和报告统计信息,而 Zephyr 独立抽象出 Object Cores 提供了统一的方法来统计和检索信息。Zephyr 的各种内核对象允许通过 Object Cores 收集和报告统计信息。Object Core 被抽象出来标识对象和统计操作用的,但并不仅局限于在内核中使用,开发人员也可以自由地将它们集成到项目中的其他对象中。本文先集中说明如何使用 Object Core,而 Object Core 在 Zephyr 内的使用情况另文说明。
Object Cores 包含一个指向统计描述符的指针,该描述符定义了与对象统计信息交互的各种操作。此外,Object Cores 包含一个指向与该对象相关联的「原始」统计信息的指针。原始数据是与统计信息相关的原始、未经处理的数据。查询的数据可能是「原始」的,但也可能通过计算 ( 例如平均值 ) 以某种方式进行了处理。
使用方法 链接到标题
从概述里面知道 Object Cores 是用来追踪某类对象的,这里准备了一个叫 mgr 的对象作为示例,mgr 支持以下接口
mgr_open
打开一个 mgr 对象mgr_close
关闭一个 mgr 对象mgr_fetch
执行 fetch 动作mgr_get_stats_raw
获取 mgr 状态的原始数据mgr_query_stats
查询处理后的数据mgr_stats_reset
复位 mgr 的状态mgr_stats_enable
允许收集 mgr 的状态mgr_stats_disable
禁止收集 mgr 的状态
这里使用 Object Core 来演示如何追踪被打开的 mgr 对象以及如何通过 Object Core 来获取 mgr 的状态。
配置 链接到标题
要使用 Object Cores, 需要配置 CONFIG_OBJ_CORE=y
。如果要通过 Object Core 获取对象状态就还需要配置 CONFIG_OBJ_CORE_STATS=y
。 Object Cores 要被嵌入到 mgr 对象,为了方便区别后续的示例代码,都会用 CONFIG_OBJ_CORE
将嵌入到 mgr 的 Object core 的代码包起来。
数据结构 链接到标题
mgr 对象有下面数据结构,对于 mgr,每个对象都需要一个 struct k_obj_core
来进追踪
struct my_obj_type_raw_info {
uint32_t total_fetch_time;
uint32_t fetch_cnt;
};
struct my_obj_type_query_stats {
uint32_t avg_fetch_time;
};
//用于管理 mgr 对象
struct my_test_manage{
bool used; //该 mgr 对象是否被 open
bool statistic; //是否允许 mgr 被统计
struct my_obj_type_raw_info my_raw_data; //mgr 统计的原始数据
//插入 struct k_obj_core 用于追踪该对象,成员名建议用 obj_core
#ifdef CONFIG_OBJ_CORE
struct k_obj_core obj_core;
#endif
};
object core 的 API 是以 struct k_obj_core
为参数,当我们在结构体中插入的成员名为 obj_core
时可以通过 K_OBJ_CORE
访问该成员,例如访问 struct my_test_manage mgr
的 obj_core
就是 K_OBJ_CORE ( &mgr )
。反过来知道 obj_core
的指针,也可以获得 mgr 的地址,例如:
struct my_test_manage *mgr;
mgr = CONTAINER_OF ( obj_core, struct my_test_manage, obj_core ) ;
初始化 链接到标题
示例代码如下
#ifdef CONFIG_OBJ_CORE
#ifdef CONFIG_OBJ_CORE_STATS
//实现原始状态数据的回调函数
static int my_obj_type_stats_raw ( struct k_obj_core *obj_core, void *stats )
{
memcpy ( stats, obj_core->stats, sizeof ( struct my_obj_type_raw_info )) ;
return 0;
}
//实现查询数据的回调函数
static int my_obj_type_stats_query ( struct k_obj_core *obj_core, void *stats )
{
struct my_test_manage *mgr;
mgr = CONTAINER_OF ( obj_core, struct my_test_manage, obj_core ) ;
return mgr_query_stats ( mgr, stats ) ;
}
//实现复位状态的回调函数
static int my_obj_type_stats_reset ( struct k_obj_core *obj_core )
{
struct my_test_manage *mgr;
mgr = CONTAINER_OF ( obj_core, struct my_test_manage, obj_core ) ;
mgr_stats_reset ( mgr ) ;
return 0;
}
//实现禁用收集状态的回调
static int my_obj_type_stats_disable ( struct k_obj_core *obj_core )
{
struct my_test_manage *mgr;
mgr = CONTAINER_OF ( obj_core, struct my_test_manage, obj_core ) ;
mgr_stats_disable ( mgr ) ;
return 0;
}
//实现启用收集状态的回调
static int my_obj_type_stats_enable ( struct k_obj_core *obj_core )
{
struct my_test_manage *mgr;
mgr = CONTAINER_OF ( obj_core, struct my_test_manage, obj_core ) ;
mgr_stats_enable ( mgr ) ;
return 0;
}
//定义并初始化 struct k_obj_core_stats_desc, 给定数据的限定长度和回调函数
static struct k_obj_core_stats_desc my_obj_type_stats_desc = {
.raw_size = sizeof ( struct my_obj_type_raw_info ) , //指定 raw data 的长度
.query_size = sizeof ( struct my_obj_type_query_stats ) , //指定 query data 的长度
.raw = my_obj_type_stats_raw,
.query = my_obj_type_stats_query,
.reset = my_obj_type_stats_reset,
.disable = my_obj_type_stats_disable,
.enable = my_obj_type_stats_enable,
};
#endif /* CONFIG_OBJ_CORE_STATS */
//定义 MGR 的类型
# define K_OBJ_TYPE_MY_NEW_TYPE K_OBJ_TYPE_ID_GEN ( "MGRS" )
struct k_obj_type my_obj_type;
void my_obj_type_init ( void )
{
//初始化 object core 用于管理 mgr
z_obj_type_init ( &my_obj_type, K_OBJ_TYPE_MY_NEW_TYPE,
offsetof ( struct my_test_manage, obj_core )) ;
#ifdef CONFIG_OBJ_CORE_STATS
//初始化 object core stat 用于获取 mgr 的统计信息
k_obj_type_stats_init ( &my_obj_type, &my_obj_type_stats_desc ) ;
#endif /* CONFIG_OBJ_CORE_STATS */
}
//在应用初始化阶段调用 my_obj_type_init, 完成 mgr 的 object core 初始化
SYS_INIT ( my_obj_type_init, APPLICATION, 0 ) ;
#endif /*CONFIG_OBJ_CORE_STATS*/
前面一整段过程完成对 my_obj_type
的初始化,my_obj_type
可用于管理绑定的 mgr 对象。初始化可以分为两部分来看,一是使用 z_obj_type_init
进行 Object Core 的初始化,将创建一个链表对 MGR 对象进行管理。另外一种是实现 struct k_obj_core_stats_desc
要求的回调函数,并通过 k_obj_type_stats_init
进行初始化。
绑定对象 链接到标题
在 mgr_open
和 mgr_close
中使用 k_obj_core_init_and_link
将 mgr 对象链接到 my_obj_type
上,之后通过操作 my_obj_type
就可以访问所有的 mgr 对象,当 mgr 对象被 close 时使用 k_obj_core_unlink
解除链接。同样的如果要通过 object core 来获取 mgr 对象数据,需要使用 k_obj_core_stats_register
将 raw data 进行注册,当 mgr 对象被 close 时使用解除注册。
static void *mgr_open ( void )
{
for ( uint32_t i=0; i<MY_TEST_MGR_NUM; i++ ) {
if ( mgrs [i].used == false ) {
mgrs [i].used = true;
#ifdef CONFIG_OBJ_CORE
//链接对象
k_obj_core_init_and_link ( K_OBJ_CORE ( &mgrs [i] ) , &my_obj_type ) ;
#ifdef CONFIG_OBJ_CORE_STATS
//向对象注册 raw data
k_obj_core_stats_register ( K_OBJ_CORE ( &mgrs [i] ) ,
&mgrs [i].my_raw_data,
sizeof ( mgrs [i].my_raw_data )) ;
#endif
#endif
return &mgrs [i];
}
}
return NULL;
}
static bool mgr_close ( void* mgr )
{
for ( uint32_t i=0; i<MY_TEST_MGR_NUM; i++ ) {
if ( &mgrs [i].used == mgr ) {
#ifdef CONFIG_OBJ_CORE
#ifdef CONFIG_OBJ_CORE_STATS
//解除链接
k_obj_core_stats_deregister ( K_OBJ_CORE ( &mgrs [i] )) ;
#endif
//解除注册
k_obj_core_unlink ( K_OBJ_CORE ( &mgrs [i] )) ;
#endif
memset ( &mgrs [i], 0, sizeof ( struct my_test_manage )) ;
return true;
}
}
return false;
}
访问对象 链接到标题
通过 k_obj_type_walk_unlocked
和 k_obj_type_walk_locked
可以变量对象,二者的差别是访问对象的时候是否加锁,使用时先定义访问函数
int walk_op ( struct k_obj_core *obj_core, void *data )
{
struct my_test_manage *mgr;
mgr = CONTAINER_OF ( obj_core, struct my_test_manage, obj_core ) ;
shell_print ( data, "%p fetch time %u cnt %u", mgr, mgr->my_raw_data.total_fetch_time, mgr->my_raw_data.fetch_cnt ) ;
return 0;
}
然后遍历访问
//找到要遍历访问的对象
struct k_obj_type *obj_type;
obj_type = k_obj_type_find ( K_OBJ_TYPE_MY_NEW_TYPE ) ;
//以非 lock 的方式遍历所有 MGR 对象,有一个对象就会调用一次 walk_op
k_obj_type_walk_unlocked ( obj_type, walk_op, shell ) ;
//以 lock 的方式遍历所有 MGR 对象,有一个对象就会调用一次 walk_op
k_obj_type_walk_locked ( obj_type, walk_op, shell ) ;
统计查询 链接到标题
当配置 CONFIG_OBJ_CORE_STATS=y
后下列用于统计查询的 API 有效
//获取 obj_core 的原始状态数据到 stats 中,允许的数据长度为 stats_len
int k_obj_core_stats_raw ( struct k_obj_core *obj_core, void *stats, size_t stats_len ) ;
//获取 obj_core 的状态数据到 stats 中,允许的数据长度为 stats_len
int k_obj_core_stats_query ( struct k_obj_core *obj_core, void *stats, size_t stats_len ) ;
//复位 obj_core 的状态
int k_obj_core_stats_reset ( struct k_obj_core *obj_core ) ;
//禁止统计状态
int k_obj_core_stats_disable ( struct k_obj_core *obj_core ) ;
//允许统计状态
int k_obj_core_stats_enable ( struct k_obj_core *obj_core ) ;
k_obj_type_stats_init
进行初始化时通过 struct k_obj_core_stats_desc
要求的回调函数,回调函数和获取状态 API 的对应关系如下:
raw
:k_obj_core_stats_raw
query
:k_obj_core_stats_query
reset
:k_obj_core_stats_reset
disable
:k_obj_core_stats_disable
enable
:k_obj_core_stats_enable
这些回调并不是必须实现,当回调被赋予 NULL
时,调用对应的 API 会返回 -ENOTSUP
。
另外struct k_obj_core_stats_desc
也会要求给 raw_size
和 query_size
, 在执行 k_obj_core_stats_raw
和 k_obj_core_stats_query
会对比传入参数 stats_len
,如果不想等就返回 -EINVAL
。
获取状态的示例代码:
int status;
//启用统计
k_obj_core_stats_enable ( K_OBJ_CORE (( struct my_test_manage* ) mgr_handle [i] )) ;
//获取状态数据
status = k_obj_core_stats_query ( K_OBJ_CORE (( struct my_test_manage* ) mgr_handle [i] ) ,
&my_stats, sizeof ( my_stats )) ;
if ( status == 0 ) {
shell_print ( shell, "avg fetch time %u", my_stats.avg_fetch_time ) ;
}
//获取原始数据
status = k_obj_core_stats_raw ( K_OBJ_CORE (( struct my_test_manage* ) mgr_handle [i] ) ,
&my_raw, sizeof ( my_raw )) ;
if ( status == 0 ) {
shell_print ( shell, "total fetch time %u fetch cnt", my_raw.total_fetch_time, my_raw.fetch_cnt ) ;
}
//复位统计数据
k_obj_core_stats_reset ( K_OBJ_CORE (( struct my_test_manage* ) mgr_handle [i] )) ;
//禁用统计
k_obj_core_stats_disable ( K_OBJ_CORE (( struct my_test_manage* ) mgr_handle [i] )) ;
参考 链接到标题
https://docs.zephyrproject.org/3.5.0/kernel/object_cores/index.html