/* ----------------------------------------------------------------------------
 * Copyright (c) Huawei Technologies Co., Ltd. 2013-2020. All rights reserved.
 * Description : LiteOS Cpu Usage Calculation Module Implementation
 * Author: Huawei LiteOS Team
 * Create: 2013-01-01
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --------------------------------------------------------------------------- */

#include "los_cpup_pri.h"
#include "los_task_pri.h"
#include "los_base.h"
#include "los_swtmr.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */

#ifdef LOSCFG_KERNEL_CPUP

LITE_OS_SEC_BSS STATIC UINT16 g_cpupSwtmrId;        //用于记录CPU使用率统计定时器的ID//
LITE_OS_SEC_BSS STATIC UINT16 g_cpupInitFlg = 0;    //用于标记CPU使用率模块是否已经初始化//
LITE_OS_SEC_BSS OsCpupCB *g_cpup = NULL;            //用于保存CPU使用率相关的信息//
LITE_OS_SEC_BSS STATIC UINT16 g_cpupMaxNum;         //表示CPU使用率统计信息的最大数量//
LITE_OS_SEC_BSS STATIC UINT16 g_cpupTaskMaxNum;     //表示CPU使用率统计信息的最大任务数量//
LITE_OS_SEC_BSS STATIC UINT16 g_hisPos = 0; /* current Sampling point of historyTime */
LITE_OS_SEC_DATA_INIT STATIC UINT32 runningTasks[LOSCFG_KERNEL_CORE_NUM] = {
    [0 ... (LOSCFG_KERNEL_CORE_NUM - 1)] = (UINT32)-1
};                                                  //用于记录每个核心上正在运行的任务的ID//
LITE_OS_SEC_BSS STATIC UINT64 cpuHistoryTime[OS_CPUP_HISTORY_RECORD_NUM + 1];
                                                    //用于保存CPU历史时间记录//
LITE_OS_SEC_BSS STATIC UINT64 g_startCycles = 0;    //用于记录任务切换前的时钟周期数//
#ifdef LOSCFG_CPUP_INCLUDE_IRQ                      //用于判断是否包含中断相关的功能//
//若满足条件编译//
LITE_OS_SEC_BSS UINT64 g_timeInIrqPerTskSwitch[LOSCFG_KERNEL_CORE_NUM]; //用于记录每个核心上任务切换期间发生的中断的时间//
LITE_OS_SEC_BSS STATIC UINT64 g_intTimeStart[LOSCFG_KERNEL_CORE_NUM];   //用于记录每个核心上中断开始的时间//
#endif

#define HIGH_BITS 32

#define CPUP_PRE_POS(pos) (((pos) == 0) ? (OS_CPUP_HISTORY_RECORD_NUM - 1) : ((pos) - 1))
#define CPUP_POST_POS(pos) (((pos) == (OS_CPUP_HISTORY_RECORD_NUM - 1)) ? 0 : ((pos) + 1))

LITE_OS_SEC_TEXT_INIT OsCpupCB *OsCpupCBGet(UINT32 index)
{
    return &g_cpup[index];
}

/*定期更新历史时间采样点和任务的历史运行时间，以便后续计算CPU使用率*/
LITE_OS_SEC_TEXT_INIT VOID OsCpupGuard(VOID)
{
    UINT16 prevPos = g_hisPos;
    UINT16 loop;
    UINT16 runTaskId;
    UINT64 curCycle;
    UINT32 intSave;

    if (g_cpupInitFlg == 0) {   //表示CPU使用率模块尚未初始化，直接返回//
        return;
    }
    //若已初始化，则禁止中断，并获取当前时钟周期数//
    intSave = LOS_IntLock();
    curCycle = OsCpupGetCycle();

    g_hisPos = CPUP_POST_POS(g_hisPos); //更新历史时间采样点的位置//
    cpuHistoryTime[prevPos] = curCycle; //记录本次采样的时钟周期数//

/*更新每个任务和CPU核心的历史运行时间*/
    for (loop = 0; loop < g_cpupMaxNum; loop++) {
        g_cpup[loop].historyTime[prevPos] = g_cpup[loop].allTime;
    }

    for (loop = 0; loop < LOSCFG_KERNEL_CORE_NUM; loop++) {
        runTaskId = runningTasks[loop];             //获取该任务在当前核心上的ID//
        /* reacquire the cycle to prevent flip */
        curCycle = OsCpupGetCycle();
        /*将该任务从开始到当前时刻所用的时钟周期数加入该任务在历史时间采样点上的历史运行时间中*/
        g_cpup[runTaskId].historyTime[prevPos] += curCycle - g_cpup[runTaskId].startTime;
#ifdef LOSCFG_CPUP_INCLUDE_IRQ  //判断中断功能是否被包含在配置中//
       /*从该任务的历史运行时间中减去该任务在任务切换期间发生的中断所用的时间*/
        g_cpup[runTaskId].historyTime[prevPos] -= g_timeInIrqPerTskSwitch[loop];
#endif
    }

    LOS_IntRestore(intSave);    //恢复中断状态//
}

