From 2178a790e5eacec1853b8102ca3e47cb7ba9e383 Mon Sep 17 00:00:00 2001 From: he <1429721469@qq.com> Date: Sun, 3 Dec 2023 23:28:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=95=E4=BD=B3=E8=81=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../extended/.vscode/c_cpp_properties.json | 18 ++ src/kernel/extended/.vscode/launch.json | 24 ++ src/kernel/extended/.vscode/settings.json | 59 +++++ src/kernel/extended/lowpower/los_lowpower.c | 38 +-- .../lowpower/powermgr/los_lowpower_impl.c | 222 ++++++++++-------- .../lowpower/runstop/src/los_runstop.c | 141 +++++++---- .../extended/lowpower/tickless/los_tickless.c | 31 ++- src/kernel/extended/perf/los_perf.c | 101 ++++---- src/kernel/extended/perf/perf_output.c | 22 +- src/kernel/extended/perf/perf_output_pri.h | 14 +- src/kernel/extended/perf/perf_pmu.c | 13 +- src/kernel/extended/perf/perf_pmu_pri.h | 38 +-- src/kernel/extended/perf/pmu/perf_hw_pmu.c | 50 ++-- src/kernel/extended/perf/pmu/perf_sw_pmu.c | 20 +- src/kernel/extended/perf/pmu/perf_timed_pmu.c | 40 ++-- ...代码阅读(初稿)-何佳聪-.docx | Bin 0 -> 14017 bytes 16 files changed, 505 insertions(+), 326 deletions(-) create mode 100644 src/kernel/extended/.vscode/c_cpp_properties.json create mode 100644 src/kernel/extended/.vscode/launch.json create mode 100644 src/kernel/extended/.vscode/settings.json create mode 100644 src/kernel/extended/软件工程代码阅读(初稿)-何佳聪-.docx diff --git a/src/kernel/extended/.vscode/c_cpp_properties.json b/src/kernel/extended/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..b1880ec --- /dev/null +++ b/src/kernel/extended/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "windows-gcc-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "D:/mingw64/bin/gcc.exe", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "windows-gcc-x64", + "compilerArgs": [ + "" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/src/kernel/extended/.vscode/launch.json b/src/kernel/extended/.vscode/launch.json new file mode 100644 index 0000000..f78275c --- /dev/null +++ b/src/kernel/extended/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "externalConsole": true, + "cwd": "h:/ruanjian/LiteOS-Reading/src/kernel/extended/perf/pmu", + "program": "h:/ruanjian/LiteOS-Reading/src/kernel/extended/perf/pmu/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/src/kernel/extended/.vscode/settings.json b/src/kernel/extended/.vscode/settings.json new file mode 100644 index 0000000..3e5eb95 --- /dev/null +++ b/src/kernel/extended/.vscode/settings.json @@ -0,0 +1,59 @@ +{ + "C_Cpp_Runner.cCompilerPath": "gcc", + "C_Cpp_Runner.cppCompilerPath": "g++", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false +} \ No newline at end of file diff --git a/src/kernel/extended/lowpower/los_lowpower.c b/src/kernel/extended/lowpower/los_lowpower.c index bd9dde0..2a19c3e 100644 --- a/src/kernel/extended/lowpower/los_lowpower.c +++ b/src/kernel/extended/lowpower/los_lowpower.c @@ -25,7 +25,7 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --------------------------------------------------------------------------- */ - + /*低功耗管理*/ #include "los_lowpower_pri.h" #ifdef LOSCFG_KERNEL_TICKLESS #include "los_tickless_pri.h" @@ -36,10 +36,10 @@ __attribute__((section(".data"))) STATIC const PowerMgrOps *g_pmOps = NULL; -VOID OsLowpowerInit(const PowerMgrOps *pmOps) +VOID OsLowpowerInit(const PowerMgrOps *pmOps) /*初始化低功耗管理*/ { if (pmOps == NULL) { -#ifdef LOSCFG_KERNEL_POWER_MGR +#ifdef LOSCFG_KERNEL_POWER_MGR/*是否配置了低功耗内核管理*/ PRINT_ERR("\r\n [PM] PowerMgrOps must be non-null.\n"); return; #endif @@ -48,34 +48,34 @@ VOID OsLowpowerInit(const PowerMgrOps *pmOps) return; } - if (g_pmOps != NULL) { + if (g_pmOps != NULL) { PRINT_ERR("\r\n [PM] Reassignment of PowerMgrOps is forbidden.\n"); return; } g_pmOps = pmOps; LOS_LowpowerHookReg(OsPowerMgrProcess); - + /*注册低功耗处理函数和终端唤醒处理函数*/ LOS_IntWakeupHookReg(OsPowerMgrWakeUpFromInterrupt); } -VOID OsPowerMgrProcess(VOID) +VOID OsPowerMgrProcess(VOID) /*执行低功耗管理的处理过程*/ { -#ifdef LOSCFG_KERNEL_POWER_MGR +#ifdef LOSCFG_KERNEL_POWER_MGR/*判断是否配置了内核低功耗管理*/ CALL_PMOPS_FUNC_VOID(process); #else - if (g_pmOps == NULL) { + if (g_pmOps == NULL) { #ifdef LOSCFG_KERNEL_TICKLESS OsTicklessOpen(); - wfi(); + wfi(); /*管理进程进入睡眠状态*/ #endif } else { - CALL_PMOPS_FUNC_VOID(process); + CALL_PMOPS_FUNC_VOID(process);/*执行低功耗管理*/ } #endif } -VOID OsPowerMgrWakeUpFromInterrupt(UINT32 intNum) +VOID OsPowerMgrWakeUpFromInterrupt(UINT32 intNum) /*从中断唤醒处理*/ { #ifdef LOSCFG_KERNEL_POWER_MGR CALL_PMOPS_FUNC_VOID(resumeFromInterrupt, intNum); @@ -90,44 +90,44 @@ VOID OsPowerMgrWakeUpFromInterrupt(UINT32 intNum) #endif } -VOID OsPowerMgrWakeupFromReset(VOID) +VOID OsPowerMgrWakeupFromReset(VOID) /*从复位唤醒处理*/ { CALL_PMOPS_FUNC_VOID(wakeupFromReset); } -VOID LOS_PowerMgrChangeFreq(LosFreqMode freq) +VOID LOS_PowerMgrChangeFreq(LosFreqMode freq)/*改变系统频率*/ { CALL_PMOPS_FUNC_VOID(changeFreq, freq); } -VOID LOS_PowerMgrDeepSleepVoteBegin(VOID) +VOID LOS_PowerMgrDeepSleepVoteBegin(VOID)/*开始深度睡眠设置*/ { CALL_PMOPS_FUNC_VOID(deepSleepVoteBegin); } -VOID LOS_PowerMgrDeepSleepVoteEnd(VOID) +VOID LOS_PowerMgrDeepSleepVoteEnd(VOID)/*结束深度睡眠状态*/ { CALL_PMOPS_FUNC_VOID(deepSleepVoteEnd); } -VOID LOS_PowerMgrSleepDelay(UINT32 tick) +VOID LOS_PowerMgrSleepDelay(UINT32 tick)/*延迟进入睡眠状态*/ { CALL_PMOPS_FUNC_VOID(deepSleepVoteDelay, tick); } -VOID LOS_PowerMgrRegisterExtVoter(UINT32 (*callback)(VOID)) +VOID LOS_PowerMgrRegisterExtVoter(UINT32 (*callback)(VOID))/*注册外部投票者*/ { CALL_PMOPS_FUNC_VOID(registerExternalVoter, callback); } -UINT32 LOS_PowerMgrGetSleepMode(VOID) +UINT32 LOS_PowerMgrGetSleepMode(VOID)/*获取睡眠模式*/ { UINT32 ret = 0; CALL_PMOPS_FUNC_RET(getSleepMode, ret); return ret; } -UINT32 LOS_PowerMgrGetDeepSleepVoteCount(VOID) +UINT32 LOS_PowerMgrGetDeepSleepVoteCount(VOID)/*获取深度睡眠的投票计数*/ { UINT32 ret = 0; CALL_PMOPS_FUNC_RET(getDeepSleepVoteCount, ret); diff --git a/src/kernel/extended/lowpower/powermgr/los_lowpower_impl.c b/src/kernel/extended/lowpower/powermgr/los_lowpower_impl.c index 0f8cc28..78f5f94 100644 --- a/src/kernel/extended/lowpower/powermgr/los_lowpower_impl.c +++ b/src/kernel/extended/lowpower/powermgr/los_lowpower_impl.c @@ -44,7 +44,7 @@ #endif #if defined(LOSCFG_KERNEL_RUNSTOP) || defined(LOSCFG_KERNEL_DEEPSLEEP) -/* Is system is up from the memory image, then this flag should be 1; else 0 */ +/* 如果系统是从内存映像中启动的,则该标志应为1;否则为0。*/ #ifdef LOSCFG_AARCH64 __attribute__((section(".data"))) INT64 g_resumeFromImg = LOS_COLD_RESET; __attribute__((section(".data"))) STATIC INT64 g_otherCoreResume = 0; @@ -55,8 +55,8 @@ __attribute__((section(".data"))) INT32 g_otherCoreResume = 0; #ifdef LOSCFG_AARCH64 /* - * 16: The number of aligned memory, - * 34: The number of task context registers(X0~X30, SP, DAIF, NZCV) + * 16: 对齐内存的数量, + * 34: 任务上下文寄存器的数量,指寄存器的集合(X0~X30, SP, DAIF, NZCV) */ LITE_OS_SEC_DATA_MINOR __attribute__((aligned(16))) UINT64 g_saveSRContext[34]; /* 3: The number of available universal registers(X0, X1, X2) temporarily saved */ @@ -161,24 +161,24 @@ STATIC PowerMgrRunOps g_pmRunOps = { .postConfig = OsPostConfigDefault, }; -STATIC VOID OsLightSleepDefault(VOID) +STATIC VOID OsLightSleepDefault(VOID)/*轻量级睡眠函数,执行wfi指令,让处理器进入睡眠状态*/ { TRACE_FUNC_CALL(); wfi(); } -STATIC VOID OsSetWakeUpTimerDefault(UINT32 sleepTick) +STATIC VOID OsSetWakeUpTimerDefault(UINT32 sleepTick)/*设置唤醒定时器,默认实现为空函数*/ { TRACE_FUNC_CALL(); } -STATIC UINT32 OsWithrawWakeUpTimerDefault(VOID) +STATIC UINT32 OsWithrawWakeUpTimerDefault(VOID)/*撤销唤醒定时器,默认实现返回0*/ { TRACE_FUNC_CALL(); return 0; } -STATIC UINT32 OsGetSleepTimeDefault(VOID) +STATIC UINT32 OsGetSleepTimeDefault(VOID)/*获取当前任务休眠时间*/ { #ifdef LOSCFG_KERNEL_TICKLESS return OsSleepTicksGet(); @@ -187,12 +187,12 @@ STATIC UINT32 OsGetSleepTimeDefault(VOID) #endif } -STATIC UINT32 OsSelectSleepModeDefault(UINT32 sleepTicks) +STATIC UINT32 OsSelectSleepModeDefault(UINT32 sleepTicks)/*选择合适的休眠模式*/ { if (sleepTicks < g_pmMgr.minSleepTicks) { return LOS_INTERMIT_NONE; } - + /*默认实现根据休眠时间和当前系统状态选择轻量级睡眠或者深度睡眠模式*/ if (g_pmMgr.deepSleepOps != NULL && sleepTicks >= g_pmMgr.minDeepSleepTicks && g_pmRunOps.getDeepSleepVoteCount() == 0) { return LOS_INTERMIT_DEEP_SLEEP; @@ -201,73 +201,73 @@ STATIC UINT32 OsSelectSleepModeDefault(UINT32 sleepTicks) return LOS_INTERMIT_LIGHT_SLEEP; } -STATIC VOID OsChangeFreqDefault(UINT8 freq) +STATIC VOID OsChangeFreqDefault(UINT8 freq)/*改变处理器频率*/ { (VOID)freq; TRACE_FUNC_CALL(); } -STATIC VOID OsEnterDeepSleepDefault(VOID) +STATIC VOID OsEnterDeepSleepDefault(VOID)// 进入深度睡眠模式函数 { TRACE_FUNC_CALL(); wfi(); } -STATIC UINT32 OsPreConfigDefault(VOID) +STATIC UINT32 OsPreConfigDefault(VOID)//电源管理模块预配置函数 { TRACE_FUNC_CALL(); return 1; } -STATIC VOID OsPostConfigDefault(VOID) +STATIC VOID OsPostConfigDefault(VOID)//电源管理模块后配置函数 { } #ifdef LOSCFG_KERNEL_DEEPSLEEP -STATIC BOOL OsCouldDeepSleepDefault(VOID) +STATIC BOOL OsCouldDeepSleepDefault(VOID)// 判断是否可以进入深度睡眠模式 { TRACE_FUNC_CALL(); return true; } -STATIC BOOL OsSuspendPreConfigDefault(VOID) +STATIC BOOL OsSuspendPreConfigDefault(VOID)// 休眠前的预配置函数 { TRACE_FUNC_CALL(); return true; } -STATIC VOID OsSuspendDeviceDefault(VOID) +STATIC VOID OsSuspendDeviceDefault(VOID)//休眠时设备挂起函数 { TRACE_FUNC_CALL(); } -STATIC VOID OsRollBackDefault(VOID) +STATIC VOID OsRollBackDefault(VOID)//唤醒后的回滚函数 { TRACE_FUNC_CALL(); } -STATIC VOID OsResumeDeviceDefault(VOID) +STATIC VOID OsResumeDeviceDefault(VOID)//唤醒后的设备恢复函数 { TRACE_FUNC_CALL(); } -STATIC VOID OsResumePostConfigDefault(VOID) +STATIC VOID OsResumePostConfigDefault(VOID)//唤醒后电源管理模块后配置函数 { TRACE_FUNC_CALL(); } -STATIC VOID OsSystemWakeupDefault(VOID) +STATIC VOID OsSystemWakeupDefault(VOID)//系统唤醒函数 { TRACE_FUNC_CALL(); } -STATIC VOID OsResumeCallBackDefault(VOID) +STATIC VOID OsResumeCallBackDefault(VOID)//唤醒后回调函数 { TRACE_FUNC_CALL(); } -STATIC VOID OsOtherCoreResumeDefault(VOID) +STATIC VOID OsOtherCoreResumeDefault(VOID)//其他核心唤醒函数 { TRACE_FUNC_CALL(); } @@ -275,18 +275,18 @@ STATIC VOID OsOtherCoreResumeDefault(VOID) STATIC VOID OsDeepSleepResume(VOID); STATIC PowerMgrDeepSleepOps g_deepSleepOps = { - .couldDeepSleep = OsCouldDeepSleepDefault, - .systemWakeup = OsSystemWakeupDefault, - .suspendPreConfig = OsSuspendPreConfigDefault, - .suspendDevice = OsSuspendDeviceDefault, - .rollback = OsRollBackDefault, - .resumeDevice = OsResumeDeviceDefault, - .resumePostConfig = OsResumePostConfigDefault, - .resumeCallBack = OsResumeCallBackDefault, - .otherCoreResume = OsOtherCoreResumeDefault + .couldDeepSleep = OsCouldDeepSleepDefault, //判断是否可以进入深度睡眠模式的函数指针 + .systemWakeup = OsSystemWakeupDefault,//唤醒函数的函数指针 + .suspendPreConfig = OsSuspendPreConfigDefault,//修面前的预配置函数的函数指针 + .suspendDevice = OsSuspendDeviceDefault,//设备挂起函数的函数指针 + .rollback = OsRollBackDefault,//唤醒后的回滚函数的函数指针 + .resumeDevice = OsResumeDeviceDefault,//设备回复函数的函数指针 + .resumePostConfig = OsResumePostConfigDefault,//唤醒后电源管理模块后配置函数的函数指针 + .resumeCallBack = OsResumeCallBackDefault,//唤醒后回调函数的函数指针 + .otherCoreResume = OsOtherCoreResumeDefault//其他核心唤醒函数的函数指针 }; -STATIC INLINE VOID OsTickResume(UINT32 sleepTicks) +STATIC INLINE VOID OsTickResume(UINT32 sleepTicks)//用于更新系统始终,根据休眠时间调整系统时钟 { UINT32 cpuid = ArchCurrCpuid(); if (sleepTicks > g_pmMgr.sleepTime[cpuid]) { @@ -297,7 +297,7 @@ STATIC INLINE VOID OsTickResume(UINT32 sleepTicks) OsSysTimeUpdate(sleepTicks); } -STATIC VOID OsDeepSleepResume(VOID) +STATIC VOID OsDeepSleepResume(VOID)//深度睡眠唤醒后的处理函数 { DEEPOPS_CALL_FUNC_VOID(resumeFromReset); LOS_AtomicSet(&g_pmMgr.resumeSleepCores, OS_MP_CPU_ALL); @@ -305,30 +305,32 @@ STATIC VOID OsDeepSleepResume(VOID) #ifdef LOSCFG_KERNEL_CPUP OsSetCpuCycle(0); #endif - +//恢复设置,恢复其他核心进程 #if (LOSCFG_KERNEL_SMP == YES) release_secondary_cores(); #endif OsSRRestoreRegister(); } -STATIC INLINE VOID OsEnterDeepSleepMainCore(VOID) +STATIC INLINE VOID OsEnterDeepSleepMainCore(VOID)//用于主核心进入深度睡眠 { + //挂起预配置 LOS_AtomicAdd(&g_pmMgr.deepSleepCores, 1); g_deepSleepOps.suspendPreConfig(); - + //是否可以进入神对睡眠判断 if (g_pmMgr.deepSleepCores == LOSCFG_KERNEL_CORE_NUM && g_deepSleepOps.couldDeepSleep()) { g_deepSleepOps.suspendDevice(); g_pmRunOps.setWakeUpTimer(g_pmMgr.sleepTime[0]); g_resumeFromImg = LOS_COLD_RESET; OsSRSaveRegister(); - + //进入深度睡眠,进行回滚操作,保存上下文 if (g_resumeFromImg == LOS_COLD_RESET) { g_resumeFromImg = LOS_DEEP_SLEEP_RESET; CALL_RUN_OPS_FUNC_NO_RETURN(contextSave); g_pmRunOps.enterDeepSleep(); g_deepSleepOps.rollback(); } + //设置唤醒定时器 g_deepSleepOps.resumeDevice(); UINT32 sleepTicks = g_pmRunOps.withdrawWakeUpTimer(); OsSysTimeUpdate(sleepTicks); @@ -342,42 +344,43 @@ STATIC INLINE VOID OsEnterDeepSleepMainCore(VOID) LOS_AtomicSub(&g_pmMgr.deepSleepCores, 1); } -STATIC INLINE VOID OsEnterSleepMode(VOID) +STATIC INLINE VOID OsEnterSleepMode(VOID)//进入睡眠模式,包括主核心和其他核心的不同处理 { #ifdef LOSCFG_KERNEL_SMP UINT32 currCpuid = ArchCurrCpuid(); - if (currCpuid == 0) { + if (currCpuid == 0) { //如果是0则进入主核心深度睡眠 #endif OsEnterDeepSleepMainCore(); -#ifdef LOSCFG_KERNEL_SMP +#ifdef LOSCFG_KERNEL_SMP //如果当前核心不是主核心,则直接返回,因为其他核心的睡眠处理逻辑不在此函数中处理 return; } UINT32 cpuMask = 1 << currCpuid; LOS_AtomicAdd(&g_pmMgr.deepSleepCores, 1); - OsSRSaveRegister(); + OsSRSaveRegister();//保存相关寄存器状态并判断是否需要唤醒当前核心。 if (g_pmMgr.resumeSleepCores & cpuMask) { INT32 val; - do { + do { //,将 g_pmMgr.resumeSleepCores 的值中当前核心的位清零,表示该核心已被唤醒。 val = LOS_AtomicRead(&g_pmMgr.resumeSleepCores); } while (LOS_AtomicCmpXchg32bits(&g_pmMgr.resumeSleepCores, val & (~cpuMask), val)); g_deepSleepOps.otherCoreResume(); UINT32 sleepTicks = g_pmRunOps.withdrawWakeUpTimer(); OsTickResume(sleepTicks); + //执行其他核心的恢复操作,并从唤醒定时器中获取休眠时间,然后调用 OsTickResume 函数更新系统时钟。 } else { - if (g_pmMgr.deepSleepCores == LOSCFG_KERNEL_CORE_NUM) { - LOS_MpSchedule(1 << 0); + if (g_pmMgr.deepSleepCores == LOSCFG_KERNEL_CORE_NUM) {//如果不需要唤醒,则判断是否所有核心都进入了深度睡眠 + LOS_MpSchedule(1 << 0);//调用函数选择一个核心唤醒系统 } #ifdef LOSCFG_KERNEL_TICKLESS - OsTicklessOpen(); + OsTicklessOpen();//开启节能模式 #endif g_pmRunOps.enterLightSleep(); } - LOS_AtomicSub(&g_pmMgr.deepSleepCores, 1); + LOS_AtomicSub(&g_pmMgr.deepSleepCores, 1);//将 g_pmMgr.deepSleepCores 的值减1,表示当前核心已经处理完睡眠状态 #endif // LOSCFG_KERNEL_SMP } -STATIC INLINE VOID OsSystemSuspend(LosIntermitMode *mode) +STATIC INLINE VOID OsSystemSuspend(LosIntermitMode *mode)//选择合适的低功耗模式(深度,轻度 { // If enterShutdownMode is not defined, will fall through to standby mode // If enterStandbyMode is not defined, will fall through to stop mode @@ -402,10 +405,10 @@ STATIC INLINE VOID OsSystemSuspend(LosIntermitMode *mode) } #endif -STATIC VOID OsLowpowerLightSleep(UINT32 mode, UINT32 cpuid, UINT32 sleepTicks) +STATIC VOID OsLowpowerLightSleep(UINT32 mode, UINT32 cpuid, UINT32 sleepTicks)//轻度睡眠中的模式调整 { if (g_pmRunOps.preConfig != NULL) { - sleepTicks = g_pmRunOps.getSleepTime(); + sleepTicks = g_pmRunOps.getSleepTime();//获取休眠时间 } if (sleepTicks > 1) { g_pmMgr.sleepMode[cpuid] = (mode & 0x0FF); @@ -414,18 +417,19 @@ STATIC VOID OsLowpowerLightSleep(UINT32 mode, UINT32 cpuid, UINT32 sleepTicks) OsTicklessOpen(); #endif if (mode == LOS_INTERMIT_LIGHT_SLEEP && g_pmRunOps.enterLightSleep != NULL) { - g_pmRunOps.enterLightSleep(); + g_pmRunOps.enterLightSleep();//进入轻度睡眠 } else { wfi(); } } else { - g_pmMgr.sleepMode[cpuid] = LOS_INTERMIT_NONE; + g_pmMgr.sleepMode[cpuid] = LOS_INTERMIT_NONE;//等待中断事件 g_pmMgr.sleepTime[cpuid] = 0; wfi(); } } STATIC VOID OsLowpowerDeepSleep(LosIntermitMode *mode, UINT32 cpuid, UINT32 sleepTicks) +//深度睡眠设置 { #ifdef LOSCFG_KERNEL_DEEPSLEEP if (g_pmRunOps.enterDeepSleep == NULL) { @@ -438,27 +442,31 @@ STATIC VOID OsLowpowerDeepSleep(LosIntermitMode *mode, UINT32 cpuid, UINT32 slee OsSystemSuspend(mode); } #else - *mode = LOS_INTERMIT_LIGHT_SLEEP; + *mode = LOS_INTERMIT_LIGHT_SLEEP;//若不支持深度睡眠则强制进入轻度睡眠 #endif } -STATIC VOID OsLowpowerProcess(VOID) +STATIC VOID OsLowpowerProcess(VOID)//处理系统进入低功耗模式的过程 { -#ifdef LOSCFG_KERNEL_RUNSTOP +#ifdef LOSCFG_KERNEL_RUNSTOP//检查系统是否需要在进入低功耗模式前保存系统消息 if (OsWowSysDoneFlagGet() == OS_STORE_SYSTEM) { OsStoreSystemInfoBeforeSuspend(); } #endif /* Change frequency is pended, need to change the freq here. */ - if ((g_pmRunOps.changeFreq != NULL)) { + if ((g_pmRunOps.changeFreq != NULL)) {//如果需要改变频率则调整切换 OsChangeFreq(); } - + //禁止中断,锁住任务调度,并获取当前CPUID和休眠时间 UINT32 intSave = LOS_IntLock(); LOS_TaskLock(); RUNOPS_CALL_FUNC_VOID(preConfig); UINT32 cpuid = ArchCurrCpuid(); UINT32 sleepTicks = g_pmRunOps.getSleepTime(); + /*如果休眠时间小于等于最小休眠时间(g_pmMgr.minSleepTicks) + 或者有任务请求不进入深度睡眠(LOS_PowerMgrGetDeepSleepVoteCount 返回值不为0), + 则将当前 CPU 设置为不进入任何中断模式,清零休眠时间, + 并调用 postConfig 函数。*/ if (sleepTicks <= g_pmMgr.minSleepTicks || LOS_PowerMgrGetDeepSleepVoteCount() != 0) { g_pmMgr.sleepMode[cpuid] = LOS_INTERMIT_NONE; g_pmMgr.sleepTime[cpuid] = 0; @@ -477,23 +485,23 @@ STATIC VOID OsLowpowerProcess(VOID) sleepTicks = g_pmMgr.maxSleepCount; } UINT32 mode = g_pmRunOps.selectSleepMode(sleepTicks); - if (mode >= LOS_INTERMIT_DEEP_SLEEP) { + if (mode >= LOS_INTERMIT_DEEP_SLEEP) {//如果支持深度睡眠 g_pmMgr.sleepTime[cpuid] = g_pmRunOps.withdrawWakeUpTimer(); OsLowpowerDeepSleep(&mode, cpuid, sleepTicks); } RUNOPS_CALL_FUNC_VOID(postConfig); - if (mode < LOS_INTERMIT_DEEP_SLEEP) { + if (mode < LOS_INTERMIT_DEEP_SLEEP) {//进入轻度睡眠 OsLowpowerLightSleep(mode, cpuid, sleepTicks); } } LOS_TaskUnlock(); - LOS_IntRestore(intSave); + LOS_IntRestore(intSave);//解锁任务调度并恢复中断 } -STATIC VOID OsLowpowerWakeupFromReset(VOID) +STATIC VOID OsLowpowerWakeupFromReset(VOID)//处理系统从重置状态唤醒的情况 { #ifdef LOSCFG_KERNEL_RUNSTOP if (g_resumeFromImg == LOS_RUN_STOP_RESET) { @@ -508,7 +516,7 @@ STATIC VOID OsLowpowerWakeupFromReset(VOID) #endif } -STATIC VOID OsLowpowerWakeupFromInterrupt(UINT32 intNum) +STATIC VOID OsLowpowerWakeupFromInterrupt(UINT32 intNum)//用于处理系统从重置状态唤醒的情况 { #ifdef LOSCFG_KERNEL_TICKLESS OsTicklessUpdate(intNum); @@ -517,26 +525,27 @@ STATIC VOID OsLowpowerWakeupFromInterrupt(UINT32 intNum) #endif } -STATIC VOID OsChangeFreq(VOID) +STATIC VOID OsChangeFreq(VOID)//处理改变系统频率的操作 { UINT32 freq; BOOL ret; - do { + do {//尝试获取频率切换的自旋锁(通过原子操作实现) + //如果成功获取锁,则说明没有其他线程正在频率切换过程中,可以继续执行 ret = LOS_AtomicCmpXchg32bits(&g_pmMgr.freeLock, LOCK_ON, LOCK_OFF); if (ret) { return; } - freq = (UINT32)g_pmMgr.freqPending; + freq = (UINT32)g_pmMgr.freqPending;//获取频率切换的目标频率,并进行频率切换 if (freq != (UINT32)g_pmMgr.freq) { - g_pmRunOps.changeFreq(freq); + g_pmRunOps.changeFreq(freq);//更新频率 LOS_AtomicSet(&g_pmMgr.freq, (INT32)freq); } - LOS_AtomicSet(&g_pmMgr.freeLock, LOCK_OFF); + LOS_AtomicSet(&g_pmMgr.freeLock, LOCK_OFF);//释放自旋锁 } while (FreqHigher(g_pmMgr.freqPending, freq)); } -STATIC VOID OsLowpowerChangeFreq(LosFreqMode freq) +STATIC VOID OsLowpowerChangeFreq(LosFreqMode freq)//改变系统频率 { TRACE_FUNC_CALL(); if (g_pmRunOps.changeFreq == NULL) { @@ -554,36 +563,36 @@ STATIC VOID OsLowpowerChangeFreq(LosFreqMode freq) // We get a high frequency request, then change it if (FreqHigher(g_pmMgr.freqPending, g_pmMgr.freq) && g_pmRunOps.changeFreq != NULL) { - OsChangeFreq(); + OsChangeFreq();//如果目标频率高于当前频率,并且 g_pmRunOps.changeFreq 不为空,则调用 OsChangeFreq 函数进行频率切换。 } } -STATIC VOID OsLowpowerDeepSleepVoteBegin(VOID) +STATIC VOID OsLowpowerDeepSleepVoteBegin(VOID)//开始深度睡眠投票 { TRACE_FUNC_CALL(); - LOS_AtomicInc(&g_pmMgr.sleepVoteCount); + LOS_AtomicInc(&g_pmMgr.sleepVoteCount);//用原子操作将 g_pmMgr.sleepVoteCount 加一,并断言 g_pmMgr.sleepVoteCount 大于零。 LOS_ASSERT(g_pmMgr.sleepVoteCount > 0); } -STATIC VOID OsLowpowerDeepSleepVoteEnd(VOID) +STATIC VOID OsLowpowerDeepSleepVoteEnd(VOID)//结束深度睡眠投票 { TRACE_FUNC_CALL(); - LOS_AtomicDec(&g_pmMgr.sleepVoteCount); + LOS_AtomicDec(&g_pmMgr.sleepVoteCount);//原子操作将 g_pmMgr.sleepVoteCount 减一,并断言 g_pmMgr.sleepVoteCount 大于等于零。 LOS_ASSERT(g_pmMgr.sleepVoteCount >= 0); } -STATIC VOID OsLowpowerDeepSleepVoteDelay(UINT32 delayTicks) +STATIC VOID OsLowpowerDeepSleepVoteDelay(UINT32 delayTicks)//延迟深度睡眠投票 { TRACE_FUNC_CALL(); } -STATIC VOID OsLowpowerRegisterExternalVoter(LowpowerExternalVoterHandle callback) +STATIC VOID OsLowpowerRegisterExternalVoter(LowpowerExternalVoterHandle callback)//注册外部投票者 { TRACE_FUNC_CALL(); g_pmMgr.exVoterHandle = callback; } -STATIC UINT32 OsLowpowerGetDeepSleepVoteCount(VOID) +STATIC UINT32 OsLowpowerGetDeepSleepVoteCount(VOID)//获取深度睡眠投票数 { if (g_pmMgr.exVoterHandle == NULL) { return (UINT32)g_pmMgr.sleepVoteCount; @@ -593,22 +602,26 @@ STATIC UINT32 OsLowpowerGetDeepSleepVoteCount(VOID) } STATIC PowerMgrOps g_pmOps = { - .process = OsLowpowerProcess, - .wakeupFromReset = OsLowpowerWakeupFromReset, - .resumeFromInterrupt = OsLowpowerWakeupFromInterrupt, - .changeFreq = OsLowpowerChangeFreq, - .deepSleepVoteBegin = OsLowpowerDeepSleepVoteBegin, - .deepSleepVoteEnd = OsLowpowerDeepSleepVoteEnd, - .deepSleepVoteDelay = OsLowpowerDeepSleepVoteDelay, - .registerExternalVoter = OsLowpowerRegisterExternalVoter, - .getDeepSleepVoteCount = OsLowpowerGetDeepSleepVoteCount, - .getSleepMode = NULL, - .setSleepMode = NULL, + .process = OsLowpowerProcess, //该函数指针用于处理低功耗过程,即在进入低功耗模式前需要执行的操作 + .wakeupFromReset = OsLowpowerWakeupFromReset,//该函数指针用于处理从复位状态唤醒时的操作 + .resumeFromInterrupt = OsLowpowerWakeupFromInterrupt,//该函数指针用于处理从中断状态恢复时的操作。 + .changeFreq = OsLowpowerChangeFreq,//该函数指针用于改变系统频率的操作,可以根据需要调整系统的工作频率 + .deepSleepVoteBegin = OsLowpowerDeepSleepVoteBegin,//该函数指针用于开始深度休眠投票,即在进入深度休眠模式前需要执行的操作 + .deepSleepVoteEnd = OsLowpowerDeepSleepVoteEnd,//该函数指针用于结束深度休眠投票,即在退出深度休眠模式后需要执行的操作 + .deepSleepVoteDelay = OsLowpowerDeepSleepVoteDelay,//该函数指针用于处理深度休眠投票延迟的操作,可以根据需要延迟深度休眠的投票 + .registerExternalVoter = OsLowpowerRegisterExternalVoter,//该函数指针用于注册外部投票者,即在系统中存在其他模块也需要参与低功耗投票时的操作 + .getDeepSleepVoteCount = OsLowpowerGetDeepSleepVoteCount,//该函数指针用于获取当前深度休眠投票的数量,可以用来监控系统中参与休眠投票的模块数量 + .getSleepMode = NULL,//该函数指针用于获取当前的睡眠模式,即获取系统当前是否处于睡眠状态 + .setSleepMode = NULL,//该函数指针用于设置睡眠模式,即将系统设置为指定的睡眠模式 + //以上提及的函数均为函数指针 }; #define FORCE_NULL_CALLBACK (void *)0x3f3f3f3f - -#define ASSIGN_MEMBER(lhs, rhs, member) \ +//以下定义是用于给结构体成员赋值,如果某个回调函数指针为特殊空值,则将相应的成员置为空,否则进行赋值 +#define ASSIGN_MEMBER(lhs, rhs, member) +//lhs 是左操作数,表示要赋值的结构体指针; +//rhs 是右操作数,表示要赋给成员的值; +//member 是要赋值的结构体成员 do { \ if ((rhs)->member == FORCE_NULL_CALLBACK) { \ (lhs)->member = NULL; \ @@ -631,16 +644,16 @@ VOID LOS_PowerMgrInit(const PowerMgrParameter *para) const PowerMgrRunOps *runOps = NULL; const PowerMgrDeepSleepOps *deepSleepOps = NULL; (void)deepSleepOps; - if (para != NULL) { + if (para != NULL) { //如果para为空,则运行操作和深度睡眠操作都为空指针 runOps = ¶->runOps; #ifdef LOSCFG_KERNEL_DEEPSLEEP deepSleepOps = ¶->deepSleepOps; #endif - g_pmMgr.minSleepTicks = para->config.minLightSleepTicks; - g_pmMgr.maxSleepCount = para->config.maxDeepSleepTicks; - g_pmMgr.minDeepSleepTicks = para->config.minDeepSleepTicks; + g_pmMgr.minSleepTicks = para->config.minLightSleepTicks;//记录了系统中需要从睡眠状态唤醒的 CPU 核心数 + g_pmMgr.maxSleepCount = para->config.maxDeepSleepTicks;//用于保护电源管理模块在多线程环境下的并发访问 + g_pmMgr.minDeepSleepTicks = para->config.minDeepSleepTicks;//记录自旋锁是否被释放 } - + //将传入的运行操作和深度睡眠操作分别赋值给全局变量 g_pmRunOps 和 g_deepSleepOps LOS_AtomicSet(&g_pmMgr.resumeSleepCores, 0); LOS_SpinInit(&g_pmMgr.lock); @@ -648,25 +661,25 @@ VOID LOS_PowerMgrInit(const PowerMgrParameter *para) // verify and assign input operators. if (runOps != NULL) { - ASSIGN_MEMBER(&g_pmRunOps, runOps, changeFreq); - ASSIGN_MEMBER(&g_pmRunOps, runOps, enterLightSleep); + ASSIGN_MEMBER(&g_pmRunOps, runOps, changeFreq);//改变CPU频率 + ASSIGN_MEMBER(&g_pmRunOps, runOps, enterLightSleep);//进入浅度睡眠 #ifdef LOSCFG_KERNEL_DEEPSLEEP - ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, enterDeepSleep); - ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, setWakeUpTimer); - ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, withdrawWakeUpTimer); + ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, enterDeepSleep);//进入深度睡眠 + ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, setWakeUpTimer);//设置唤醒定时器 + ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, withdrawWakeUpTimer);//撤销定时器 #else ASSIGN_MEMBER(&g_pmRunOps, runOps, enterDeepSleep); ASSIGN_MEMBER(&g_pmRunOps, runOps, setWakeUpTimer); ASSIGN_MEMBER(&g_pmRunOps, runOps, withdrawWakeUpTimer); #endif - ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, getSleepTime); - ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, selectSleepMode); - ASSIGN_MEMBER(&g_pmRunOps, runOps, preConfig); - ASSIGN_MEMBER(&g_pmRunOps, runOps, postConfig); + ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, getSleepTime);//货的睡眠时间 + ASSIGN_MEMBER_NOT_NULL(&g_pmRunOps, runOps, selectSleepMode);//选择不同的睡眠模式 + ASSIGN_MEMBER(&g_pmRunOps, runOps, preConfig);//预配置 + ASSIGN_MEMBER(&g_pmRunOps, runOps, postConfig);//后配置 } #ifdef LOSCFG_KERNEL_DEEPSLEEP - if (deepSleepOps != NULL) { + if (deepSleepOps != NULL) {//进入深度睡眠 ASSIGN_MEMBER(&g_deepSleepOps, deepSleepOps, couldDeepSleep); ASSIGN_MEMBER(&g_deepSleepOps, deepSleepOps, systemWakeup); ASSIGN_MEMBER(&g_deepSleepOps, deepSleepOps, suspendPreConfig); @@ -680,4 +693,7 @@ VOID LOS_PowerMgrInit(const PowerMgrParameter *para) #endif // Register PowerMgr to Low-Power Framework. LOS_LowpowerInit(&g_pmOps); + //将电源管理模块注册到低功耗框架中。 + //低功耗框架是一个用于管理处理器和设备进入低功耗模式的软件框架, + //它能够最大限度地降低系统能耗,提高系统的电池寿命 } diff --git a/src/kernel/extended/lowpower/runstop/src/los_runstop.c b/src/kernel/extended/lowpower/runstop/src/los_runstop.c index 0da74e3..f529d6a 100644 --- a/src/kernel/extended/lowpower/runstop/src/los_runstop.c +++ b/src/kernel/extended/lowpower/runstop/src/los_runstop.c @@ -51,22 +51,28 @@ extern "C" { /* If core is ready for imaging */ LITE_OS_SEC_DATA_MINOR STATIC UINT32 g_sysDoneFlag[LOSCFG_KERNEL_CORE_NUM] = { [0 ... (LOSCFG_KERNEL_CORE_NUM - 1)] = OS_NO_STORE_SYSTEM -}; +}; /*标记数组状态,用来表示系统是否加载完成*/ /* Start position of flash to write image */ LITE_OS_SEC_DATA_MINOR STATIC UINTPTR g_flashImgAddr; +/*flash图像地址和大小,用于存储flash相关信息。*/ /* Start position of heap memory after carry the image from flash to memory */ LITE_OS_SEC_DATA_MINOR STATIC const VOID *g_heapMemStart = NULL; +/*初始化图像地址*/ /* Size of heap memory in image */ LITE_OS_SEC_DATA_MINOR STATIC size_t g_heapMemSize = 0; +/*初始化定义图像大小*/ + #ifdef LOSCFG_EXC_INTERACTION /* Start position of exc interaction heap memory after carry the image from flash to memory */ LITE_OS_SEC_DATA_MINOR STATIC const VOID *g_excInteractionMemStart = NULL; +/*在存储器映像从闪存复制到内存之后异常交互堆的起始位置变量*/ /* Size of exc interaction heap memory in image */ LITE_OS_SEC_DATA_MINOR STATIC size_t g_excInteractionMemSize = 0; +/*异常交互堆内存在储存器映像中的大小*/ #endif /* Size of wow image */ LITE_OS_SEC_DATA_MINOR STATIC size_t g_wowImgSize = 0; @@ -76,15 +82,17 @@ LITE_OS_SEC_DATA_MINOR STATIC EVENT_CB_S g_suspendResumeEvent; LITE_OS_SEC_DATA_MINOR STATIC EVENT_CB_S g_writeFlashEvent; typedef struct { - UINTPTR memStart; - UINTPTR flashStart; - size_t memSize; + UINTPTR memStart; /*内存起始地址*/ + UINTPTR flashStart; /*闪存起始地址*/ + size_t memSize; /*存储空间大小*/ } FlashWriteParam; BOOL IsImageResume(VOID) { return (g_resumeFromImg != LOS_COLD_RESET); } +/*判断系统是否从存储器映像中恢复的,功能是当系统异常启动或者需要重启的时候就会从内存将其数据保存到闪存中 +此函数就是判断系统是否是从存储器映像回复的,从而确定是否需要对系统状态进行恢复*/ LITE_OS_SEC_TEXT_MINOR STATIC VOID OsDoWriteWow2Flash(FLASH_WRITE_FUNC flashWriteFunc, const FlashWriteParam *wowSection, @@ -109,29 +117,32 @@ LITE_OS_SEC_TEXT_MINOR STATIC VOID OsDoWriteWow2Flash(FLASH_WRITE_FUNC flashWrit return; } } - -LITE_OS_SEC_TEXT_MINOR VOID OsWriteWow2Flash(VOID) +/*首先检查内存中的大小是否为0 +若不为0则将wowsection、excheapsection、heapmemsection中的静态数据和代码存储在系统启动的时候将其从闪存加入到内存中*/ +LITE_OS_SEC_TEXT_MINOR VOID OsWriteWow2Flash(VOID) /*根据指定的内存区域,在闪存中写入相应的数据,完成写入操作*/ { FlashWriteParam wowSection; FlashWriteParam excHeapSection = {0}; - FlashWriteParam heapMemSection; - size_t eraseAlignSize; - size_t writeAlignSize; + FlashWriteParam heapMemSection; /*这是三种闪存内部独立的堆专用的内存区域对应的闪存写入参数*/ + size_t eraseAlignSize; /*表示闪存擦除时的对齐大小*/ + size_t writeAlignSize; /*闪存写入时的对齐大小*/ FLASH_WRITE_FUNC flashWriteFunc = g_runstopParam.pfFlashWriteFunc; - eraseAlignSize = g_runstopParam.uwFlashEraseAlignSize; - writeAlignSize = g_runstopParam.uwFlashWriteAlignSize; + eraseAlignSize = g_runstopParam.uwFlashEraseAlignSize; /*用来指定擦除和写入时的对齐大小,通常设置为扇区大小的整数倍*/ + writeAlignSize = g_runstopParam.uwFlashWriteAlignSize; /*为了避免出现擦除或写入不规则数据的情况, + 需要将操作的地址向下或向上舍入到扇区大小的整数倍 + 从而避免因为不规则的操作而导致数据的错误或损坏。*/ writeAlignSize = (writeAlignSize >= eraseAlignSize) ? writeAlignSize : eraseAlignSize; if (flashWriteFunc == NULL) { PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__); return; } - wowSection.memStart = (UINTPTR)&__ram_vectors_vma; - wowSection.flashStart = g_flashImgAddr; + wowSection.memStart = (UINTPTR)&__ram_vectors_vma;/*初始化wowSection,为内存中起始地址*/ + wowSection.flashStart = g_flashImgAddr; /*为闪存中起始地址*/ wowSection.memSize = ((UINTPTR)&__wow_end) - ((UINTPTR)&__ram_vectors_vma); wowSection.memSize = (wowSection.memSize + writeAlignSize - 1) & ~(writeAlignSize - 1); - + /*计算了wowSection大小,通过与运算保证每次写入的数据都是整个扇区的倍数*/ #ifdef LOSCFG_EXC_INTERACTION excHeapSection.memStart = (UINTPTR)m_aucSysMem0; excHeapSection.flashStart = g_flashImgAddr + wowSection.memSize; @@ -152,39 +163,41 @@ LITE_OS_SEC_TEXT_MINOR VOID OsWriteWow2Flash(VOID) g_wowImgSize = wowSection.memSize + heapMemSection.memSize + excHeapSection.memSize; OsDoWriteWow2Flash(flashWriteFunc, &wowSection, &excHeapSection, &heapMemSection); + /*将变量传输给函数,由其实现相应的写入操作*/ } -LITE_OS_SEC_TEXT_MINOR VOID OsSystemSuspend(VOID) +LITE_OS_SEC_TEXT_MINOR VOID OsSystemSuspend(VOID) /*实现系统的挂起操作*/ { - UINT32 cpuid; + UINT32 cpuid; /*获取当前CPU的ID*/ - (VOID)LOS_IntLock(); + (VOID)LOS_IntLock(); LOS_TaskLock(); cpuid = ArchCurrCpuid(); + /*禁止中断并锁定任务调度器,确保在执行挂起操作期间不会被打断*/ + g_sysDoneFlag[cpuid] = OS_NO_STORE_SYSTEM; /*将当前CPU的系统挂起标志设置为不需要保存系统状态*/ + g_saveTsk[cpuid] = OsCurrTaskGet(); /*保存当前任务指针到savetask变量中*/ - g_sysDoneFlag[cpuid] = OS_NO_STORE_SYSTEM; - g_saveTsk[cpuid] = OsCurrTaskGet(); - - OsSRSaveRegister(); + OsSRSaveRegister(); /*保存当前CPU的寄存器状态,以便在恢复系统时能够正确恢复到挂起前的状态*/ /* If 1 core, only to save registers */ - if (cpuid != 0) { - if (g_otherCoreResume != 0) { + if (cpuid != 0) { /*若此CPU部位0号内核*/ + if (g_otherCoreResume != 0) { /*说明其他多核核心需要恢复运行*/ HalIrqInitPercpu(); OsTickStart(); LOS_TaskUnlock(); (VOID)LOS_IntUnLock(); - return; + return; } - g_sysDoneFlag[cpuid - 1] = OS_STORE_SYSTEM; + g_sysDoneFlag[cpuid - 1] = OS_STORE_SYSTEM; /*需要初始化中断并启动系统时钟,并最终解锁任务调度器并恢复中断*/ while (1) {} } - if (g_resumeFromImg) { + if (g_resumeFromImg) { /*如果是 0 号 CPU,且系统需要从镜像中恢复(g_resumeFromImg 为真)*/ OsWriteWow2Flash(); LOS_TaskUnlock(); (VOID)LOS_IntUnLock(); (VOID)LOS_EventWrite(&g_suspendResumeEvent, FLASH_IMG_SUCCESS); - } else { + /*调用 OsWriteWow2Flash 函数将数据写入闪存,并发送 FLASH_IMG_SUCCESS 事件信号,表示成功从镜像中恢复*/ + } else { /*不需要从镜像中恢复*/ OsTickStart(); LOS_TaskUnlock(); (VOID)LOS_IntUnLock(); @@ -194,9 +207,15 @@ LITE_OS_SEC_TEXT_MINOR VOID OsSystemSuspend(VOID) } (VOID)LOS_EventWrite(&g_suspendResumeEvent, WAKEUP_FROM_SUSPEND); } + /*启动系统时钟,解锁任务调度器和中断,并根据是否设置了空闲唤醒回调函数来执行相应的操作, + 最后发送 WAKEUP_FROM_SUSPEND 事件信号,表示从挂起状态唤醒*/ } LITE_OS_SEC_TEXT VOID OsWriteToFlashTask(VOID) +/*初始化了一个事件对象 g_writeFlashEvent +并且在循环中调用 LOS_EventRead 函数等待事件的发生, +并以 OR 模式和清除模式等待事件的标志位为 0x01。 +一旦事件发生,它调用 OsSystemSuspend 函数将系统挂起。*/ { (VOID)LOS_EventInit(&g_writeFlashEvent); @@ -207,6 +226,10 @@ LITE_OS_SEC_TEXT VOID OsWriteToFlashTask(VOID) } LITE_OS_SEC_TEXT VOID OsStoreSystemInfoBeforeSuspend(VOID) +/*根据当前 CPU 的 ID 判断是否需要挂起系统。 +如果当前 CPU 不是 0 号 CPU,直接调用 OsSystemSuspend 函数挂起系统。 +如果是 0 号 CPU,则调用 LOS_EventWrite 函数向事件对象 g_writeFlashEvent 发送一个事件, +唤醒 OsWriteToFlashTask 任务来执行挂起操作。*/ { UINT32 cpuid = ArchCurrCpuid(); if (cpuid != 0) { @@ -218,6 +241,9 @@ LITE_OS_SEC_TEXT VOID OsStoreSystemInfoBeforeSuspend(VOID) } LITE_OS_SEC_TEXT_MINOR VOID OsSystemWakeup(VOID) +/*是系统从挂起状态唤醒后的处理函数。*/ + + { UINT32 cpuid; errno_t err; @@ -225,7 +251,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OsSystemWakeup(VOID) if (!g_resumeFromImg) { return; } - +/*进行一些内存数据的复制操作,然后设置当前 CPU 的任务指针,*/ #ifdef LOSCFG_EXC_INTERACTION err = memmove_s(m_aucSysMem0, g_excInteractMemSize, g_excInteractionMemStart, g_excInteractionMemSize); if (err != EOK) { @@ -243,6 +269,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OsSystemWakeup(VOID) cpuid = ArchCurrCpuid(); OsCurrTaskSet(g_saveTsk[cpuid]); +/*设置系统计数器频率。接着,它重置内存池的末尾节点,清零 BSS 区域的数据,重新初始化中断*/ /* Set system counter freq */ HalClockFreqWrite(OS_SYS_CLOCK); dsb(); @@ -270,7 +297,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OsSystemWakeup(VOID) #ifdef LOSCFG_KERNEL_CPUP OsSetCpuCycle(0); #endif - +/*并调用 OsSRRestoreRegister 函数恢复寄存器状态*/ #if (LOSCFG_KERNEL_SMP == YES) release_secondary_cores(); #endif @@ -281,32 +308,33 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsWaitImagingDone(UINTPTR wowFlashAddr, size_t *wo { UINT32 ret; - g_flashImgAddr = wowFlashAddr; - (VOID)LOS_EventInit(&g_suspendResumeEvent); + g_flashImgAddr = wowFlashAddr; /*烧录的flash地址*/ + (VOID)LOS_EventInit(&g_suspendResumeEvent); /*指向用于存储烧录镜像大小的变量的指针*/ - // This flag will be stored into flash, and will affect the wakeup procedure when cpu is rebooting. + // 这个标志将被存储到闪存中,当 CPU 重新启动时,它将影响唤醒流程。 g_resumeFromImg = LOS_RUN_STOP_RESET; - // This flag affects the suspending procedure later, - // and will be reset depending on 'g_resumeFromImg' when cpu is rebooting. + // 这个标志会影响之后的挂起过程,并且在 CPU 重新启动时根据 'g_resumeFromImg' 的值进行重置 g_otherCoreResume = 0; - g_sysDoneFlag[LOSCFG_KERNEL_CORE_NUM - 1] = OS_STORE_SYSTEM; + g_sysDoneFlag[LOSCFG_KERNEL_CORE_NUM - 1] = OS_STORE_SYSTEM; /*表示系统状态需要被保存*/ ret = LOS_EventRead(&g_suspendResumeEvent, 0xFF, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); + /*等待事件发生*/ if (wowImgSize != NULL) { *wowImgSize = g_wowImgSize; - } + }/*保证能够在烧录完成之后正确的保存和恢复状态*/ return ret; } -LITE_OS_SEC_TEXT_MINOR VOID OsCarryLeftScatter(VOID) +LITE_OS_SEC_TEXT_MINOR VOID OsCarryLeftScatter(VOID) /*将位于RAM的数据从指定位置复制到Flash存储器中*/ { size_t size; UINTPTR memAddr; - size_t wowSize; - size_t readAlignSize; - size_t eraseAlignSize; - size_t writeAlignSize; + size_t wowSize;/*等待复制数据的大小*/ + size_t readAlignSize;/*读取对齐大小*/ + size_t eraseAlignSize;/*擦除对齐大小*/ + size_t writeAlignSize;/*写入对齐大小*/ + /*读取所有参数的初始状态*/ UINTPTR imageFlashAddr; FLASH_READ_FUNC flashReadFunc = g_runstopParam.pfFlashReadFunc; @@ -315,18 +343,19 @@ LITE_OS_SEC_TEXT_MINOR VOID OsCarryLeftScatter(VOID) eraseAlignSize = g_runstopParam.uwFlashEraseAlignSize; writeAlignSize = g_runstopParam.uwFlashWriteAlignSize; writeAlignSize = (writeAlignSize >= eraseAlignSize) ? writeAlignSize : eraseAlignSize; - + /*计算wowsize的大小,根据对齐大小调整值*/ wowSize = ((UINTPTR)&__wow_end) - ((UINTPTR)&__ram_vectors_vma); wowSize = (wowSize + writeAlignSize - 1) & ~(writeAlignSize - 1); imageFlashAddr += wowSize; - + /*检查memaddr是否超出了BSS段的起始地址*/ memAddr = ((UINTPTR)&__ram_vectors_vma) + wowSize; if (memAddr >= ((UINTPTR)&__bss_start)) { return; } + /*计算了要复制的数据大小,在磁盘中根据对齐大小调整size*/ size = ((UINTPTR)&__int_stack_start) - memAddr; size = (size + readAlignSize - 1) & ~(readAlignSize - 1); - + /*将RAM中的数据从memaddr复制到flash存储器的imageflashaddr,进行缓存和同步操作*/ if ((flashReadFunc != NULL) && (flashReadFunc((VOID *)memAddr, imageFlashAddr, size) != 0)) { PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__); } @@ -336,6 +365,8 @@ LITE_OS_SEC_TEXT_MINOR VOID OsCarryLeftScatter(VOID) } LITE_OS_SEC_TEXT_MINOR VOID OsRunstopParamInit(const RUNSTOP_PARAM_S *runstopParam) +/*初始化运行暂停功能所需的参数,保存在全局变量g_中,以便告诉计算机目前的系统转台 +包含了运行暂停功能所需的各个回调函数和对齐大小等参数*/ { g_runstopParam.pfIdleWakeupCallback = runstopParam->pfIdleWakeupCallback; g_runstopParam.pfWakeupCallback = runstopParam->pfWakeupCallback; @@ -350,28 +381,31 @@ LITE_OS_SEC_TEXT_MINOR VOID OsRunstopParamInit(const RUNSTOP_PARAM_S *runstopPar } LITE_OS_SEC_TEXT_MINOR VOID LOS_MakeImage(RUNSTOP_PARAM_S *runstopParam) +/*用于除法运行暂停功能的操作,并根据返回值进行相应处理*/ { UINT32 ret; size_t imgSize; - + /*检查是否需要暂停*/ if (runstopParam == NULL) { return; } + /*调用函数,将传入的runstopparam转换为全局变量*/ OsRunstopParamInit(runstopParam); ret = OsWaitImagingDone(g_runstopParam.uwWowFlashAddr, &imgSize); - if (ret == WAKEUP_FROM_SUSPEND) { + /*用于等待图像转移完成,范围相应的状态码ret和图像大小imgsize*/ + if (ret == WAKEUP_FROM_SUSPEND) { /*从暂停状态唤醒,并查看系统是否需要空闲唤醒回调*/ if (g_runstopParam.pfWakeupCallback != NULL) { g_runstopParam.pfWakeupCallback(); } - OsCarryLeftScatter(); + OsCarryLeftScatter(); /*将RAM中的数据复制到Flash存储器*/ PRINT_INFO("Resume ok!\n"); - } else if (ret == FLASH_IMG_SUCCESS) { + } else if (ret == FLASH_IMG_SUCCESS) { /*闪存图像成功*/ if (g_runstopParam.pfImageDoneCallback != NULL) { g_runstopParam.pfImageDoneCallback(); } - PRINT_INFO("Flash ok! Image length 0x%x\n", imgSize); + PRINT_INFO("Flash ok! Image length 0x%x\n", imgSize);/*图像转移成功,并打印图像大小*/ } } @@ -380,8 +414,9 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsWowWriteFlashTaskCreate(VOID) UINT32 ret; UINT32 writeFlashTaskId; TSK_INIT_PARAM_S taskInitParam; - + /*首先对任务初始化参数进行了清零操作*/ (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); + /*设置了任务入口函数,并且制定了任务的堆栈大小,任务名和优先级*/ taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsWriteToFlashTask; taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; taskInitParam.pcName = "WowWriteFlashTask"; @@ -389,24 +424,28 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsWowWriteFlashTaskCreate(VOID) #ifdef LOSCFG_KERNEL_SMP taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(0); #endif + /*创建任务,返回结果*/ ret = LOS_TaskCreate(&writeFlashTaskId, &taskInitParam); return ret; } LITE_OS_SEC_TEXT_MINOR size_t OsWowImageSizeGet(VOID) +/*获取wow图像的大小,返回全局变量*/ { return g_wowImgSize; } LITE_OS_SEC_TEXT_MINOR UINT32 OsWowSysDoneFlagGet(VOID) +/*获取wow系统完成的标志*/ { UINT32 cpuid = ArchCurrCpuid(); return g_sysDoneFlag[cpuid]; } LITE_OS_SEC_TEXT_MINOR VOID OsWowOtherCoreResume(UINT32 cpuid) +/*唤醒其他的核心*/ { - if (g_otherCoreResume == 1) { + if (g_otherCoreResume == 1) { /*全局变量的值为1则表示需要唤醒其他核心*/ OsCurrTaskSet(g_saveTsk[cpuid]); OsSRRestoreRegister(); } diff --git a/src/kernel/extended/lowpower/tickless/los_tickless.c b/src/kernel/extended/lowpower/tickless/los_tickless.c index fdeb5b8..d609b1e 100644 --- a/src/kernel/extended/lowpower/tickless/los_tickless.c +++ b/src/kernel/extended/lowpower/tickless/los_tickless.c @@ -46,42 +46,46 @@ STATIC volatile UINT32 g_sleepTicks[LOSCFG_KERNEL_CORE_NUM] = {0}; (((GET_SYS_CLOCK()) / (g_tickPerSecond)) - (cyclesCur)) : \ ((((GET_SYS_CLOCK()) / (g_tickPerSecond)) << 1) - (cyclesCur))) -LITE_OS_SEC_TEXT VOID LOS_TicklessEnable(VOID) +LITE_OS_SEC_TEXT VOID LOS_TicklessEnable(VOID) /*开启Tickless功能*/ { g_ticklessFlag = TRUE; + /*变量表示Tickless功能的开启状态,为TRUE表示已开启,为FALSE表示已关闭。*/ } -LITE_OS_SEC_TEXT VOID LOS_TicklessDisable(VOID) +LITE_OS_SEC_TEXT VOID LOS_TicklessDisable(VOID) /*开启Tickless功能*/ { g_ticklessFlag = FALSE; } -LITE_OS_SEC_TEXT BOOL OsTicklessFlagGet(VOID) +LITE_OS_SEC_TEXT BOOL OsTicklessFlagGet(VOID) /*用于获取Tickless标志的状态*/ { return g_ticklessFlag; } -LITE_OS_SEC_TEXT BOOL OsTickIrqFlagGet(VOID) +LITE_OS_SEC_TEXT BOOL OsTickIrqFlagGet(VOID) { return g_tickIrqFlag[ArchCurrCpuid()]; + /*数组表示每个核心的Tick中断标志的状态, + 为TRUE表示中断正在处理中,为FALSE表示中断未处理。*/ } -LITE_OS_SEC_TEXT VOID OsTickIrqFlagSet(BOOL tickIrqFlag) +LITE_OS_SEC_TEXT VOID OsTickIrqFlagSet(BOOL tickIrqFlag) /*用于设置当前核心的时钟中断标志*/ { g_tickIrqFlag[ArchCurrCpuid()] = tickIrqFlag; } -LITE_OS_SEC_TEXT UINT32 OsTicklessSleepTickGet(VOID) +LITE_OS_SEC_TEXT UINT32 OsTicklessSleepTickGet(VOID) /*用于获取当前系统的睡眠计时器的数值*/ { return g_sleepTicks[ArchCurrCpuid()]; } -LITE_OS_SEC_TEXT VOID OsTicklessSleepTickSet(UINT32 sleeptick) +LITE_OS_SEC_TEXT VOID OsTicklessSleepTickSet(UINT32 sleeptick) /*设置当前核心得到睡眠计时器的数值*/ { g_sleepTicks[ArchCurrCpuid()] = sleeptick; } -LITE_OS_SEC_TEXT UINT32 OsSleepTicksGet(VOID) +LITE_OS_SEC_TEXT UINT32 OsSleepTicksGet(VOID) /*函数用于获取当前需要休眠的ticks数,通过查询任务链表和软件定时器链表, + 找到最小的定时器到期时间,作为休眠时长。*/ { UINT32 tskSortLinkTicks, sleepTicks; @@ -104,7 +108,8 @@ LITE_OS_SEC_TEXT UINT32 OsSleepTicksGet(VOID) return sleepTicks; } -LITE_OS_SEC_TEXT VOID OsSysTimeUpdate(UINT32 sleepTicks) +LITE_OS_SEC_TEXT VOID OsSysTimeUpdate(UINT32 sleepTicks) /*用于更新系统时间, + 根据休眠时长更新全局计数器和任务链表、软件定时器链表的到期时间*/ { UINT32 intSave; @@ -127,7 +132,7 @@ LITE_OS_SEC_TEXT VOID OsSysTimeUpdate(UINT32 sleepTicks) LOS_IntRestore(intSave); } -VOID OsTicklessUpdate(UINT32 irqnum) +VOID OsTicklessUpdate(UINT32 irqnum) /*OsTicklessUpdate函数用于在发生中断时更新系统时间*/ { UINT32 cycles, ticks; UINT32 cyclesPertick; @@ -165,7 +170,8 @@ VOID OsTicklessUpdate(UINT32 irqnum) LOS_IntRestore(intSave); } -VOID OsTicklessStart(VOID) +VOID OsTicklessStart(VOID) /*Tickless模式的入口函数,根据休眠时长计算需要延迟的周期数, + 并设置定时器的重载值,启动Tickless模式。*/ { UINT32 intSave; /* @@ -202,7 +208,8 @@ VOID OsTicklessStart(VOID) return; } -VOID OsTicklessOpen(VOID) +VOID OsTicklessOpen(VOID) /*在Tick中断处理函数中开启Tickless模式。 + 当Tick中断处理函数检测到Tickless标志为1时,调用该函数启动Tickless模式。*/ { if (OsTickIrqFlagGet()) { OsTickIrqFlagSet(0); diff --git a/src/kernel/extended/perf/los_perf.c b/src/kernel/extended/perf/los_perf.c index ecb0c2e..e8b84f6 100644 --- a/src/kernel/extended/perf/los_perf.c +++ b/src/kernel/extended/perf/los_perf.c @@ -37,10 +37,11 @@ extern "C" { #endif /* __cplusplus */ #ifdef LOSCFG_KERNEL_PERF -STATIC Pmu *g_pmu = NULL; -STATIC PerfCB g_perfCb = {0}; +STATIC Pmu *g_pmu = NULL;//用于保存当前系统中所使用的硬件性能计数器 +STATIC PerfCB g_perfCb = {0};//保存了性能测量回调函数和一些测量结果数据 LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_perfSpin); +//定义了一个自旋锁 g_perfSpin,用于保护性能测量模块在多线程环境下的并发访问 #define PERF_LOCK(state) LOS_SpinLockSave(&g_perfSpin, &(state)) #define PERF_UNLOCK(state) LOS_SpinUnlockRestore(&g_perfSpin, (state)) @@ -55,8 +56,9 @@ STATIC INLINE UINT64 OsPerfGetCurrTime(VOID) #endif } -STATIC UINT32 OsPmuInit(VOID) +STATIC UINT32 OsPmuInit(VOID)//初始化性能计数器 { + //判断是否开启了计数器 #ifdef LOSCFG_PERF_HW_PMU if (OsHwPmuInit() != LOS_OK) { return LOS_ERRNO_PERF_HW_INIT_ERROR; @@ -77,13 +79,13 @@ STATIC UINT32 OsPmuInit(VOID) return LOS_OK; } -STATIC UINT32 OsPerfConfig(PerfEventConfig *eventsCfg) +STATIC UINT32 OsPerfConfig(PerfEventConfig *eventsCfg)//配置性能计数器 { UINT32 i; UINT32 ret; g_pmu = OsPerfPmuGet(eventsCfg->type); - if (g_pmu == NULL) { + if (g_pmu == NULL) {//根据配置的类型获取对应的性能计数器对象 PRINT_ERR("perf config type error %u!\n", eventsCfg->type); return LOS_ERRNO_PERF_INVALID_PMU; } @@ -92,6 +94,7 @@ STATIC UINT32 OsPerfConfig(PerfEventConfig *eventsCfg) (VOID)memset_s(&g_pmu->events, sizeof(PerfEvent), 0, sizeof(PerfEvent)); +//根据配置信息设置各性能事件的参数,调用性能计数器对象的配置函数进行配置 for (i = 0; i < eventNum; i++) { g_pmu->events.per[i].eventId = eventsCfg->events[i].eventId; g_pmu->events.per[i].period = eventsCfg->events[i].period; @@ -109,13 +112,13 @@ STATIC UINT32 OsPerfConfig(PerfEventConfig *eventsCfg) return LOS_OK; } -STATIC VOID OsPerfPrintCount(VOID) +STATIC VOID OsPerfPrintCount(VOID)//用于打印性能计数器的统计信息 { UINT32 index; UINT32 intSave; UINT32 cpuid = ArchCurrCpuid(); - PerfEvent *events = &g_pmu->events; + PerfEvent *events = &g_pmu->events;//获取性能计数器对象的性能时间数组和事件数量 UINT32 eventNum = events->nr; PERF_LOCK(intSave); @@ -123,7 +126,7 @@ STATIC VOID OsPerfPrintCount(VOID) Event *event = &(events->per[index]); /* filter out event counter with no event binded. */ - if (event->period == 0) { + if (event->period == 0) { //事件周期 continue; } PRINT_EMG("[%s] eventType: 0x%x [core %u]: %llu\n", g_pmu->getName(event), event->eventId, cpuid, @@ -132,7 +135,7 @@ STATIC VOID OsPerfPrintCount(VOID) PERF_UNLOCK(intSave); } -STATIC INLINE VOID OsPerfPrintTs(VOID) +STATIC INLINE VOID OsPerfPrintTs(VOID)//打印时间信息 { #ifdef LOSCFG_PERF_CALC_TIME_BY_TICK DOUBLE time = (g_perfCb.endTime - g_perfCb.startTime) * 1.0 / LOSCFG_BASE_CORE_TICK_PER_SECOND; @@ -142,7 +145,7 @@ STATIC INLINE VOID OsPerfPrintTs(VOID) PRINT_EMG("time used: %.6f(s)\r\n", time); } -STATIC VOID OsPerfStart(VOID) +STATIC VOID OsPerfStart(VOID)//启动及更新CPU和计数器状态 { UINT32 cpuid = ArchCurrCpuid(); @@ -152,7 +155,7 @@ STATIC VOID OsPerfStart(VOID) } if (g_perfCb.pmuStatusPerCpu[cpuid] != PERF_PMU_STARTED) { - UINT32 ret = g_pmu->start(); + UINT32 ret = g_pmu->start();//若计数器未启动则启动 if (ret != LOS_OK) { PRINT_ERR("perf start on core:%u failed, ret = 0x%x\n", cpuid, ret); return; @@ -164,7 +167,7 @@ STATIC VOID OsPerfStart(VOID) } } -STATIC VOID OsPerfStop(VOID) +STATIC VOID OsPerfStop(VOID)//停止性能计数器 { UINT32 cpuid = ArchCurrCpuid(); @@ -191,19 +194,21 @@ STATIC VOID OsPerfStop(VOID) } STATIC UINT32 OsPerfBackTrace(UINTPTR *callChain, UINT32 maxDepth, PerfRegs *regs) +//获取当前函数调用链的信息,并将结果存储在 callChain 数组中 { UINT32 i; - UINT32 count = ArchBackTraceGet(regs->fp, callChain, maxDepth); + UINT32 count = ArchBackTraceGet(regs->fp, callChain, maxDepth);//获取当前状态的帧指针值 PRINT_DEBUG("backtrace depth = %u, fp = 0x%x\n", count, regs->fp); for (i = 0; i < count; i++) { - PRINT_DEBUG("ip[%u]: 0x%x\n", i, callChain[i]); + PRINT_DEBUG("ip[%u]: 0x%x\n", i, callChain[i]);//打印调用链中每个函数的指令地址 } - return count; + return count;//返回用链的深度 } STATIC UINT32 OsPerfCollectData(Event *event, PerfSampleData *data, PerfRegs *regs) +//收集性能计数器的数据,并将其存储在 data 结构体中 { UINT32 size = 0; UINT32 depth; @@ -211,12 +216,12 @@ STATIC UINT32 OsPerfCollectData(Event *event, PerfSampleData *data, PerfRegs *re CHAR *p = (CHAR *)data; if (sampleType & PERF_RECORD_CPU) { - *(UINT32 *)(p + size) = ArchCurrCpuid(); + *(UINT32 *)(p + size) = ArchCurrCpuid();//函数获取当前CPU的ID,并存储在 data->cpuid 字段中 size += sizeof(data->cpuid); } if (sampleType & PERF_RECORD_TID) { - *(UINT32 *)(p + size) = LOS_CurTaskIDGet(); + *(UINT32 *)(p + size) = LOS_CurTaskIDGet();// 函数获取当前任务的ID,并存储在 data->taskId 字段中 size += sizeof(data->taskId); } @@ -231,7 +236,7 @@ STATIC UINT32 OsPerfCollectData(Event *event, PerfSampleData *data, PerfRegs *re } if (sampleType & PERF_RECORD_TIMESTAMP) { - *(UINT64 *)(p + size) = OsPerfGetCurrTime(); + *(UINT64 *)(p + size) = OsPerfGetCurrTime();//获取当前时间戳,并存储在 data->time 字段中 size += sizeof(data->time); } @@ -254,7 +259,7 @@ STATIC UINT32 OsPerfCollectData(Event *event, PerfSampleData *data, PerfRegs *re * return TRUE if user haven't specified any taskId(which is supposed * to instrument the whole system) */ -STATIC BOOL OsPerfTaskFilter(UINT32 taskId) +STATIC BOOL OsPerfTaskFilter(UINT32 taskId)//过滤任务ID,判断一个给定的任务ID是否需要进行性能优化 { UINT32 i; @@ -262,7 +267,7 @@ STATIC BOOL OsPerfTaskFilter(UINT32 taskId) return TRUE; } - for (i = 0; i < g_perfCb.taskIdsNr; i++) { + for (i = 0; i < g_perfCb.taskIdsNr; i++) { //储存允许过滤任务ID的列表 if (g_perfCb.taskIds[i] == taskId) { return TRUE; } @@ -270,7 +275,7 @@ STATIC BOOL OsPerfTaskFilter(UINT32 taskId) return FALSE; } -STATIC INLINE UINT32 OsPerfParamValid(VOID) +STATIC INLINE UINT32 OsPerfParamValid(VOID)//检查性能函数的有效性 { UINT32 index; UINT32 res = 0; @@ -287,7 +292,7 @@ STATIC INLINE UINT32 OsPerfParamValid(VOID) return res; } -STATIC UINT32 OsPerfHdrInit(UINT32 id) +STATIC UINT32 OsPerfHdrInit(UINT32 id)//初始化性能数据的头部信息 { PerfDataHdr head = { .magic = PERF_DATA_MAGIC_WORD, @@ -299,7 +304,7 @@ STATIC UINT32 OsPerfHdrInit(UINT32 id) return OsPerfOutPutWrite((CHAR *)&head, head.len); } -VOID OsPerfUpdateEventCount(Event *event, UINT32 value) +VOID OsPerfUpdateEventCount(Event *event, UINT32 value)//更新上传事件的技术 { if (event == NULL) { return; @@ -307,46 +312,46 @@ VOID OsPerfUpdateEventCount(Event *event, UINT32 value) event->count[ArchCurrCpuid()] += (value & 0xFFFFFFFF); /* event->count is UINT64 */ } -VOID OsPerfHandleOverFlow(Event *event, PerfRegs *regs) +VOID OsPerfHandleOverFlow(Event *event, PerfRegs *regs)//处理性能计数器溢出的情况 { PerfSampleData data; UINT32 len; (VOID)memset_s(&data, sizeof(PerfSampleData), 0, sizeof(PerfSampleData)); - if ((g_perfCb.needSample) && OsPerfTaskFilter(LOS_CurTaskIDGet())) { + if ((g_perfCb.needSample) && OsPerfTaskFilter(LOS_CurTaskIDGet())) {//判断是否优化 len = OsPerfCollectData(event, &data, regs); OsPerfOutPutWrite((CHAR *)&data, len); } } -UINT32 LOS_PerfInit(VOID *buf, UINT32 size) +UINT32 LOS_PerfInit(VOID *buf, UINT32 size)//初始化性能统计模块 { UINT32 ret; UINT32 intSave; - PERF_LOCK(intSave); + PERF_LOCK(intSave);//保存中断状态 if (g_perfCb.status != PERF_UNINIT) { ret = LOS_ERRNO_PERF_STATUS_INVALID; goto PERF_INIT_ERROR; } - ret = OsPmuInit(); + ret = OsPmuInit();//函数性能计数器初始化 if (ret != LOS_OK) { goto PERF_INIT_ERROR; } - ret = OsPerfOutPutInit(buf, size); + ret = OsPerfOutPutInit(buf, size);//性能输出缓冲区进行初始化 if (ret != LOS_OK) { ret = LOS_ERRNO_PERF_BUF_ERROR; goto PERF_INIT_ERROR; } g_perfCb.status = PERF_STOPED; PERF_INIT_ERROR: - PERF_UNLOCK(intSave); + PERF_UNLOCK(intSave);//解锁中断处理 return ret; } -UINT32 LOS_PerfConfig(PerfConfigAttr *attr) +UINT32 LOS_PerfConfig(PerfConfigAttr *attr)//配置性能统计模块的属性 { UINT32 ret; UINT32 intSave; @@ -355,20 +360,20 @@ UINT32 LOS_PerfConfig(PerfConfigAttr *attr) return LOS_ERRNO_PERF_CONFIG_NULL; } - PERF_LOCK(intSave); + PERF_LOCK(intSave);//保存中断状态 if (g_perfCb.status != PERF_STOPED) { ret = LOS_ERRNO_PERF_STATUS_INVALID; PRINT_ERR("perf config status error : 0x%x\n", g_perfCb.status); goto PERF_CONFIG_ERROR; } - g_pmu = NULL; + g_pmu = NULL;//将全局标量PMU计数器置零 g_perfCb.needSample = attr->needSample; g_perfCb.taskFilterEnable = attr->taskFilterEnable; g_perfCb.sampleType = attr->sampleType; - if (attr->taskFilterEnable) { + if (attr->taskFilterEnable) {//开启任务过滤功能 ret = memcpy_s(g_perfCb.taskIds, PERF_MAX_FILTER_TSKS * sizeof(UINT32), attr->taskIds, g_perfCb.taskIdsNr * sizeof(UINT32)); if (ret != EOK) { @@ -377,29 +382,29 @@ UINT32 LOS_PerfConfig(PerfConfigAttr *attr) } g_perfCb.taskIdsNr = MIN(attr->taskIdsNr, PERF_MAX_FILTER_TSKS); } - ret = OsPerfConfig(&attr->eventsCfg); + ret = OsPerfConfig(&attr->eventsCfg);//对事件配置进行处理 PERF_CONFIG_ERROR: PERF_UNLOCK(intSave); return ret; } -VOID LOS_PerfStart(UINT32 sectionId) +VOID LOS_PerfStart(UINT32 sectionId)//启动性能统计模块 { UINT32 intSave; UINT32 ret; PERF_LOCK(intSave); - if (g_perfCb.status != PERF_STOPED) { + if (g_perfCb.status != PERF_STOPED) {//判断统计模块是否打开 PRINT_ERR("perf start status error : 0x%x\n", g_perfCb.status); goto PERF_START_ERROR; } - if (!OsPerfParamValid()) { + if (!OsPerfParamValid()) {//检车行呢个统计模块的参数是否有效 PRINT_ERR("forgot call `LOS_Config(...)` before instrumenting?\n"); goto PERF_START_ERROR; } - if (g_perfCb.needSample) { + if (g_perfCb.needSample) {//判断是否需要抽样 ret = OsPerfHdrInit(sectionId); /* section header init */ if (ret != LOS_OK) { PRINT_ERR("perf hdr init error 0x%x\n", ret); @@ -407,7 +412,7 @@ VOID LOS_PerfStart(UINT32 sectionId) } } - SMP_CALL_PERF_FUNC(OsPerfStart); /* send to all cpu to start pmu */ + SMP_CALL_PERF_FUNC(OsPerfStart); /* 所有CPU开始PMU计数器,启动性能统计模块i奥 */ g_perfCb.status = PERF_STARTED; g_perfCb.startTime = OsPerfGetCurrTime(); PERF_START_ERROR: @@ -415,7 +420,7 @@ PERF_START_ERROR: return; } -VOID LOS_PerfStop(VOID) +VOID LOS_PerfStop(VOID)//停止性能统计模块的运行,进行一些清理操作 { UINT32 intSave; @@ -427,12 +432,12 @@ VOID LOS_PerfStop(VOID) SMP_CALL_PERF_FUNC(OsPerfStop); /* send to all cpu to stop pmu */ - OsPerfOutPutFlush(); + OsPerfOutPutFlush();//刷新输出操作 if (g_perfCb.needSample) { OsPerfOutPutInfo(); } - + //更新了两个全局变量的值,表示性能统计模块已经在状态上和时间上停止了 g_perfCb.status = PERF_STOPED; g_perfCb.endTime = OsPerfGetCurrTime(); @@ -442,21 +447,21 @@ PERF_STOP_ERROR: return; } -UINT32 LOS_PerfDataRead(CHAR *dest, UINT32 size) +UINT32 LOS_PerfDataRead(CHAR *dest, UINT32 size)//从性能统计门票快的输出缓冲区中读取数据到指定的内存 { return OsPerfOutPutRead(dest, size); } -VOID LOS_PerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func) +VOID LOS_PerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func)//注册型那个统计模块的通知hook函数 { UINT32 intSave; - + //保存中断状态,恢复中断状态 PERF_LOCK(intSave); OsPerfNotifyHookReg(func); PERF_UNLOCK(intSave); } -VOID LOS_PerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func) +VOID LOS_PerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func)//刷新hook { UINT32 intSave; @@ -465,7 +470,7 @@ VOID LOS_PerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func) PERF_UNLOCK(intSave); } -VOID OsPerfSetIrqRegs(UINTPTR pc, UINTPTR fp) +VOID OsPerfSetIrqRegs(UINTPTR pc, UINTPTR fp)//设置中断相关的寄存器,用于中断时的性能统计 { LosTaskCB *runTask = (LosTaskCB *)ArchCurrTaskGet(); runTask->pc = pc; diff --git a/src/kernel/extended/perf/perf_output.c b/src/kernel/extended/perf/perf_output.c index 20bea3a..a83d806 100644 --- a/src/kernel/extended/perf/perf_output.c +++ b/src/kernel/extended/perf/perf_output.c @@ -39,11 +39,14 @@ STATIC PERF_BUF_FLUSH_HOOK g_perfBufFlushHook = NULL; STATIC PerfOutputCB g_perfOutputCb; STATIC VOID OsPerfDefaultNotify(VOID) +//默认的性能缓冲区通知回调函数,在性能缓冲区的水位线达到一定值时打印一条信息 { PRINT_INFO("perf buf waterline notify!\n"); } UINT32 OsPerfOutPutInit(VOID *buf, UINT32 size) +//初始化性能输出模块。如果传入的缓冲区指针为空,则使用LOS_MemAlloc函数动态分配内存。 +//然后初始化环形缓冲区,设置水位线,并注册默认的性能缓冲区通知回调函数 { UINT32 ret; BOOL releaseFlag = FALSE; @@ -69,21 +72,22 @@ RELEASE: return ret; } -VOID OsPerfOutPutFlush(VOID) +VOID OsPerfOutPutFlush(VOID)//刷新性能输出缓冲区 { if (g_perfBufFlushHook != NULL) { g_perfBufFlushHook(g_perfOutputCb.ringbuf.fifo, g_perfOutputCb.ringbuf.size); } } -UINT32 OsPerfOutPutRead(CHAR *dest, UINT32 size) +UINT32 OsPerfOutPutRead(CHAR *dest, UINT32 size)//从性能输出缓冲区中读取数据 { OsPerfOutPutFlush(); return LOS_RingbufRead(&g_perfOutputCb.ringbuf, dest, size); } -STATIC BOOL OsPerfOutPutBegin(UINT32 size) +STATIC BOOL OsPerfOutPutBegin(UINT32 size)//开始写入性能输出缓冲区 { + //检查是否有足够空间 if (g_perfOutputCb.ringbuf.remain < size) { PRINT_INFO("perf buf has no enough space for 0x%x\n", size); return FALSE; @@ -91,9 +95,9 @@ STATIC BOOL OsPerfOutPutBegin(UINT32 size) return TRUE; } -STATIC VOID OsPerfOutPutEnd(VOID) +STATIC VOID OsPerfOutPutEnd(VOID)//结束性能输出 { - OsPerfOutPutFlush(); + OsPerfOutPutFlush();//刷新缓冲区 if (LOS_RingbufUsedSize(&g_perfOutputCb.ringbuf) >= g_perfOutputCb.waterMark) { if (g_perfBufNotifyHook != NULL) { g_perfBufNotifyHook(); @@ -101,7 +105,7 @@ STATIC VOID OsPerfOutPutEnd(VOID) } } -UINT32 OsPerfOutPutWrite(CHAR *data, UINT32 size) +UINT32 OsPerfOutPutWrite(CHAR *data, UINT32 size)//将数据写入性能输入缓冲区 { if (!OsPerfOutPutBegin(size)) { return LOS_NOK; @@ -113,17 +117,17 @@ UINT32 OsPerfOutPutWrite(CHAR *data, UINT32 size) return LOS_OK; } -VOID OsPerfOutPutInfo(VOID) +VOID OsPerfOutPutInfo(VOID)//打印性能输出缓冲区的信息,包括地址和长度 { PRINT_EMG("dump section data, addr: %p length: %#x \r\n", g_perfOutputCb.ringbuf.fifo, g_perfOutputCb.ringbuf.size); } -VOID OsPerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func) +VOID OsPerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func)//注册性能缓冲区通知 { g_perfBufNotifyHook = func; } -VOID OsPerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func) +VOID OsPerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func)//注册性能缓冲区刷新的函数 { g_perfBufFlushHook = func; } diff --git a/src/kernel/extended/perf/perf_output_pri.h b/src/kernel/extended/perf/perf_output_pri.h index 382f2a9..603e64d 100644 --- a/src/kernel/extended/perf/perf_output_pri.h +++ b/src/kernel/extended/perf/perf_output_pri.h @@ -43,13 +43,13 @@ typedef struct { UINT32 waterMark; /* notify water mark */ } PerfOutputCB; -extern UINT32 OsPerfOutPutInit(VOID *buf, UINT32 size); -extern UINT32 OsPerfOutPutRead(CHAR *dest, UINT32 size); -extern UINT32 OsPerfOutPutWrite(CHAR *data, UINT32 size); -extern VOID OsPerfOutPutInfo(VOID); -extern VOID OsPerfOutPutFlush(VOID); -extern VOID OsPerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func); -extern VOID OsPerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func); +extern UINT32 OsPerfOutPutInit(VOID *buf, UINT32 size);//初始化性能输出模块 +extern UINT32 OsPerfOutPutRead(CHAR *dest, UINT32 size);//从性能输出缓冲区中读取数据,将数据拷贝到指定的目标缓冲区中 +extern UINT32 OsPerfOutPutWrite(CHAR *data, UINT32 size);//将数据写入性能输出缓冲区 +extern VOID OsPerfOutPutInfo(VOID);//输出性能统计信息 +extern VOID OsPerfOutPutFlush(VOID);//刷新性能输出缓冲区 +extern VOID OsPerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func);//注册性能输出缓冲区通知 +extern VOID OsPerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func);//注册性能输出缓冲区刷新 #ifdef __cplusplus #if __cplusplus diff --git a/src/kernel/extended/perf/perf_pmu.c b/src/kernel/extended/perf/perf_pmu.c index a2771ba..ff5cca6 100644 --- a/src/kernel/extended/perf/perf_pmu.c +++ b/src/kernel/extended/perf/perf_pmu.c @@ -36,11 +36,11 @@ extern "C" { STATIC Pmu *g_pmuMgr[PERF_EVENT_TYPE_MAX] = {NULL}; -UINT32 OsPerfPmuRegister(Pmu *pmu) +UINT32 OsPerfPmuRegister(Pmu *pmu)//注册性能计数器 { UINT32 type; - if ((pmu == NULL) || (pmu->type >= PERF_EVENT_TYPE_MAX)) { + if ((pmu == NULL) || (pmu->type >= PERF_EVENT_TYPE_MAX)) {//如果传入PMU为空指针或者type超出了有效范围 return LOS_NOK; } @@ -52,19 +52,20 @@ UINT32 OsPerfPmuRegister(Pmu *pmu) return LOS_NOK; } -Pmu *OsPerfPmuGet(UINT32 type) +Pmu *OsPerfPmuGet(UINT32 type)//获取指定类型的性能计数器 { if (type >= PERF_EVENT_TYPE_MAX) { return NULL; } - if (type == PERF_EVENT_TYPE_RAW) { /* process hardware raw events with hard pmu */ - type = PERF_EVENT_TYPE_HW; + if (type == PERF_EVENT_TYPE_RAW) { //如果是原始事件类型 + /* process hardware raw events with hard pmu */ + type = PERF_EVENT_TYPE_HW;//则将其转化为硬件事件类型 } return g_pmuMgr[type]; } -VOID OsPerfPmuRm(UINT32 type) +VOID OsPerfPmuRm(UINT32 type)//删除指定类型的性能计数器 { if (type >= PERF_EVENT_TYPE_MAX) { return; diff --git a/src/kernel/extended/perf/perf_pmu_pri.h b/src/kernel/extended/perf/perf_pmu_pri.h index 2507d34..4cbb5bd 100644 --- a/src/kernel/extended/perf/perf_pmu_pri.h +++ b/src/kernel/extended/perf/perf_pmu_pri.h @@ -53,7 +53,7 @@ typedef struct { VOID (*setPeriod)(Event *event); UINTPTR (*readCnt)(Event *event); UINT32 (*mapEvent)(UINT32 eventType, BOOL reverse); -} HwPmu; +} HwPmu;//硬件性能计数器结构体,包括硬件计数器、计数器是否能被分频、分频系数、启用、禁用、开始、停止、清除、设置周期、读取计数器值和事件映射等函数指针 typedef struct { Pmu pmu; @@ -69,35 +69,35 @@ typedef struct { }; #endif }; -} SwPmu; +} SwPmu;//软件性能计数器结构体,包括软件计数器、是否启用标志位、定时器配置时间 #define GET_HW_PMU(item) LOS_DL_LIST_ENTRY(item, HwPmu, pmu) -#define TIMER_PERIOD_LOWER_BOUND_US 100 +#define TIMER_PERIOD_LOWER_BOUND_US 100//定时器最小周期 -#define CCNT_FULL 0xFFFFFFFF -#define CCNT_PERIOD_LOWER_BOUND 0x00000000 -#define CCNT_PERIOD_UPPER_BOUND 0xFFFFFF00 -#define PERIOD_CALC(p) (CCNT_FULL - (p)) +#define CCNT_FULL 0xFFFFFFFF//计数器最大值 +#define CCNT_PERIOD_LOWER_BOUND 0x00000000//最小周期 +#define CCNT_PERIOD_UPPER_BOUND 0xFFFFFF00//最大周期 +#define PERIOD_CALC(p) (CCNT_FULL - (p))//计算给定周期对应的计数器值 #define VALID_PERIOD(p) ((PERIOD_CALC(p) > CCNT_PERIOD_LOWER_BOUND) \ - && (PERIOD_CALC(p) < CCNT_PERIOD_UPPER_BOUND)) + && (PERIOD_CALC(p) < CCNT_PERIOD_UPPER_BOUND))//判断给定周期是否合法 -#define PERF_HW_INVAILD_EVENT_TYPE 0xFFFFFFFF +#define PERF_HW_INVAILD_EVENT_TYPE 0xFFFFFFFF//无效的事件类型 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) -extern UINT32 OsPerfPmuRegister(Pmu *pmu); -extern VOID OsPerfPmuRm(UINT32 type); -extern Pmu *OsPerfPmuGet(UINT32 type); +extern UINT32 OsPerfPmuRegister(Pmu *pmu);//注册硬件性能计数器 +extern VOID OsPerfPmuRm(UINT32 type);//删除硬件性能计数器 +extern Pmu *OsPerfPmuGet(UINT32 type);//获取指定类型的硬件性能计数器 -extern UINT32 OsHwPmuInit(VOID); -extern UINT32 OsSwPmuInit(VOID); -extern UINT32 OsTimedPmuInit(VOID); +extern UINT32 OsHwPmuInit(VOID);//初始化硬件性能计数器 +extern UINT32 OsSwPmuInit(VOID);//初始化软件性能计数器 +extern UINT32 OsTimedPmuInit(VOID);//初始化定时器性能计数器 -extern UINT32 OsGetPmuCounter0(VOID); -extern UINT32 OsGetPmuMaxCounter(VOID); -extern UINT32 OsGetPmuCycleCounter(VOID); -extern UINT32 OsPerfHwInit(HwPmu *hwPmu); +extern UINT32 OsGetPmuCounter0(VOID);//获取0核计数器值 +extern UINT32 OsGetPmuMaxCounter(VOID);//获取最大计数器数 +extern UINT32 OsGetPmuCycleCounter(VOID);//获取周期性计数器值 +extern UINT32 OsPerfHwInit(HwPmu *hwPmu);//初始化硬件性能计数器 #ifdef __cplusplus #if __cplusplus diff --git a/src/kernel/extended/perf/pmu/perf_hw_pmu.c b/src/kernel/extended/perf/pmu/perf_hw_pmu.c index ca0b797..f76869d 100644 --- a/src/kernel/extended/perf/pmu/perf_hw_pmu.c +++ b/src/kernel/extended/perf/pmu/perf_hw_pmu.c @@ -34,7 +34,7 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ -STATIC Pmu *g_perfHw = NULL; +STATIC Pmu *g_perfHw = NULL;//指向性能计数器相关的数据结构或对象 STATIC CHAR *g_eventName[PERF_COUNT_HW_MAX] = { [PERF_COUNT_HW_CPU_CYCLES] = "cycles", @@ -53,39 +53,41 @@ STATIC CHAR *g_eventName[PERF_COUNT_HW_MAX] = { * 2.Find available counter for each event. * 3.Decide whether this hardware pmu need prescaler (once every 64 cycle counts). */ -STATIC UINT32 OsPerfHwConfig(VOID) +STATIC UINT32 OsPerfHwConfig(VOID)//性能计数器的配置函数,用于初始化和配置硬件性能计数器 { UINT32 i; HwPmu *armPmu = GET_HW_PMU(g_perfHw); - UINT32 maxCounter = OsGetPmuMaxCounter(); - UINT32 counter = OsGetPmuCounter0(); - UINT32 cycleCounter = OsGetPmuCycleCounter(); + UINT32 maxCounter = OsGetPmuMaxCounter();//获得最大计数器数量 + UINT32 counter = OsGetPmuCounter0();//获取0核计数器的值 + UINT32 cycleCounter = OsGetPmuCycleCounter();//周期计数器的值 UINT32 cycleCode = armPmu->mapEvent(PERF_COUNT_HW_CPU_CYCLES, PERF_EVENT_TO_CODE); if (cycleCode == PERF_HW_INVAILD_EVENT_TYPE) { return LOS_NOK; } - + //获取性能事件的列表的和数量并进行遍历 PerfEvent *events = &g_perfHw->events; UINT32 eventNum = events->nr; for (i = 0; i < eventNum; i++) { Event *event = &(events->per[i]); - if (!VALID_PERIOD(event->period)) { + if (!VALID_PERIOD(event->period)) {//检查事件周期是否合法 PRINT_ERR("Config period: 0x%x invalid, should be in (%#x, %#x)\n", event->period, PERIOD_CALC(CCNT_PERIOD_UPPER_BOUND), PERIOD_CALC(CCNT_PERIOD_LOWER_BOUND)); return LOS_NOK; } if (g_perfHw->type == PERF_EVENT_TYPE_HW) { /* do map */ + //映射编码 UINT32 eventId = armPmu->mapEvent(event->eventId, PERF_EVENT_TO_CODE); if (eventId == PERF_HW_INVAILD_EVENT_TYPE) { return LOS_NOK; } event->eventId = eventId; } - + //函数根据事件编码是否与周期计数器的事件编码相同,来确定该事件使用的计数器。 + //如果相同,则使用周期计数器;否则,使用普通计数器,并递增计数器的值。 if (event->eventId == cycleCode) { event->counter = cycleCounter; } else { @@ -93,11 +95,11 @@ STATIC UINT32 OsPerfHwConfig(VOID) counter++; } - if (counter >= maxCounter) { + if (counter >= maxCounter) {//检查计数器是否超过了最大计数器数量 PRINT_ERR("max events: %u excluding cycle event\n", maxCounter - 1); return LOS_NOK; } - + //打印结果,设置根据平台支持的分频 PRINT_DEBUG("Perf Config %u eventId = 0x%x, counter = 0x%x, period = 0x%x\n", i, event->eventId, event->counter, event->period); } @@ -106,21 +108,21 @@ STATIC UINT32 OsPerfHwConfig(VOID) return LOS_OK; } -STATIC UINT32 OsPerfHwStart(VOID) +STATIC UINT32 OsPerfHwStart(VOID)//用于启动硬件性能计数器 { UINT32 i; UINT32 cpuid = ArchCurrCpuid(); - HwPmu *armPmu = GET_HW_PMU(g_perfHw); + HwPmu *armPmu = GET_HW_PMU(g_perfHw);//获取硬件性能计数器的指针 PerfEvent *events = &g_perfHw->events; UINT32 eventNum = events->nr; - armPmu->clear(); + armPmu->clear();//清零计数器 for (i = 0; i < eventNum; i++) { Event *event = &(events->per[i]); - armPmu->setPeriod(event); - armPmu->enable(event); + armPmu->setPeriod(event);//设置事件的计数周期 + armPmu->enable(event);//启用事件的计数器 event->count[cpuid] = 0; } @@ -128,7 +130,7 @@ STATIC UINT32 OsPerfHwStart(VOID) return LOS_OK; } -STATIC UINT32 OsPerfHwStop(VOID) +STATIC UINT32 OsPerfHwStop(VOID)//停止硬件性能计数器 { UINT32 i; UINT32 cpuid = ArchCurrCpuid(); @@ -148,7 +150,9 @@ STATIC UINT32 OsPerfHwStop(VOID) /* multiplier of cycle counter */ UINT32 eventId = armPmu->mapEvent(event->eventId, PERF_CODE_TO_EVENT); if ((eventId == PERF_COUNT_HW_CPU_CYCLES) && (armPmu->cntDivided != 0)) { + //如果该事件的事件ID与周期计数器事件ID相同,并且硬件性能计数器的分频设置armPmu->cntDivided不为0 PRINT_DEBUG("perf stop is cycle\n"); + //此处将该事件的计数值左移6位,相当于乘以64 event->count[cpuid] = event->count[cpuid] << 6; /* CCNT counts every 64th cpu cycle */ } PRINT_DEBUG("perf stop eventCount[0x%x] : [%s] = %llu\n", event->eventId, g_eventName[eventId], @@ -157,11 +161,11 @@ STATIC UINT32 OsPerfHwStop(VOID) return LOS_OK; } -STATIC CHAR *OsPerfGetEventName(Event *event) +STATIC CHAR *OsPerfGetEventName(Event *event)//获取事件名称 { UINT32 eventId; - HwPmu *armPmu = GET_HW_PMU(g_perfHw); - eventId = armPmu->mapEvent(event->eventId, PERF_CODE_TO_EVENT); + HwPmu *armPmu = GET_HW_PMU(g_perfHw);//获取PMU上的事件信息 + eventId = armPmu->mapEvent(event->eventId, PERF_CODE_TO_EVENT);//将事件ID映射位对应计数器事件ID if (eventId < PERF_COUNT_HW_MAX) { return g_eventName[eventId]; } else { @@ -169,21 +173,21 @@ STATIC CHAR *OsPerfGetEventName(Event *event) } } -UINT32 OsPerfHwInit(HwPmu *hwPmu) +UINT32 OsPerfHwInit(HwPmu *hwPmu)//初始化性能计数器 { UINT32 ret; if (hwPmu == NULL) { return LOS_NOK; } - + //设置性能计数器的类型,配置函数,启动函数,停止函数,获取事件名称函数 hwPmu->pmu.type = PERF_EVENT_TYPE_HW; hwPmu->pmu.config = OsPerfHwConfig; hwPmu->pmu.start = OsPerfHwStart; hwPmu->pmu.stop = OsPerfHwStop; hwPmu->pmu.getName = OsPerfGetEventName; - + //将硬件性能计数器的事件数据结构清零 (VOID)memset_s(&hwPmu->pmu.events, sizeof(PerfEvent), 0, sizeof(PerfEvent)); - ret = OsPerfPmuRegister(&hwPmu->pmu); + ret = OsPerfPmuRegister(&hwPmu->pmu);//注册硬件性能计数器,将其存储在全局变量中 g_perfHw = OsPerfPmuGet(PERF_EVENT_TYPE_HW); return ret; diff --git a/src/kernel/extended/perf/pmu/perf_sw_pmu.c b/src/kernel/extended/perf/pmu/perf_sw_pmu.c index 5ea7e52..fe6f251 100644 --- a/src/kernel/extended/perf/pmu/perf_sw_pmu.c +++ b/src/kernel/extended/perf/pmu/perf_sw_pmu.c @@ -51,7 +51,7 @@ STATIC CHAR* g_eventName[PERF_COUNT_SW_MAX] = { [PERF_COUNT_SW_MUX_PEND] = "mux pend", }; -VOID OsPerfHook(UINT32 eventType) +VOID OsPerfHook(UINT32 eventType)//软件性能计数器的事件处理函数 { if (!g_perfSw.enable) { return; @@ -69,7 +69,7 @@ VOID OsPerfHook(UINT32 eventType) if (event->counter == eventType) { OsPerfUpdateEventCount(event, 1); if (event->count[ArchCurrCpuid()] % event->period == 0) { - OsPerfFetchCallerRegs(®s); + OsPerfFetchCallerRegs(®s);//获取寄存器信息 OsPerfHandleOverFlow(event, ®s); } return; @@ -77,7 +77,7 @@ VOID OsPerfHook(UINT32 eventType) } } -STATIC UINT32 OsPerfSwConfig(VOID) +STATIC UINT32 OsPerfSwConfig(VOID)//对软件性能计数器进行配置 { UINT32 i; PerfEvent *events = &g_perfSw.pmu.events; @@ -94,29 +94,29 @@ STATIC UINT32 OsPerfSwConfig(VOID) return LOS_OK; } -STATIC UINT32 OsPerfSwStart(VOID) +STATIC UINT32 OsPerfSwStart(VOID)//启动软件性能计数器 { UINT32 i; UINT32 cpuid = ArchCurrCpuid(); PerfEvent *events = &g_perfSw.pmu.events; UINT32 eventNum = events->nr; - for (i = 0; i < eventNum; i++) { + for (i = 0; i < eventNum; i++) {//遍历所有事件 Event *event = &(events->per[i]); - event->count[cpuid] = 0; + event->count[cpuid] = 0;//清零当前事件在CPU中的计数器 } - g_perfSw.enable = TRUE; + g_perfSw.enable = TRUE;//启动计数器 return LOS_OK; } -STATIC UINT32 OsPerfSwStop(VOID) +STATIC UINT32 OsPerfSwStop(VOID)//关闭软件性能计数器 { g_perfSw.enable = FALSE; return LOS_OK; } -STATIC CHAR *OsPerfGetEventName(Event *event) +STATIC CHAR *OsPerfGetEventName(Event *event)//获取事件的名称 { UINT32 eventId = event->eventId; if (eventId < PERF_COUNT_SW_MAX) { @@ -125,7 +125,7 @@ STATIC CHAR *OsPerfGetEventName(Event *event) return "unknown"; } -UINT32 OsSwPmuInit(VOID) +UINT32 OsSwPmuInit(VOID)//对PMU计数器进行初始化 { g_perfSw.pmu = (Pmu) { .type = PERF_EVENT_TYPE_SW, diff --git a/src/kernel/extended/perf/pmu/perf_timed_pmu.c b/src/kernel/extended/perf/pmu/perf_timed_pmu.c index 4659c08..6080f90 100644 --- a/src/kernel/extended/perf/pmu/perf_timed_pmu.c +++ b/src/kernel/extended/perf/pmu/perf_timed_pmu.c @@ -39,12 +39,12 @@ extern "C" { STATIC SwPmu g_perfTimed; -STATIC BOOL OsPerfTimedPeriodValid(UINT32 period) +STATIC BOOL OsPerfTimedPeriodValid(UINT32 period)//验证定时器中的时间周期是否合法 { return period >= TIMER_PERIOD_LOWER_BOUND_US; } -STATIC UINT32 OsPerfTimedStart(VOID) +STATIC UINT32 OsPerfTimedStart(VOID)//启动定时器事件 { UINT32 i; UINT32 cpuid = ArchCurrCpuid(); @@ -74,7 +74,7 @@ STATIC UINT32 OsPerfTimedStart(VOID) return LOS_OK; } -STATIC UINT32 OsPerfTimedConfig(VOID) +STATIC UINT32 OsPerfTimedConfig(VOID)//配置定时器,检验是否合法 { UINT32 i; PerfEvent *events = &g_perfTimed.pmu.events; @@ -101,7 +101,7 @@ STATIC UINT32 OsPerfTimedConfig(VOID) return LOS_NOK; } -STATIC UINT32 OsPerfTimedStop(VOID) +STATIC UINT32 OsPerfTimedStop(VOID)//关闭定时器设置 { UINT32 ret; if (ArchCurrCpuid() != 0) { /* only need stop on one core */ @@ -116,7 +116,7 @@ STATIC UINT32 OsPerfTimedStop(VOID) return LOS_OK; } -STATIC VOID OsPerfTimedHandle(VOID) +STATIC VOID OsPerfTimedHandle(VOID)//处理定时器事件 { UINT32 index; PerfRegs regs; @@ -125,7 +125,7 @@ STATIC VOID OsPerfTimedHandle(VOID) UINT32 eventNum = events->nr; (VOID)memset_s(®s, sizeof(PerfRegs), 0, sizeof(PerfRegs)); - OsPerfFetchIrqRegs(®s); + OsPerfFetchIrqRegs(®s);//获取当前寄存器状态 for (index = 0; index < eventNum; index++) { Event *event = &(events->per[index]); @@ -134,48 +134,50 @@ STATIC VOID OsPerfTimedHandle(VOID) } } -STATIC enum hrtimer_restart OsPerfHrtimer(struct hrtimer *hrtimer) +STATIC enum hrtimer_restart OsPerfHrtimer(struct hrtimer *hrtimer)//高精度定时器(hrtimer)的回调函数 { SMP_CALL_PERF_FUNC(OsPerfTimedHandle); /* send to all cpu to collect data */ + //将定时器事件的处理发送给所有CPU进行数据收集 return HRTIMER_RESTART; } -STATIC CHAR *OsPerfGetEventName(Event *event) +STATIC CHAR *OsPerfGetEventName(Event *event)//获取事件名称 { - if (event->eventId == PERF_COUNT_CPU_CLOCK) { + if (event->eventId == PERF_COUNT_CPU_CLOCK) {//读取事件ID是否与计数器中的事件记录相同 return "timed"; } else { return "unknown"; } } -UINT32 OsTimedPmuInit(VOID) +UINT32 OsTimedPmuInit(VOID)//初始化定时器 { UINT32 ret; - g_perfTimed.time = (union ktime) { + g_perfTimed.time = (union ktime) {//保存定时器信息 .tv.sec = 0, .tv.usec = HRTIMER_DEFAULT_PERIOD_US, }; - hrtimer_init(&g_perfTimed.hrtimer, 1, HRTIMER_MODE_REL); + hrtimer_init(&g_perfTimed.hrtimer, 1, HRTIMER_MODE_REL);//第一个参数代表定时器对象,第二个参数为时间源类型,代表的是相对时间,最后一个参数代表定时器模式,这里使用的是相对时间模式 - ret = hrtimer_create(&g_perfTimed.hrtimer, g_perfTimed.time, OsPerfHrtimer); + ret = hrtimer_create(&g_perfTimed.hrtimer, g_perfTimed.time, OsPerfHrtimer);//创建定时器 if (ret != LOS_OK) { return ret; } g_perfTimed.pmu = (Pmu) { - .type = PERF_EVENT_TYPE_TIMED, - .config = OsPerfTimedConfig, - .start = OsPerfTimedStart, - .stop = OsPerfTimedStop, - .getName = OsPerfGetEventName, + .type = PERF_EVENT_TYPE_TIMED,//此性能计数器是定时器类型 + .config = OsPerfTimedConfig,//性能计数器的事件配置 + .start = OsPerfTimedStart,//启动 + .stop = OsPerfTimedStop,//停止 + .getName = OsPerfGetEventName,//获取事件名称 }; (VOID)memset_s(&g_perfTimed.pmu.events, sizeof(PerfEvent), 0, sizeof(PerfEvent)); + //执行完之后清零事件结构体,并在下面进行状态码的注册读取 ret = OsPerfPmuRegister(&g_perfTimed.pmu); - return ret; + return ret;//返回值为初始化状态码 } #ifdef __cplusplus diff --git a/src/kernel/extended/软件工程代码阅读(初稿)-何佳聪-.docx b/src/kernel/extended/软件工程代码阅读(初稿)-何佳聪-.docx new file mode 100644 index 0000000000000000000000000000000000000000..4d112b6f661c0c5322db4731bd81bfcdb797786f GIT binary patch literal 14017 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 HZ?*pcv7}9Z literal 0 HcmV?d00001