概述 链接到标题

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 mgrobj_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_openmgr_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_unlockedk_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_sizequery_size, 在执行 k_obj_core_stats_rawk_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