/*创建一个软件定时器，以便定期更新历史时间采样点和任务的历史运行时间，从而实现CPU使用率的统计*/  
LITE_OS_SEC_TEXT_INIT VOID OsCpupGuardCreator(VOID)
{
    /*下面函数的参数分别为*/
    //设定定时器的周期是每秒钟的基本核心时钟滴答数//
    //工作模式为周期模式//
    //回调函数//
    //定时器ID保存在g_cpupSwtmrId变量中//
    //最后一个参数为0表示不携带额外参数//
    (VOID)LOS_SwtmrCreate(LOSCFG_BASE_CORE_TICK_PER_SECOND, LOS_SWTMR_MODE_PERIOD,
                          (SWTMR_PROC_FUNC)OsCpupGuard, &g_cpupSwtmrId, 0);

    (VOID)LOS_SwtmrStart(g_cpupSwtmrId);    //启动该软件定时器//
}

/*初始化CPU使用率统计模块，其中包括创建一个最高优先级的任务，
该任务的入口函数为OsCpupGuardCreator，
用于创建和启动周期性调用OsCpupGuard()函数的软件定时器*/
LITE_OS_SEC_TEXT_INIT VOID OsCpupGuardInit(VOID)
{
    TSK_INIT_PARAM_S taskInitParam;
    UINT32 tempId;
    //初始化taskInitParam，并将其内容清零//
    (VOID)memset_s((void *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
    taskInitParam.pfnTaskEntry  = (TSK_ENTRY_FUNC)OsCpupGuardCreator;   //指定任务入口函数为OsCpupGuardCreator，即创建和启动软件定时器的函数//
    taskInitParam.uwStackSize   = LOS_TASK_MIN_STACK_SIZE;  //指定任务栈的大小为最小任务栈大小//
    taskInitParam.pcName        = "CpupGuardCreator";   //指定任务的名称为"CpupGuardCreator"//
    taskInitParam.usTaskPrio    = OS_TASK_PRIORITY_HIGHEST; //指定任务的优先级为最高优先级//
    taskInitParam.uwResved      = LOS_TASK_STATUS_DETACHED;    //指定任务状态为LOS_TASK_STATUS_DETACHED//
#ifdef LOSCFG_KERNEL_SMP    //判断操作系统是否支持多核//
    taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());  //设置任务的CPU亲和性掩码//
#endif
    /*传入上述初始化好的参数taskInitParam，并将任务ID保存在tempId中*/
    (VOID)LOS_TaskCreate(&tempId, &taskInitParam);
}

/*
 * Description: initialization of CPUP
 * Return     : LOS_OK or Error Information
 */
LITE_OS_SEC_TEXT_INIT UINT32 OsCpupInit(VOID)   
{
    UINT32 size;

    g_cpupTaskMaxNum = g_taskMaxNum;
    g_cpupMaxNum = g_cpupTaskMaxNum;
/*如果配置了包含中断的CPU使用率统计（LOSCFG_CPUP_INCLUDE_IRQ），
则将g_cpupMaxNum增加LOSCFG_PLATFORM_HWI_LIMIT*/
#ifdef LOSCFG_CPUP_INCLUDE_IRQ
    g_cpupMaxNum += LOSCFG_PLATFORM_HWI_LIMIT;
#endif

    /* every task has only one record, and it won't operated at the same time */
    size = g_cpupMaxNum * sizeof(OsCpupCB); //计算需要分配的内存空间大小//
    g_cpup = (OsCpupCB *)LOS_MemAlloc(m_aucSysMem0, size);  //分配内存，用于存储OsCpupCB结构体数组//
    if (g_cpup == NULL) {   //内存分配失败//
        return LOS_ERRNO_CPUP_NO_MEMORY;
    }

    OsCpupGuardInit();  //初始化CPU使用率统计模块//

    (VOID)memset_s(g_cpup, size, 0, size);  //将分配的内存空间清零//
    g_cpupInitFlg = 1;                      //表示CPU使用率统计模块已经初始化完成//

    return LOS_OK;  //初始化成功//
}

LITE_OS_SEC_TEXT_INIT VOID LOS_CpupReset(VOID)  //用于重置CPU使用率统计模块//
{
    UINT32 cpupIndex;
    UINT32  maxNum = g_cpupMaxNum;
    UINT64 curCycle;
    UINT16 loop;
    UINT32 intSave;

    /*检查全局变量g_cpup是否为NULL，如果是，则直接返回，不执行任何操作*/
    if (g_cpup == NULL) {
        return;
    }

    g_cpupInitFlg = 0;  //表示CPU使用率统计模块未初始化//
    intSave = LOS_IntLock();    //锁定中断，防止在重置过程中发生中断//
    (VOID)LOS_SwtmrStop(g_cpupSwtmrId); //停止CPU使用率统计定时器//
    curCycle = OsCpupGetCycle();        //获取当前的CPU周期数//

    /*将cpuHistoryTime数组中的所有元素都设置为curCycle，清空历史时间记录*/
    for (loop = 0; loop < (OS_CPUP_HISTORY_RECORD_NUM + 1); loop++) {
        cpuHistoryTime[loop] = curCycle;
    }

    /*遍历每个CPU使用率统计结构体，
    并将其起始时间和总时间都设置为curCycle，
    同时清空每个结构体中的历史时间记录*/
    for (cpupIndex = 0; cpupIndex < maxNum; cpupIndex++) {
        g_cpup[cpupIndex].startTime = curCycle;
        g_cpup[cpupIndex].allTime = curCycle;
        for (loop = 0; loop < (OS_CPUP_HISTORY_RECORD_NUM + 1); loop++) {
            g_cpup[cpupIndex].historyTime[loop] = curCycle;
        }
    }

/*如果配置了包含中断的CPU使用率统计，
则将g_timeInIrqPerTskSwitch数组中的所有元素都设置为0，
用于记录任务切换期间的中断时间*/
#ifdef LOSCFG_CPUP_INCLUDE_IRQ
    for (loop = 0; loop < LOSCFG_KERNEL_CORE_NUM; loop++) {
        g_timeInIrqPerTskSwitch[loop] = 0;
    }
#endif

    (VOID)LOS_SwtmrStart(g_cpupSwtmrId);    //重新启动CPU使用率统计定时器//
    LOS_IntRestore(intSave);                //恢复中断状态//
    g_cpupInitFlg = 1;                      //表示CPU使用率统计模块已经重新初始化完成//

    return;
}

/*用于设置CPU周期数起始值，以便后面记录时间时
能够正确计算CPU周期数的差值，从而得到时间间隔*/
LITE_OS_SEC_TEXT_MINOR VOID OsCpupSetCycle(UINT64 startCycles) 
{
    g_startCycles = startCycles;
    return;
}

/*
 * Description: get current cycles count
 * Return     : current cycles count
 */
LITE_OS_SEC_TEXT_MINOR UINT64 OsCpupGetCycle(VOID)
{
    UINT32 high;
    UINT32 low;
    UINT64 cycles;

    LOS_GetCpuCycle(&high, &low);
    cycles = ((UINT64)high << HIGH_BITS) + low;     //将高位和低位的计数值合并成一个64位计数值//
    if (g_startCycles == 0) {
        g_startCycles = cycles;
    }

    /*
     * The cycles should keep growing, if the checking failed,
     * it mean LOS_GetCpuCycle has the problem which should be fixed.
     */
    LOS_ASSERT(cycles >= g_startCycles);

    return (cycles - g_startCycles);
}

/*
 * Description: start task to get cycles count in current task beginning
 */
LITE_OS_SEC_TEXT_MINOR VOID OsTaskCycleStart(VOID)  //用于在任务开始时获取CPU周期计数//
{
    UINT32 taskId;
    LosTaskCB *runTask = NULL;

    if (g_cpupInitFlg == 0) {   //如果为0则表示还未进行CPU周期计数的初始化，直接返回//
        return;
    }

    runTask = OsCurrTaskGet();  //获取当前正在运行的任务//
    taskId = runTask->taskId;   //获取当前任务的ID//

    g_cpup[taskId].id = taskId;
    g_cpup[taskId].startTime = OsCpupGetCycle();

    return;
}

/*
 * Description: quit task and get cycle count
 */
LITE_OS_SEC_TEXT_MINOR VOID OsTaskCycleEnd(VOID)
{
    UINT32 taskId;
    UINT64 cpuCycle;
    LosTaskCB *runTask = NULL;

    if (g_cpupInitFlg == 0) {
        return;
    }

    runTask = OsCurrTaskGet();
    taskId = runTask->taskId;

    if (g_cpup[taskId].startTime == 0) {    //判断是否已经记录了任务的开始时间，//
        return;                             //若为0则表示未记录开始时间，直接返回//
    }

    cpuCycle = OsCpupGetCycle();
    g_cpup[taskId].allTime += cpuCycle - g_cpup[taskId].startTime;  //获取任务从开始到结束的CPU周期数//

#ifdef LOSCFG_CPUP_INCLUDE_IRQ  //如果开启了包含中断处理时间的统计，需要对任务的总运行时间进行修正//
    UINT32 cpuId = ArchCurrCpuid();
    g_cpup[taskId].allTime -= g_timeInIrqPerTskSwitch[cpuId];   //减去当前CPU核心上中断处理所占用的时间
    g_timeInIrqPerTskSwitch[cpuId] = 0;
#endif
    g_cpup[taskId].startTime = 0;   //表示任务的运行时间统计结束//

    return;
}

/*
 * Description: start task to get cycles count in current task ending
 */
LITE_OS_SEC_TEXT_MINOR VOID OsTaskCycleEndStart(const LosTaskCB *newTask)
{
    UINT64 cpuCycle;
    LosTaskCB *runTask = NULL;
    OsCpupCB *cpup = NULL;
    UINT32 cpuId = ArchCurrCpuid();

    if ((g_cpupInitFlg == 0) || (newTask == NULL)) {
        return;
    }

    runTask = OsCurrTaskGet();
    cpuCycle = OsCpupGetCycle();

    cpup = &g_cpup[runTask->taskId];
    if (cpup->startTime != 0) {
        cpup->allTime += cpuCycle - cpup->startTime;    //表示该任务之前已经开始了CPU周期计数，需要对其总运行时间进行更新//
#ifdef LOSCFG_CPUP_INCLUDE_IRQ      //根据是否满足条件配置，对总运行时间进行修正//
        cpup->allTime -= g_timeInIrqPerTskSwitch[cpuId];
        g_timeInIrqPerTskSwitch[cpuId] = 0;
#endif
    }

    cpup = &g_cpup[newTask->taskId];
    /*将新任务的ID和当前CPU周期计数值保存，表示新任务的CPU周期计数开始*/
    cpup->id = newTask->taskId;
    cpup->startTime = cpuCycle;
    runningTasks[cpuId] = newTask->taskId;  //更新当前CPU核心上正在运行的任务ID//

    return;
}

/*用于获取CPU周期计数数据在数组中的位置*/
LITE_OS_SEC_TEXT_MINOR STATIC VOID OsCpupGetPos(UINT32 mode, UINT16 *curPosPointer, UINT16 *prePosPointer)
{
    UINT16 curPos;
    UINT16 tmpPos;
    UINT16 prePos;

    tmpPos = g_hisPos;              //获取当前位置//
    curPos = CPUP_PRE_POS(tmpPos);  //获取前一个位置//

    /*
     * The current position has nothing to do with the CPUP modes,
     * however, the previous position differs.
     */
    switch (mode) {
        /*表示需要获取最近一秒内的CPU周期计数数据，
        此时将前一个位置设置为当前位置的前一个位置*/
        case CPUP_LAST_ONE_SECONDS:
            prePos = CPUP_PRE_POS(curPos);
            break;
        /*表示需要获取最近十秒内的CPU周期计数数据，
        此时将前一个位置设置为当前位置*/
        case CPUP_LAST_TEN_SECONDS:
            prePos = tmpPos;
            break;
        /*表示需要获取所有时间内的CPU周期计数数据，
        此时将前一个位置设置为数组的最后一个位置*/
        case CPUP_ALL_TIME:
            /* fall-through */
        default:
            prePos = OS_CPUP_HISTORY_RECORD_NUM;
            break;
    }

    *curPosPointer = curPos;    //保存当前位置//
    *prePosPointer = prePos;    //保存前一个位置//

    return;
}

/*用于检查CPU使用率统计参数的合法性*/
LITE_OS_SEC_TEXT_MINOR STATIC INLINE UINT32 OsCpuUsageParaCheck(UINT32 taskId)
{
    if (g_cpupInitFlg == 0) {
        return LOS_ERRNO_CPUP_NO_INIT;
    }

    if (OS_TSK_GET_INDEX(taskId) >= g_taskMaxNum) {     //任务ID索引值超过了最大任务数，//
        return LOS_ERRNO_CPUP_TSK_ID_INVALID;           //表示任务ID无效，返回错误码//
    }

    /* weather the task is created */
    if (g_cpup[taskId].id != 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;        //表示该任务尚未创建，返回错误码//
    }

    return LOS_OK;  //表示通过检查//
}

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_HistorySysCpuUsage(UINT32 mode)   //用于获取历史系统CPU使用率//
{
    UINT64 cpuCycleAll;
    UINT64 idleCycleAll = 0;
    UINT32 cpup = 0;
    UINT16 pos;
    UINT16 prePos;
    UINT32 intSave;
    UINT32 idleTaskId;
#ifdef LOSCFG_KERNEL_SMP
    UINT32 cpuId = 0;
#endif

    if (g_cpupInitFlg == 0) {
        return LOS_ERRNO_CPUP_NO_INIT;
    }

    /* get end time of current task */
    intSave = LOS_IntLock();    //锁定中断状态//
    OsTaskCycleEnd();       //获取当前任务的结束时间//

    OsCpupGetPos(mode, &pos, &prePos);  //获取历史CPU使用率数据的位置信息//
    cpuCycleAll = cpuHistoryTime[pos] - cpuHistoryTime[prePos]; //计算CPU的总周期数//

#ifdef LOSCFG_KERNEL_SMP    //判断是否为SMP系统//
    /* For SMP system, each idle task needs to be accounted */
    while (cpuId < LOSCFG_KERNEL_CORE_NUM) {
        idleTaskId = g_percpu[cpuId].idleTaskId;
        //累加各核心的空闲任务的周期数到idleCycleAll中//
        idleCycleAll += g_cpup[idleTaskId].historyTime[pos] - g_cpup[idleTaskId].historyTime[prePos];
        cpuId++;
    }
    cpuCycleAll *= LOSCFG_KERNEL_CORE_NUM;
#else
    idleTaskId = OsGetIdleTaskId(); //直接获取空闲任务的周期数。//
    idleCycleAll = g_cpup[idleTaskId].historyTime[pos] - g_cpup[idleTaskId].historyTime[prePos];
#endif

    if (cpuCycleAll) {
        cpup = (LOS_CPUP_PRECISION - (UINT32)((LOS_CPUP_PRECISION * idleCycleAll) / cpuCycleAll));
    }       //得出CPU使用率//

    OsTaskCycleStart();     //重新开始任务的时间统计//
    LOS_IntRestore(intSave);    //恢复中断状态//

    return cpup;
}

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_HistoryTaskCpuUsage(UINT32 taskId, UINT32 mode)
{
    UINT64 cpuCycleAll;
    UINT64 cpuCycleCurTask;
    UINT16 pos;
    UINT16 prePos;
    UINT32 intSave;
    UINT32 cpup = 0;
    UINT32 ret;

    if (g_cpupInitFlg == 0) {
        return LOS_ERRNO_CPUP_NO_INIT;
    }

    //对传入的任务ID进行参数检查，检查结果不等于LOS_OK，则返回相应的错误码//
    ret = OsCpuUsageParaCheck(taskId);
    if (ret != LOS_OK) {
        return ret;
    }
    OsCpupCB *taskCpup = &g_cpup[taskId];

    intSave = LOS_IntLock();
    OsTaskCycleEnd();

    OsCpupGetPos(mode, &pos, &prePos);      //获取历史CPU使用率数据的位置信息//
    cpuCycleAll = cpuHistoryTime[pos] - cpuHistoryTime[prePos]; //计算CPU的总周期数//
    cpuCycleCurTask = taskCpup->historyTime[pos] - taskCpup->historyTime[prePos];   //计算当前任务的CPU周期数//
    if (cpuCycleAll) {
        cpup = (UINT32)((LOS_CPUP_PRECISION * cpuCycleCurTask) / cpuCycleAll);
    }   //计算得出CPU使用率//

    OsTaskCycleStart();
    LOS_IntRestore(intSave);

    return cpup;
}

//用于获取所有任务历史CPU使用率//
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_AllCpuUsage(UINT16 maxNum, CPUP_INFO_S *cpupInfo, UINT32 mode, UINT16 flag)
{
    UINT16 loop;
    UINT16 pos;
    UINT16 prePos;
    UINT32 intSave;
    UINT64 cpuCycleAll;
    UINT64 cpuCycleCurTask;
    UINT16 numTmpMax = maxNum;
    UINT16 numTmpMin = 0;
    UINT16 numMax = g_cpupTaskMaxNum;

    if (g_cpupInitFlg == 0) {
        return  LOS_ERRNO_CPUP_NO_INIT;
    }

    if (cpupInfo == NULL) { //检查传入的指针cpupInfo是否为空，如果为空，返回错误码//
        return LOS_ERRNO_CPUP_TASK_PTR_NULL;
    }

    if (maxNum == 0) {  //检查传入的maxNum是否等于0，如果等于0，返回错误码//
        return  LOS_ERRNO_CPUP_MAXNUM_INVALID;
    }

#ifdef LOSCFG_CPUP_INCLUDE_IRQ      //如果宏被定义//
    if (flag == 0) {
        numTmpMax += g_cpupTaskMaxNum;
        numTmpMin += g_cpupTaskMaxNum;
        numMax = g_cpupMaxNum;
    }
#endif

    if (numTmpMax > numMax) {
        numTmpMax = numMax;
    }

    intSave = LOS_IntLock();
    OsTaskCycleEnd();

    OsCpupGetPos(mode, &pos, &prePos);  //获取历史CPU使用率数据的位置信息//
    cpuCycleAll = cpuHistoryTime[pos] - cpuHistoryTime[prePos]; //计算CPU的总周期数//

    /*通过循环遍历所有任务的CPU使用率数据，计算当前任务的CPU周期数并保存*/
    for (loop = numTmpMin; loop < numTmpMax; loop++) {
        if ((g_cpup[loop].status & OS_TASK_STATUS_UNUSED) || (g_cpup[loop].status == 0)) {
            continue;
        }

        cpuCycleCurTask = g_cpup[loop].historyTime[pos] - g_cpup[loop].historyTime[prePos];
        cpupInfo[loop - numTmpMin].usStatus = g_cpup[loop].status;

        if (cpuCycleAll) {
            cpupInfo[loop - numTmpMin].uwUsage = (UINT32)((LOS_CPUP_PRECISION * cpuCycleCurTask) / cpuCycleAll);
        }
    }

    OsTaskCycleStart();
    LOS_IntRestore(intSave);

    return LOS_OK;
}

#ifdef LOSCFG_CPUP_INCLUDE_IRQ
/*用于在中断开始时记录当前的时钟周期数，以便于后续做中断处理时间的统计和分析*/
LITE_OS_SEC_TEXT_MINOR VOID OsCpupIrqStart(VOID)
{
    g_intTimeStart[ArchCurrCpuid()] = OsCpupGetCycle();
    return;
}

/*在中断结束时进行统计操作，
包括记录中断号、更新中断期间任务切换的时间以及累加中断期间的总时间*/
LITE_OS_SEC_TEXT_MINOR VOID OsCpupIrqEnd(UINT32 intNum)
{
    UINT64 intTimeEnd = OsCpupGetCycle();   //获取当前的时钟周期数//
    UINT32 cpuId = ArchCurrCpuid();         //获取当前CPU的ID//

    if (g_cpupInitFlg == 0) {
        return;
    }

    g_cpup[g_taskMaxNum + intNum].id = intNum;
    g_cpup[g_taskMaxNum + intNum].status = OS_TASK_STATUS_RUNNING;  //将中断状态设为运行中//
    g_timeInIrqPerTskSwitch[cpuId] += (intTimeEnd - g_intTimeStart[cpuId]); //增加中断期间任务切换所消耗的时间//
    g_cpup[g_taskMaxNum + intNum].allTime += (intTimeEnd - g_intTimeStart[cpuId]);

    return;
}
#endif

#endif /* LOSCFG_KERNEL_CPUP */
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */

