鸿蒙轻内核M核源码分析系列十五 CPU使用率CPUP

往期知识点记录:

  • 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
  • 轻内核M核源码分析系列一 数据结构-双向循环链表
  • 轻内核M核源码分析系列二 数据结构-任务就绪队列
  • 鸿蒙轻内核M核源码分析系列三 数据结构-任务排序链表
  • 轻内核M核源码分析系列四 中断Hwi
  • 轻内核M核源码分析系列五 时间管理
  • 轻内核M核源码分析系列六 任务及任务调度(1)任务栈
  • 轻内核M核源码分析系列六 任务及任务调度(2)任务模块
  • 轻内核M核源码分析系列六 任务及任务调度(3)任务调度模块
  • 轻内核M核源码分析系列七 动态内存Dynamic Memory
  • 轻内核M核源码分析系列八 静态内存MemoryBox
  • 轻内核M核源码分析系列九 互斥锁Mutex
  • 轻内核M核源码分析系列十 软件定时器Swtmr
  • 轻内核M核源码分析系列十一 (1)信号量Semaphore
  • 轻内核M核源码分析系列十一 (2)信号量Semaphore
  • 轻内核M核源码分析系列十二 事件Event
  • 轻内核M核源码分析系列十三 消息队列Queue
  • 轻内核M核源码分析系列十四 软件定时器Swtmr
  • 轻内核M核源码分析系列十五 CPU使用率CPUP
  • 轻内核M核源码分析系列十六 MPU内存保护单元
  • 轻内核M核源码分析系列十七(1) 异常钩子函数类型介绍
  • 轻内核M核源码分析系列十七(2) 异常钩子函数的注册操作
  • 轻内核M核源码分析系列十七(3) 异常信息ExcInfo
  • 轻内核M核源码分析系列十八 Fault异常处理
  • 轻内核M核源码分析系列十九 Musl LibC
  • 轻内核M核源码分析系列二十 Newlib C
  • 持续更新中……

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数加上每个tickcycle数。⑹处计算当前任务的运行的总时间,然后把开始时间置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;}⑷  cpuCycle = LOS_SysCycleGet();⑸  if (cpuCycle < g_cpup[taskID].startTime) {cpuCycle += g_cyclesPerTick;}⑹  g_cpup[taskID].allTime += (cpuCycle - g_cpup[taskID].startTime);g_cpup[taskID].startTime = 0;return;
}
3.1.3 OsTskCycleEndStart任务切换时更新任务历史运行时间

该函数在任务调度切换时会被执行,计算当前运行任务的运行总时间,记录新任务的开始时间,并更新所有任务的历史运行时间。函数的示意图如下:

⑴处先判断CPUP是否已经初始化,如果没有初始化过,退出该函数的执行。⑵处获取当前任务的任务编号,然后获取系统的当前cycle数。⑶处如果当前任务的开始时间不为0,则计算当前任务的运行的总时间,然后把开始时间置0。

⑷处获取新任务的任务编号,⑸处设置该任务对应的CPUP结构体的任务编号和开始时间。⑹处如果记录间隔大于系统时钟(即每秒的cycle数),更新上次记录时间。这意味着每个任务的historyTime[]数组中的每个元素表示1s多的周期内该任务的运行cycle数量,并不是非常精确的。然后执行⑺,记录每一个任务对应的CPUP的历史运行时间。⑻处更新历史运行时间数组的当前索引值。

LITE_OS_SEC_TEXT_MINOR VOID OsTskCycleEndStart(VOID)
{UINT32 taskID;UINT64 cpuCycle;UINT16 loopNum;⑴  if (g_cpupInitFlg == 0) {return;}⑵  taskID = g_losTask.runTask->taskID;cpuCycle = LOS_SysCycleGet();⑶  if (g_cpup[taskID].startTime != 0) {if (cpuCycle < g_cpup[taskID].startTime) {cpuCycle += g_cyclesPerTick;}g_cpup[taskID].allTime += (cpuCycle - g_cpup[taskID].startTime);g_cpup[taskID].startTime = 0;}⑷  taskID = g_losTask.newTask->taskID;
⑸  g_cpup[taskID].cpupID = taskID;g_cpup[taskID].startTime = cpuCycle;⑹  if ((cpuCycle - g_lastRecordTime) > OS_CPUP_RECORD_PERIOD) {g_lastRecordTime = cpuCycle;for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {
⑺          g_cpup[loopNum].historyTime[g_hisPos] = g_cpup[loopNum].allTime;}⑻      if (g_hisPos == (OS_CPUP_HISTORY_RECORD_NUM - 1)) {g_hisPos = 0;} else {g_hisPos++;}}return;
}
3.1.4 OsGetPrePos获取历史运行时间数组上一索引位置

代码比较简单,如果传入参数curPos为0,则返回数组的最后一个索引位置OS_CPUP_HISTORY_RECORD_NUM - 1。否则返回减1返回。

LITE_OS_SEC_TEXT_MINOR static inline UINT16 OsGetPrePos(UINT16 curPos)
{return (curPos == 0) ? (OS_CPUP_HISTORY_RECORD_NUM - 1) : (curPos - 1);
}
3.1.5 OsGetPositions获取历史运行时间数组的当前及上一索引位置

根据CPUP统计时间间隔模式,获取历史运行时间数组的当前及上一索引位置。

⑴处获取历史运行时间数组的当前索引位置
⑵如果时间间隔模式为1秒,当前索引curPos位置为g_hisPos的上一索引位置,上一索引位置prePos需要继续上前一位。
⑶如果时间间隔模式小于1秒,当前索引curPos位置为g_hisPos的上一索引位置,上一索引位置prePos为0。如果时间间隔模式是10秒,当前索引curPos位置就等于g_hisPos,上一索引位置prePos为0。⑷处设置传出参数。

LITE_OS_SEC_TEXT_MINOR static VOID OsGetPositions(UINT16 mode, UINT16* curPosAddr, UINT16* prePosAddr)
{UINT16 curPos;UINT16 prePos = 0;⑴  curPos = g_hisPos;⑵  if (mode == CPUP_IN_1S) {curPos = OsGetPrePos(curPos);prePos = OsGetPrePos(curPos);
⑶  } else if (mode == CPUP_LESS_THAN_1S) {curPos = OsGetPrePos(curPos);}⑷  *curPosAddr = curPos;*prePosAddr = prePos;
}

3.2 CPUP对外接口

我们先分析下外部接口,接口说明如下:

接口名称功能描述
LOS_SysCpuUsage获取当前系统CPU占用率
LOS_HistorySysCpuUsage获取系统历史CPU占用率
LOS_TaskCpuUsage获取指定任务CPU占用率
LOS_HistoryTaskCpuUsage获取指定任务历史CPU占用率
LOS_AllTaskCpuUsage获取所有任务CPU占用率
LOS_CpupUsageMonitor输出任务历史CPU占用率
3.2.1 LOS_SysCpuUsage

该函数会统计当前系统CPU占用率,返回值基于千分率计算,取值范围为[0,1000]。函数的示意图如下:

⑴处先判断CPUP是否已经初始化,如果没有初始化过,返回错误码。
⑵处调用函数OsTskCycleEnd()获取当前任务的结束时间,并计算出运行总时间。
⑶处统计所有任务的运行总时间,如果总时间不为0,执行
⑷计算出系统的任务CPU占用率。
⑸处调用函数OsTskCycleStart()设置新任务的CPUP统计的开始时间。

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_SysCpuUsage(VOID)
{UINT64  cpuCycleAll = 0;UINT32  cpupRet = 0;UINT16  loopNum;UINT32 intSave;⑴  if (g_cpupInitFlg == 0) {return LOS_ERRNO_CPUP_NO_INIT;}intSave = LOS_IntLock();
⑵  OsTskCycleEnd();⑶  for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {cpuCycleAll += g_cpup[loopNum].allTime;}⑷  if (cpuCycleAll) {cpupRet = LOS_CPUP_PRECISION -  (UINT32)((LOS_CPUP_PRECISION *g_cpup[g_idleTaskID].allTime) / cpuCycleAll);}⑸  OsTskCycleStart();LOS_IntRestore(intSave);return cpupRet;
}
3.2.2 LOS_HistorySysCpuUsage

