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

news2024/9/21 2:30:19

往期知识点记录:

  • 鸿蒙(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 task
    intSave = 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.coloradmin.cn/o/2114128.html

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

相关文章

三维布尔运算对不规范几何数据的兼容处理

1.前言 上一篇文章谈过八叉树布尔运算&#xff0c;对于规范几何数据的情况是没有问题的。 在实际情况中&#xff0c;由于几何数据来源不一&#xff0c;处理和生成方式不一&#xff0c;我们无法保证进行布尔运算的几何数据都是规范的&#xff0c;对于不规范情况有时候也有需求…

个股场外期权的行权时间是什么时候?

今天带你了解个股场外期权的行权时间是什么时候&#xff1f;场外个股期权的行权日并没有一个固定的日期&#xff0c;它主要取决于期权合约的具体条款和规定。 个股场外期权 个股场外期权是指在场外交易市场进行的、以单个股票为标的资产的期权合约。这种期权与在交易所交易的…

@Cacheable踩坑,服务停住,~lock

1、问题&#xff1a; 方法使用Cacheable注解&#xff0c;服务每次重启后&#xff0c;调到这个方法都服务停住了&#xff0c;日志也不打了。 2、原因&#xff1a; 服务停止住了&#xff0c;发现redis会生成key~lock的锁&#xff0c;永不过期&#xff0c;也没有删除。 例如以下…

【2025】公司仓库管理系统的设计与实现(公司仓库信息管理系统,仓库信息系统,管理系统,信息管理系统,货物仓管系统)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

【IEEE出版】2024博鳌新型电力系统国际论坛——电力系统与新能源技术创新论坛(NPSIF 2024,10月30-11月1)

2024博鳌新型电力系统国际论坛——电力系统与新能源技术创新论坛将于2024年10月30-11月1日于海南博鳌举办。 会议的历史悠久&#xff0c;致力于促进电力系统领域的研究和开发活动&#xff0c;同时也着眼于促进全球各地研究人员、开发人员、工程师、学生和从业人员之间的科学信息…

适合新手进阶,借助ChatGPT撰写学术论文全流程指南,附顶级提示词使用攻略

大家好,感谢关注。我是七哥,一个在高校里不务正业,折腾学术科研AI实操的学术人。关于使用ChatGPT等AI学术科研的相关问题可以和作者七哥(yida985)交流,多多交流,相互成就,共同进步,为大家带来最酷最有效的智能AI学术科研写作攻略。 学术论文的写作涉及深入研究、分析…

ECCV`24 | 蚂蚁集团开源风格控制新SOTA!StyleTokenizer:零样本精确控制图像生成

文章链接&#xff1a;https://arxiv.org/pdf/2409.02543 代码&数据集链接&#xff1a; https://github.com/alipay/style-tokenizer 亮点直击 介绍了一种名为StyleTokenizer的新方法&#xff0c;用于在扩散模型中进行风格控制。这种方法允许通过一个任意参考图像实现对生成…

元学习(meta learning)(一)

元学习从字面的意思就是“学习”的“学习”&#xff0c;也 就是学习如何学习。大部分的深度学习就是在不断的调整超参数&#xff0c;或者在决定网络架构&#xff0c;改变 学习率等等。实际上没有什么好方法来调这些超参&#xff0c;今天工业界最常拿来解决调整超参数的 方法是买…

dpdk——数据平面开发套件

数据平面开发工具包 &#xff08;DPDK&#xff09; 是一个 Linux Foundation 项目&#xff0c;它由多个库组成&#xff0c;用于加速在各种 CPU 架构上运行的数据包处理。 网络性能、吞吐量和延迟对于各种应用程序至关重要&#xff0c;包括无线和有线基础设施、路由器、负载均衡…

2024年【防爆电气】考试题库及防爆电气复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 防爆电气考试题库根据新防爆电气考试大纲要求&#xff0c;安全生产模拟考试一点通将防爆电气模拟考试试题进行汇编&#xff0c;组成一套防爆电气全真模拟考试试题&#xff0c;学员可通过防爆电气复审模拟考试全真模拟…

基于Java+SpringBoot+Vue+MySQL的高校大学生迎新管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的高校大学生迎新管理系统【附源码文档】…

828华为云征文 | Flexus X 实例服务器网络性能深度评测

引言 随着互联网应用的快速发展&#xff0c;网络带宽和性能对云服务器的表现至关重要。在不同的云服务平台上&#xff0c;即便配置相同的带宽&#xff0c;实际的网络表现也可能有所差异。因此&#xff0c;了解并测试服务器的网络性能变得尤为重要。本文将以华为云X实例服务器为…

【NumPy】基础知识

NumPy是Python的第三方库&#xff0c;要使用需要先导入。 import numpy as np 在pycharm中可以通过np.来查看numpy的可用函数。 np.函数名? 查看对应函数的详细信息。 生成NumPy数组 ndarray 多维数组对象 numpy封装了一个新的数据类型ndarray&#xff0c;是一个多维数组对…

图论篇--代码随想录算法训练营第五十三天打卡| 110. 字符串接龙,105.有向图的完全可达性,106. 岛屿的周长

110. 字符串接龙 题目链接&#xff1a;110. 字符串接龙 题目描述&#xff1a; 字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列&#xff1a; 序列中第一个字符串是 beginStr。序列中最后一个字符串是 endStr。 每次转换只能改变一个字符…

解决报错:java.lang.NumberFormatException: Cannot parse null string

最近在做javaweb项目&#xff0c;整了一整天&#xff0c;代码翻来覆去反复看&#xff0c;就是没看出问题&#xff0c;没承想问题是出在编码上&#xff0c;我服了&#xff01;我就知道我代码逻辑没问题。 把enctype"multipart/form-data"删掉&#xff0c;就好了... 这…

自然语言处理系列六十三》神经网络算法》LSTM长短期记忆神经网络算法

注&#xff1a;此文章内容均节选自充电了么创始人&#xff0c;CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》&#xff08;人工智能科学与技术丛书&#xff09;【陈敬雷编著】【清华大学出版社】 文章目录 自然语言处理系列六十三神经网络算法》LSTM长短期记忆神经网络算…

【C++多线程编程】 线程安全与对象生命周期管理

目录 类的线程安全 实现线程安全 构造函数在多线程中的安全性 析构函数多线程环境的安全 智能指针实现多线程安全 shared_ptr 非完全线程安全 shared_ptr可能导致对象生命周期延长 const引用可以减少传递shared_ptr开销 shared_ptr 智能指针块模块的优点 析构所在线程…

前端核心基础知识总结

目录 前言 一、HTML模块 1. 标签结构 2. 语义化标签 3. 表单元素 二、CSS模块 1. 选择器 2. 盒模型 示例一&#xff1a;为一个div标签设置了宽度为 200 像素&#xff0c;高度为 100 像素的内容区。 示例二&#xff1a;内边距的存在可以使内容与边框之间有一定的间隔&…

数字化转型专家讲师培训师唐兴通中欧国际工商学院数字化转型战略与实现路径AIGC人工智能数字化战略数字商业模式创新

《数字化转型战略与实现路径》 课程内容与收益 本课程的目标是通过深入的学习来帮助学员全面地了解数字化转型的概念和实现路径&#xff0c;掌握数字化转型的各种方法和技巧&#xff0c;进而提升数字化转型的能力和水平&#xff0c;从而使企业更具有竞争力。在这个课程中&…

《黑神话悟空》永冻流出装如何装备!!

整体玩法是通过法宝芭蕉扇打出控制后&#xff0c;再用化身技打出冰冻&#xff0c;冰冻期间用棍花持续输出&#xff0c;同时积攒元气和棍势&#xff0c;在利用三或四棍势打出一波爆发输出&#xff0c;基本上一套打完元气又满了&#xff0c;可以再放下一次控制&#xff0c;如此循…