CPUP(Central Processing Unit Percentage,CPU占用率)分为系统CPU占用率和任务CPU占用率。用户通过系统级的CPU占用率,判断当前系统负载是否超出设计规格。通过系统中各个任务的CPU占用情况,判断各个任务的CPU占用率是否符合设计的预期。
系统CPU占用率是指周期时间内系统的CPU占用率,用于表示系统一段时间内的闲忙程度,也表示CPU的负载情况。系统CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示系统满负荷运转。
任务CPU占用率指单个任务的CPU占用率,用于表示单个任务在一段时间内的闲忙程度。任务CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示在一段时间内系统一直在运行该任务。
本文通过分析鸿蒙轻内核CPUP扩展模块的源码。本文中所涉及的源码,以OpenHarmony LiteOS-M内核为例,均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_m 获取。
CPUP模块用任务级记录的方式,在任务切换时,记录任务启动时间,任务切出或者退出时间,每次当任务退出时,系统会累加整个任务的占用时间。接下来,我们看下CPUP模块支持的常见操作的源代码。
1、CPUP结构体定义和常用宏定义
1.1 CPUP结构体定义
在文件components\cpup\los_cpup.h定义的CPUP控制块结构体为OsCpupCB,结构体源代码如下,allTime记录该任务自系统启动以来运行的cycle数,startTime记录任务开始运行的时间,historyTime[]历史运行时间数组的10个元素记录最近10秒中每一秒中每个任务自系统启动以来运行的cycle数,其他结构体成员的解释见注释部分。
typedef struct {
UINT32 cpupID; /**< 任务编号 */
UINT16 status; /**< 任务状态 */
UINT64 allTime; /**< 总共运行的时间 */
UINT64 startTime; /**< 任务开始时间 */
UINT64 historyTime[OS_CPUP_HISTORY_RECORD_NUM]; /**< 历史运行时间数组,其中OS_CPUP_HISTORY_RECORD_NUM为10 */
} OsCpupCB;
另外,还定义了一个结构体CPUP_INFO_S,如下:
typedef struct tagCpupInfo {
UINT16 usStatus; /**< 保存当前运行任务状态 */
UINT32 uwUsage; /**< 使用情况,值范围为 [0,1000]. */
} CPUP_INFO_S;
1.2 CPUP枚举定义
CPUP头文件components\cpup\los_cpup.h中还提供了相关的枚举,CPUP占用率类型CPUP_TYPE_E,及CPUP统计时间间隔模式CPUP_MODE_E。
typedef enum {
SYS_CPU_USAGE = 0, /* 系统CPUP */
TASK_CPU_USAGE, /* 任务CPUP */
} CPUP_TYPE_E;
typedef enum {
CPUP_IN_10S = 0, /* CPUP统计周期10s */
CPUP_IN_1S, /* CPUP统计周期1s */
CPUP_LESS_THAN_1S, /* CPUP统计周期<1s */
} CPUP_MODE_E;
2、CPUP初始化
CPUP默认关闭,用户可以通过宏LOSCFG_BASE_CORE_CPUP进行开启。开启CPUP的情况下,在系统启动时,在kernel\src\los_init.c中调用OsCpupInit()进行CPUP模块初始化。下面,我们分析下CPUP初始化的代码。
⑴处计算CPUP结构体池需要的内存大小,然后为CPUP申请内存,如果申请失败,则返回错误。⑵处初始化成功后,设置初始化标记g_cpupInitFlg。
LITE_OS_SEC_TEXT_INIT UINT32 OsCpupInit()
{
UINT32 size;
size = g_taskMaxNum * sizeof(OsCpupCB);
⑴ g_cpup = (OsCpupCB *)LOS_MemAlloc(m_aucSysMem0, size);
if (g_cpup == NULL) {
return LOS_ERRNO_CPUP_NO_MEMORY;
}
(VOID)memset_s(g_cpup, size, 0, size);
⑵ g_cpupInitFlg = 1;
return LOS_OK;
}
3、CPUP常用操作
3.1 CPUP内部接口
我们先分析下内部接口,这些接口会被LOS_开头的外部接口调用。
3.1.1 OsTskCycleStart记录任务开始时间
CPUP模块对外接口执行后期会调用该内部接口,设置下一个任务的开始运行时间。
⑴处先判断CPUP是否已经初始化,如果没有初始化过,退出该函数的执行。⑵处获取新任务的任务编号。⑶处设置该任务对应的CPUP结构体的任务编号和开始时间。
LITE_OS_SEC_TEXT_MINOR VOID OsTskCycleStart(VOID)
{
UINT32 taskID;
⑴ if (g_cpupInitFlg == 0) {
return;
}
⑵ taskID = g_losTask.newTask->taskID;
⑶ g_cpup[taskID].cpupID = taskID;
g_cpup[taskID].startTime = LOS_SysCycleGet();
return;
}
3.1.2 OsTskCycleEnd记录任务结束时间
CPUP模块对外接口执行前期会调用该内部接口,获取当前任务的结束时间,并统计当前任务的运行总时间。
⑴处先判断CPUP是否已经初始化,如果没有初始化过,退出该函数的执行。⑵处获取当前任务的任务编号。⑶处如果该任务的开始时间为0,退出函数执行。⑷处获取系统的当前cycle数。⑸如果获取的小于任务CPUP开始时间,则把获取的cycle数加上每个tick的cycle数。⑹处计算当前任务的运行的总时间,然后把开始时间置0。
LITE_OS_SEC_TEXT_MINOR VOID OsTskCycleEnd(VOID)
{
UINT32 taskID;
UINT64 cpuCycle;
⑴ if (g_cpupInitFlg == 0) {
return;
}
⑵ taskID = g_losTask.runTask->taskID;
⑶ if (g_cpup[taskID].startTime == 0) {
return;
}
⑷ cpuCycl

最低0.47元/天 解锁文章
632

被折叠的 条评论
为什么被折叠?