该函数获取系统历史CPU占用率,对于历史CPU占用率,需要传入时间间隔模式参数,支持10秒、1秒、小于1秒三种。

⑴处先判断CPUP是否已经初始化,如果没有初始化过,返回错误码。
⑵处调用函数OsTskCycleEnd()获取当前任务的结束时间,并计算出运行总时间。
⑶处调用函数OsGetPositions()计算出历史运行时间数组索引位置。
⑷处计算出各个任务的周期内运行总时间,如果时间间隔模式为1秒,取值两个历史运行时间之差,即为1秒内任务的运行时间数。对于时间间隔模式为10秒,historyTime[curPos]表示10秒前的自系统启动以来的任务运行的时间数,计算出来的差值即为10秒内任务的运行时间数。对于时间间隔模式为小于1秒,historyTime[curPos]表示上一秒前的自系统启动以来的任务运行的时间数,计算出来的差值即为小于1秒内任务的运行时间数。
⑸处计算空闲任务周期内运行总时间。
⑹处如果总时间不为0,计算出系统的任务历史CPU占用率。最后,调用函数OsTskCycleStart()设置新任务的CPUP统计的开始时间。可以参考示意图进行理解:

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_HistorySysCpuUsage(UINT16 mode)
{UINT64  cpuCycleAll = 0;UINT64  idleCycleAll = 0;UINT32  cpupRet = 0;UINT16  loopNum;UINT16  curPos;UINT16  prePos = 0;UINT32 intSave;⑴  if (g_cpupInitFlg == 0) {return LOS_ERRNO_CPUP_NO_INIT;}// get end time of current taskintSave = LOS_IntLock();
⑵  OsTskCycleEnd();⑶  OsGetPositions(mode, &curPos, &prePos);for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {
⑷      if (mode == CPUP_IN_1S) {cpuCycleAll += g_cpup[loopNum].historyTime[curPos] - g_cpup[loopNum].historyTime[prePos];} else {cpuCycleAll += g_cpup[loopNum].allTime - g_cpup[loopNum].historyTime[curPos];}}⑸  if (mode == CPUP_IN_1S) {idleCycleAll += g_cpup[g_idleTaskID].historyTime[curPos] -g_cpup[g_idleTaskID].historyTime[prePos];} else {idleCycleAll += g_cpup[g_idleTaskID].allTime - g_cpup[g_idleTaskID].historyTime[curPos];}⑹  if (cpuCycleAll) {cpupRet = (LOS_CPUP_PRECISION -  (UINT32)((LOS_CPUP_PRECISION * idleCycleAll) / cpuCycleAll));}OsTskCycleStart();LOS_IntRestore(intSave);return cpupRet;
}
3.2.3 LOS_TaskCpuUsage

该函数会统计指定任务的CPU占用率,和函数LOS_SysCpuUsage()代码相似度高,可以参考上文对该函数的讲解。

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskCpuUsage(UINT32 taskID)
{UINT64  cpuCycleAll = 0;UINT16  loopNum;UINT32 intSave;UINT32  cpupRet = 0;if (g_cpupInitFlg == 0) {return LOS_ERRNO_CPUP_NO_INIT;}if (OS_TSK_GET_INDEX(taskID) >= g_taskMaxNum) {return LOS_ERRNO_CPUP_TSK_ID_INVALID;}if (g_cpup[taskID].cpupID != taskID) {return LOS_ERRNO_CPUP_THREAD_NO_CREATED;}if ((g_cpup[taskID].status & OS_TASK_STATUS_UNUSED) || (g_cpup[taskID].status == 0)) {return LOS_ERRNO_CPUP_THREAD_NO_CREATED;}intSave = LOS_IntLock();OsTskCycleEnd();for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {if ((g_cpup[loopNum].status & OS_TASK_STATUS_UNUSED) || (g_cpup[loopNum].status == 0)) {continue;}cpuCycleAll += g_cpup[loopNum].allTime;}if (cpuCycleAll) {cpupRet = (UINT32)((LOS_CPUP_PRECISION * g_cpup[taskID].allTime) / cpuCycleAll);}OsTskCycleStart();LOS_IntRestore(intSave);return cpupRet;
}
3.2.4 LOS_HistoryTaskCpuUsage

该函数获取指定任务的历史CPU占用率,和函数LOS_HistorySysCpuUsage()代码相似度高,可以参考上文对该函数的讲解。

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_HistoryTaskCpuUsage(UINT32 taskID, UINT16 mode)
{UINT64  cpuCycleAll = 0;UINT64  cpuCycleCurTsk = 0;UINT16  loopNum, curPos;UINT16  prePos = 0;UINT32 intSave;UINT32  cpupRet = 0;if (g_cpupInitFlg == 0) {return LOS_ERRNO_CPUP_NO_INIT;}if (OS_TSK_GET_INDEX(taskID) >= g_taskMaxNum) {return LOS_ERRNO_CPUP_TSK_ID_INVALID;}if (g_cpup[taskID].cpupID != taskID) {return LOS_ERRNO_CPUP_THREAD_NO_CREATED;}if ((g_cpup[taskID].status & OS_TASK_STATUS_UNUSED) || (g_cpup[taskID].status == 0)) {return LOS_ERRNO_CPUP_THREAD_NO_CREATED;}intSave = LOS_IntLock();OsTskCycleEnd();OsGetPositions(mode, &curPos, &prePos);for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {if ((g_cpup[loopNum].status & OS_TASK_STATUS_UNUSED) || (g_cpup[loopNum].status == 0)) {continue;}if (mode == CPUP_IN_1S) {cpuCycleAll += g_cpup[loopNum].historyTime[curPos] - g_cpup[loopNum].historyTime[prePos];} else {cpuCycleAll += g_cpup[loopNum].allTime - g_cpup[loopNum].historyTime[curPos];}}if (mode == CPUP_IN_1S) {cpuCycleCurTsk += g_cpup[taskID].historyTime[curPos] - g_cpup[taskID].historyTime[prePos];} else {cpuCycleCurTsk += g_cpup[taskID].allTime - g_cpup[taskID].historyTime[curPos];}if (cpuCycleAll) {cpupRet = (UINT32)((LOS_CPUP_PRECISION * cpuCycleCurTsk) / cpuCycleAll);}OsTskCycleStart();LOS_IntRestore(intSave);return cpupRet;
}
3.2.5 LOS_AllTaskCpuUsage

该函数获取全部任务的CPU占用率,获取的CPU占用率信息保存在传出参数结构体CPUP_INFO_S *cpupInfo指向的内存区域里,需要注意这个内存区域的大小需要等于sizeof(CPUP_INFO_S) * g_taskMaxNum。还需要传入时间间隔模式参数,支持10秒、1秒、小于1秒三种。

⑴处先判断CPUP是否已经初始化,如果没有初始化过,返回错误码。传出参数cpupInfo指针不能为空,否则返回错误码。⑵处调用函数OsTskCycleEnd()获取当前任务的结束时间,并计算出运行总时间。⑶处调用函数OsGetPositions()计算出历史运行时间数组索引位置。⑷处计算出各个任务的周期内运行总时间,如果时间间隔模式为1秒,取值两个历史运行时间之差,否则取值XX。⑸处设置每一个任务的状态,然后计算出每一个任务的CPU占用率。最后,调用函数OsTskCycleStart()设置新任务的CPUP统计的开始时间。

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_AllTaskCpuUsage(CPUP_INFO_S *cpupInfo, UINT16 mode)
{UINT16  loopNum;UINT16  curPos;UINT16  prePos = 0;UINT32 intSave;UINT64  cpuCycleAll = 0;UINT64  cpuCycleCurTsk = 0;⑴  if (g_cpupInitFlg == 0) {return  LOS_ERRNO_CPUP_NO_INIT;}if (cpupInfo == NULL) {return LOS_ERRNO_CPUP_TASK_PTR_NULL;}intSave = LOS_IntLock();
⑵  OsTskCycleEnd();⑶  OsGetPositions(mode, &curPos, &prePos);for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {if ((g_cpup[loopNum].status & OS_TASK_STATUS_UNUSED) ||(g_cpup[loopNum].status == 0)) {continue;}if (mode == CPUP_IN_1S) {cpuCycleAll += g_cpup[loopNum].historyTime[curPos] - g_cpup[loopNum].historyTime[prePos];} else {cpuCycleAll += g_cpup[loopNum].allTime - g_cpup[loopNum].historyTime[curPos];}}⑷  for (loopNum = 0; loopNum < g_taskMaxNum; loopNum++) {if ((g_cpup[loopNum].status & OS_TASK_STATUS_UNUSED) ||(g_cpup[loopNum].status == 0)) {continue;}if (mode == CPUP_IN_1S) {cpuCycleCurTsk += g_cpup[loopNum].historyTime[curPos] - g_cpup[loopNum].historyTime[prePos];} else {cpuCycleCurTsk += g_cpup[loopNum].allTime - g_cpup[loopNum].historyTime[curPos];}
⑸      cpupInfo[loopNum].usStatus = g_cpup[loopNum].status;if (cpuCycleAll) {cpupInfo[loopNum].uwUsage = (UINT32)((LOS_CPUP_PRECISION * cpuCycleCurTsk) / cpuCycleAll);}cpuCycleCurTsk = 0;}OsTskCycleStart();LOS_IntRestore(intSave);return LOS_OK;
}
3.2.6 LOS_CpupUsageMonitor

该函数获取历史CPU占用率并打印输出,传入参数有三个:CPU占用率类型,CPUP时间周期模式,指定的任务编号。对于任务CPU占用率,才需要指定有效的任务编号。

⑴处处理CPU占用率类型为系统CPU占用率的情况
⑵处打印使用的CPUP时间周期模式。
⑶处通过调用函数LOS_HistorySysCpuUsage()获取系统历史CPU占用率,然后执行
⑷打印输出CPU占用率结果,输出结果范围为[0,100]。

⑸处处理CPU占用率类型为指定任务CPU占用率的情况,首先判断下任务编号的有效性,校验任务是否创建等。
⑹处打印使用的CPUP时间周期模式。
⑺处通过调用函数LOS_HistoryTaskCpuUsage()获取指定任务的历史CPU占用率,然后执行
⑻打印输出CPU占用率结果,输出结果范围为[0,100]。

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CpupUsageMonitor(CPUP_TYPE_E type, CPUP_MODE_E mode, UINT32 taskID)
{UINT32 ret;LosTaskCB *taskCB = NULL;switch (type) {
⑴      case SYS_CPU_USAGE:
⑵          if (mode == CPUP_IN_10S) {PRINTK("\nSysCpuUsage in 10s: ");} else if (mode == CPUP_IN_1S) {PRINTK("\nSysCpuUsage in 1s: ");} else {PRINTK("\nSysCpuUsage in <1s: ");}
⑶          ret = LOS_HistorySysCpuUsage(mode);
⑷          PRINTK("%d.%d", ret / LOS_CPUP_PRECISION_MULT, ret % LOS_CPUP_PRECISION_MULT);break;⑸      case TASK_CPU_USAGE:if (taskID > LOSCFG_BASE_CORE_TSK_LIMIT) {PRINT_ERR("\nThe taskid is invalid.\n");return OS_ERROR;}taskCB = OS_TCB_FROM_TID(taskID);if ((taskCB->taskStatus & OS_TASK_STATUS_UNUSED)) {PRINT_ERR("\nThe taskid is invalid.\n");return OS_ERROR;}
⑹          if (mode == CPUP_IN_10S) {PRINTK("\nCPUusage of taskID %d in 10s: ", taskID);} else if (mode == CPUP_IN_1S) {PRINTK("\nCPUusage of taskID %d in 1s: ", taskID);} else {PRINTK("\nCPUusage of taskID %d in <1s: ", taskID);}
⑺          ret = LOS_HistoryTaskCpuUsage(taskID, mode);
⑻          PRINTK("%u.%u", ret / LOS_CPUP_PRECISION_MULT, ret % LOS_CPUP_PRECISION_MULT);break;default:PRINT_ERR("\nThe type is invalid.\n");return OS_ERROR;}return LOS_OK;
}

小结

本文带领大家一起剖析了鸿蒙轻内核的CPUP扩展模块的源代码。

经常有很多小伙伴抱怨说:不知道学习鸿蒙开发哪些技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?

为了能够帮助到大家能够有规划的学习,这里特别整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

在这里插入图片描述

《鸿蒙 (Harmony OS)开发学习手册》(共计892页):https://gitcode.com/HarmonyOS_MN/733GH/overview

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

在这里插入图片描述

基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

在这里插入图片描述

鸿蒙开发面试真题(含参考答案):https://gitcode.com/HarmonyOS_MN/733GH/overview

在这里插入图片描述

OpenHarmony 开发环境搭建

图片

《OpenHarmony源码解析》:https://gitcode.com/HarmonyOS_MN/733GH/overview

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……
  • 系统架构分析
  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

图片

OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview

图片
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/878890.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国产脑机全面超越马斯克Nearlink

&#x1f4a5;&#x1f4a5;&#x1f4a5;刚刚&#xff0c;世界首富马斯克同学已经是完全懵逼了&#xff0c;心态都崩了&#xff01;因为今天爆出来了一个轰动了全世界科技界的大新闻&#xff0c;国产脑机在多个维度上全面超越了马斯克的Nearlink&#xff01; &#x1f4a5;&am…

SpringBoot2:请求处理原理分析-RESTFUL风格接口

一、RESTFUL简介 Rest风格支持&#xff08;使用HTTP请求方式&#xff0c;动词来表示对资源的操作&#xff09; 以前&#xff1a;/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户 现在&#xff1a; /user GET-获取用户 DELETE-删除用户 PUT-修改…

数据仓库技术选型方案文档

关联博客&#xff1a; 数据仓库技术选型方案文档 Flink CDC MySQL数据同步到Doris表同步配置生成工具类 新版报表系统&#xff08;明细报表、看板、数据大屏&#xff09;方案&介绍 文章目录 数据仓库技术选型背景现状现状架构目标架构业务反馈&痛点问题&#xff1a;原因…

随手记:小程序体积超出2M包大小如何优化

小程序的包体积限制是2M&#xff0c;超出包大小如何优化 先简单列出&#xff0c;最近比较忙&#xff0c;后续优化明细&#xff0c;有着急的先留言踢我 1.分包 留几个主要的页面体积小的&#xff0c;剩下的在page.json中拆到subpackages中&#xff0c;简单举个例子 "page…

多维动态规划-面试高频!-最长公共子序列和最长公共子串、回文串-c++实现和详解

1143. 最长公共子序列 中等 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删…

力扣1049-最后一块石头的重量II(Java详细题解)

题目链接&#xff1a;1049. 最后一块石头的重量 II - 力扣&#xff08;LeetCode&#xff09; 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 最近刚学完01背包&#xff0c;所以现在的题解都是以01背包问题为基础再来写的。 如果大家不懂…

FPGA实现串口升级及MultiBoot(二)FPGA启动流程

这个系列开篇肯定要先了解FPGA的启动流程&#xff0c;试想一下&#xff1a;我想实现MultiBoot&#xff0c;那么我应该在什么时候开始升级&#xff0c;升级失败后FPGA进行了哪些操作&#xff0c;以及怎么回到Golden区&#xff1f; 还有一个问题&#xff0c;就是我硬件打板回来&a…

Selenium 实现图片验证码识别

前言 在测试过程中&#xff0c;有的时候登录需要输入图片验证码。这时候使用Selenium进行自动化测试&#xff0c;怎么做图片验证码识别&#xff1f;本篇内容主要介绍使用Selenium、BufferedImage、Tesseract进行图片 验证码识别。 环境准备 jdk&#xff1a;1.8 tessdata&…

深度学习--对抗生成网络(GAN, Generative Adversarial Network)

对抗生成网络&#xff08;GAN, Generative Adversarial Network&#xff09;是一种深度学习模型&#xff0c;由Ian Goodfellow等人在2014年提出。GAN主要用于生成数据&#xff0c;通过两个神经网络相互对抗&#xff0c;来生成以假乱真的新数据。以下是对GAN的详细阐述&#xff…

如果电脑一直提示微软账号登录……

前言 今天小白接了个电脑故障问题&#xff1a;电脑提示微软账号登录&#xff0c;然后经过各种操作…… 电脑重启之后就变成了这样&#xff1a; 按理说&#xff0c;登录了微软账号之后&#xff0c;Windows系统要进入到桌面就必须有一个输入密码验证的过程&#xff0c;但这个界…

Harmony OS DevEco Studio 如何导入第三方库(以lottie为例)?-- HarmonyOS自学2

在做鸿蒙开发时&#xff0c;离不开第三方库的引入 一.有哪些支持的Harmony OS的 第三方库&#xff1f; 第三方库下载地址&#xff1a; 1 tpc_resource: 三方组件资源汇总 2 OpenHarmony三方库中心仓 二. 如何加入到DevEco Studio工程 以 lottie为例 OpenHarmony-TPC/lot…

nginx 新建一个 PC web 站点

注意&#xff1a;进行实例之前必须完成nginx的源码编译。&#xff08;阅读往期文章完成步骤&#xff09; 1.编辑nginx的配置文件&#xff0c;修改内容 [rootlocalhost ~]# vim /usr/local/nginx/conf/nginx.conf 2.创建新目录/usr/local/nginx/conf.d/&#xff0c;编辑新文件…

基于飞腾平台的Hive的安装配置

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

通信工程学习:什么是PCM脉冲编码调制、DPCM差分脉冲编码调制、ADPCM自适应差分脉冲编码调制

PCM脉冲编码调制、DPCM差分脉冲编码调制、ADPCM自适应差分脉冲编码调制 PCM、DPCM、ADPCM是音频编码技术中的三种重要方式&#xff0c;它们在音频信号的数字化、压缩和传输中起着关键作用。以下是对这三种技术的详细解释&#xff1a; 一、PCM&#xff08;Pulse Code Modulatio…

2024数学建模国赛选题建议+团队助攻资料(已更新完毕)

目录 一、题目特点和选题建议 二、模型选择 1、评价模型 2、预测模型 3、分类模型 4、优化模型 5、统计分析模型 三、white学长团队助攻资料 1、助攻代码 2、成品论文PDF版 3、成品论文word版 9月5日晚18&#xff1a;00就要公布题目了&#xff0c;根据历年竞赛题目…

[C#学习笔记]注释

官方文档&#xff1a;Documentation comments - C# language specification | Microsoft Learn 一、常用标记总结 1.1 将文本设置为代码风格的字体&#xff1a;<c> 1.2 源代码或程序输出:<code> 1.3 异常指示:<exception> 1.4 段落 <para> 1.5 换行&…

Reflection 70B:震撼AI行业的开源模型

随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;开源与闭源模型的竞争变得越来越激烈。近日&#xff0c;Reflection 70B模型的发布在AI行业引发了巨大的震动。这款拥有70亿参数的开源模型不仅在多项基准测试中取得了优异成绩&#xff0c;还在很多情况下超越…

滑动窗口系列(同向双指针)/9.7

新的解题思路 一、三数之和的多种可能 给定一个整数数组 arr &#xff0c;以及一个整数 target 作为目标值&#xff0c;返回满足 i < j < k 且 arr[i] arr[j] arr[k] target 的元组 i, j, k 的数量。 由于结果会非常大&#xff0c;请返回 109 7 的模。 输入&…

【阿里云】个人认证与公司认证

个人认证和企业认证的区别 更新时间&#xff1a;2024-05-20 09:32:52 本文档主要介绍个人认证账号和企业认证账号的区别。 账号实名认证分为个人实名认证和企业实名认证。 个人账号认证&#xff0c;请选择认证类型为 个人&#xff0c;支持个人支付宝授权认证和个人扫脸认证。…

使用cage工具包生成验证码

目录 1. 导入依赖2. 控制类3. 测试 1. 导入依赖 <!-- 验证码工具 --><dependency><groupId>com.github.cage</groupId><artifactId>cage</artifactId><version>1.0</version></dependency>2. 控制类 RestControl…