摘要:CPUP(Central Processing Unit Percentage,CPU占用率)分為系統CPU占用率和任務CPU占用率。用戶通過系統級的CPU占用率,判斷當前系統負載是否超出設計規格。通過系統中各個任務的CPU占用情況,判斷各個任務的CPU占用率是否符合設計的預期。
本文分享自華為雲社區《鴻蒙輕內核M核源碼分析系列十五 CPU使用率CPUP (1)》,作者:zhushy。
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; } ⑷ 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對外接口
我們先分析下外部接口,接口說明如下:
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擴展模塊的源代碼。感謝閱讀,如有任何問題、建議,都可以博客下留言給我,謝謝。