From aa43a7ec88db2f47c27eb2aa3d7e30285cd294bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E8=B1=AA?= <2548632733@qq.com> Date: Mon, 4 Dec 2023 00:24:26 +0800 Subject: [PATCH 1/4] Code reading --- 文豪/cppsupport/los_cppsupport.c | 74 +++ 文豪/cpup/cpup_shellcmd.c | 134 ++++ 文豪/cpup/los_cpup.c | 593 ++++++++++++++++++ 文豪/los_cppsupport_pri.h | 53 ++ 文豪/los_cpup_pri.h | 74 +++ 文豪/los_trace_pri.h | 150 +++++ 文豪/trace/los_trace.c | 424 +++++++++++++ .../pipeline/serial/trace_pipeline_serial.c | 98 +++ .../pipeline/serial/trace_pipeline_serial.h | 50 ++ 文豪/trace/pipeline/trace_pipeline.c | 156 +++++ 文豪/trace/pipeline/trace_pipeline.h | 104 +++ 文豪/trace/pipeline/trace_tlv.c | 121 ++++ 文豪/trace/pipeline/trace_tlv.h | 95 +++ 文豪/trace/trace_offline.c | 264 ++++++++ 文豪/trace/trace_online.c | 117 ++++ 15 files changed, 2507 insertions(+) create mode 100644 文豪/cppsupport/los_cppsupport.c create mode 100644 文豪/cpup/cpup_shellcmd.c create mode 100644 文豪/cpup/los_cpup.c create mode 100644 文豪/los_cppsupport_pri.h create mode 100644 文豪/los_cpup_pri.h create mode 100644 文豪/los_trace_pri.h create mode 100644 文豪/trace/los_trace.c create mode 100644 文豪/trace/pipeline/serial/trace_pipeline_serial.c create mode 100644 文豪/trace/pipeline/serial/trace_pipeline_serial.h create mode 100644 文豪/trace/pipeline/trace_pipeline.c create mode 100644 文豪/trace/pipeline/trace_pipeline.h create mode 100644 文豪/trace/pipeline/trace_tlv.c create mode 100644 文豪/trace/pipeline/trace_tlv.h create mode 100644 文豪/trace/trace_offline.c create mode 100644 文豪/trace/trace_online.c diff --git a/文豪/cppsupport/los_cppsupport.c b/文豪/cppsupport/los_cppsupport.c new file mode 100644 index 0000000..e6239ab --- /dev/null +++ b/文豪/cppsupport/los_cppsupport.c @@ -0,0 +1,74 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved. + * Description: LiteOS Cpp Support 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_cppsupport_pri.h" +#include "los_printf.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +typedef VOID (*InitFunc)(VOID); + +/*------------------------------------------- +*`LITE_OS_SEC_TEXT_MINOR``UINTPTR`ȡ +*`LOS_CppSystemInit`Уһʼ飬 +*εЩʼݴ`flag` +*ضλִгʼ +*--------------------------------------------*/ +LITE_OS_SEC_TEXT_MINOR INT32 LOS_CppSystemInit(UINTPTR initArrayStart, UINTPTR initArrayEnd, INT32 flag) +{ + UINTPTR fastEnd = (UINTPTR)&__fast_end; + UINTPTR *start = (UINTPTR *)initArrayStart; + InitFunc initFunc = NULL; + +#ifdef LOSCFG_AARCH64 + __register_frame(__EH_FRAME_BEGIN__); +#endif + + for (; start != (UINTPTR *)initArrayEnd; ++start) { + if ((flag == BEFORE_SCATTER) && ((UINTPTR)*start > fastEnd)) { + continue; + } else if ((flag == AFTER_SCATTER) && ((UINTPTR)*start <= fastEnd)) { + continue; + } + + initFunc = (InitFunc)(*start); + initFunc(); + } + + return 0; +} + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ diff --git a/文豪/cpup/cpup_shellcmd.c b/文豪/cpup/cpup_shellcmd.c new file mode 100644 index 0000000..8e4160b --- /dev/null +++ b/文豪/cpup/cpup_shellcmd.c @@ -0,0 +1,134 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2013-2020. All rights reserved. + * Description: ShellCmd Cpup + * 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_config.h" +#ifdef LOSCFG_SHELL +#include "stdio.h" +#include "stdlib.h" +#include "los_cpup_pri.h" +#include "los_task_pri.h" +#include "shcmd.h" +#include "shell.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +VOID OsCmdCpupOperateOneParam(UINT32 mode) //ݲmodeȡϵͳCPUʹʵʷ// +{ + UINT32 ret; + + if (mode == CPUP_LAST_TEN_SECONDS) { //ȥ10s// + PRINTK("\nSysCpuUsage in 10s: "); + } else if (mode == CPUP_LAST_ONE_SECONDS) { //ȥ1s// + PRINTK("\nSysCpuUsage in 1s: "); + } else { //ʷƽCPUʹ// + PRINTK("\nSysCpuUsage in all time: "); + } + ret = LOS_HistorySysCpuUsage(mode); //ȡCPUʹʵֵ// + PRINTK("%u.%u", ret / LOS_CPUP_PRECISION_MULT, ret % LOS_CPUP_PRECISION_MULT); +} + +VOID OsCmdCpupOperateTwoParam(UINT32 mode, UINT32 taskId) //ݲmodeȡtaskIdָ// +{ //CPUʹʵʷ// + UINT32 ret; + + if (mode == CPUP_LAST_TEN_SECONDS) { //ȥ10s// + PRINTK("\nTaskId %u CpuUsage in 10s: ", taskId); + } else if (mode == CPUP_LAST_ONE_SECONDS) { //ȥ1s// + PRINTK("\nTaskId %u CpuUsage in 1s: ", taskId); + } else { //ʷƽCPUʹ// + PRINTK("\nTaskId %u CpuUsage in all time: ", taskId); + } + ret = LOS_HistoryTaskCpuUsage(taskId, mode); //ȡCPUʹʵֵ// + PRINTK("%u.%u", ret / LOS_CPUP_PRECISION_MULT, ret % LOS_CPUP_PRECISION_MULT); +} + +LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdCpup(INT32 argc, const CHAR **argv) //IJȡϵͳָCPUʹ// +{ + size_t mode, taskId; + CHAR *bufMode = NULL; + CHAR *bufId = NULL; + LosTaskCB *taskCB = NULL; + UINT32 ret; + + if (argc <= 0) { //ûвȡϵͳȥ10CPUʹʲӡ// + ret = LOS_HistorySysCpuUsage(CPUP_LAST_TEN_SECONDS); + PRINTK("\nSysCpuUsage in 10s: %u.%u", ret / LOS_CPUP_PRECISION_MULT, ret % LOS_CPUP_PRECISION_MULT); + return 0; + } + + mode = strtoul(argv[0], &bufMode, 0); //һתΪ޷modeʾCPUʹʵĻȡģʽ// +/*------------------------------------------------------------------*/ + //жmodeǷЧ// + if ((bufMode == NULL) || (*bufMode != 0)) { + PRINTK("\nThe input mode is invalid. Please try again.\n"); + return 0; + } + + if (mode > CPUP_ALL_TIME) { + mode = CPUP_ALL_TIME; + } +/*------------------------------------------------------------------*/ +//ֻһOsCmdCpupOperateOneParamȡϵͳCPUʹ// + if (argc == 1) { + OsCmdCpupOperateOneParam((UINT32)mode); + return 0; + } +/*------------------------------------------------------------------*/ +//жtaskIdǷЧ// + taskId = strtoul(argv[1], &bufId, 0); + if ((taskId >= g_taskMaxNum) || (*bufId != 0)) { + PRINTK("\nThe input taskId is invalid. Please try again.\n"); + return 0; + } + taskCB = OS_TCB_FROM_TID(taskId); + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + PRINTK("\nThe task is unused. Please try again.\n"); + return 0; + } +/*-----------------------------------------------------------------*/ +//ڶΪIDȻOsCmdCpupOperateTwoParamȡָCPUʹ// + if (argc == 2) { + OsCmdCpupOperateTwoParam((UINT32)mode, (UINT32)taskId); + return 0; + } + + PRINTK("cpup [MODE] \ncpup [MODE] [TASKID] \n"); + return 0; +} +//ͨShellնcpupӦIJȡCPUʹʵʷ// +SHELLCMD_ENTRY(cpup_shellcmd, CMD_TYPE_EX, "cpup", XARGS, (CmdCallBackFunc)OsShellCmdCpup); +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ +#endif /* LOSCFG_SHELL */ diff --git a/文豪/cpup/los_cpup.c b/文豪/cpup/los_cpup.c new file mode 100644 index 0000000..688ff34 --- /dev/null +++ b/文豪/cpup/los_cpup.c @@ -0,0 +1,593 @@ +/* ---------------------------------------------------------------------------- + * 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) +{ + /*溯IJֱΪ*/ + //趨ʱÿӵĻʱӵδ// + //ģʽΪģʽ// + //ص// + //ʱIDg_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 + /*ʼõIJtaskInitParamIDtempId*/ + (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_cpupMaxNumLOSCFG_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ʼֵԱ¼ʱʱ +ܹȷCPUIJֵӶõʱ*/ +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ڼijʼֱӷ// + 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Ƿ00ش// + 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(); //ȡǰCPUID// + + 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 */ + diff --git a/文豪/los_cppsupport_pri.h b/文豪/los_cppsupport_pri.h new file mode 100644 index 0000000..5e3fcb9 --- /dev/null +++ b/文豪/los_cppsupport_pri.h @@ -0,0 +1,53 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved. + * Description: Cpp Support HeadFile + * 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. + * --------------------------------------------------------------------------- */ + +#ifndef _LOS_CPPSUPPORT_PRI_H +#define _LOS_CPPSUPPORT_PRI_H //ֹΰͬһͷļ// + +#include "los_cppsupport.h" + +#ifdef __cplusplus //ݱǷΪC++// +#if __cplusplus //ʹáextern 'C'// +extern "C" { //´ݽ// +#endif /* __cplusplus */ //ȷ// +#endif /* __cplusplus */ + +extern CHAR __fast_end; //һ_fast_endCHARͱ// + +#ifdef LOSCFG_AARCH64 //// +extern UINT8 __EH_FRAME_BEGIN__[]; //һUINT8͵// +VOID __register_frame(VOID *begin); +#endif + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ //رextern'C'// +#endif /* __cplusplus */ + +#endif /* _LOS_CPPSUPPORT_PRI_H */ diff --git a/文豪/los_cpup_pri.h b/文豪/los_cpup_pri.h new file mode 100644 index 0000000..f8da73e --- /dev/null +++ b/文豪/los_cpup_pri.h @@ -0,0 +1,74 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2013-2020. All rights reserved. + * Description: Cpup HeadFile + * 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. + * --------------------------------------------------------------------------- */ + +#ifndef _LOS_CPUP_PRI_H +#define _LOS_CPUP_PRI_H //ֹΰͬһͷļ// + +#include "los_cpup.h" //ܰһЩCPUʹ// +#include "los_task_pri.h" //ͳصĹͶ// + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define OS_CPUP_HISTORY_RECORD_NUM 11 //ʷ¼Ϊ11// +#define LOS_CPUP_PRECISION 1000 //CPUʹʵľΪ1000// +#define LOS_CPUP_PRECISION_MULT (LOS_CPUP_PRECISION / 100) //ڼCPUʹ// + +typedef struct { + UINT32 id; /* Task ID */ + UINT16 status; /* Task status */ + UINT64 allTime; /* Total running time */ + UINT64 startTime; /* Time before a task is invoked */ + UINT64 historyTime[OS_CPUP_HISTORY_RECORD_NUM + 1]; /* Historical running time, the last one saves zero */ +} OsCpupCB; + +extern OsCpupCB *OsCpupCBGet(UINT32 index); //ȡ `OsCpupCB` ṹָ// +extern UINT32 OsCpupInit(VOID); //CPUʹͳģijʼ// +extern VOID OsCpupSetCycle(UINT64 startCycles); //CPUڼ// +extern UINT64 OsCpupGetCycle(VOID); //ȡCPUڼ// +extern VOID OsTaskCycleStart(VOID); //ڵʼ// +extern VOID OsTaskCycleEnd(VOID); //ڵĽ// +extern VOID OsTaskCycleEndStart(const LosTaskCB *newTask); //ڣʼµ// +#ifdef LOSCFG_CPUP_INCLUDE_IRQ +VOID OsCpupIrqStart(VOID); //ǰһ£ڴ// +VOID OsCpupIrqEnd(UINT32); //жϵCPUʹͳƺ// +#endif + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _LOS_CPUP_PRI_H */ + +/*δ붨һЩCPUʹͳƵݽṹͺ +ڲϵͳʵֶжϵCPUʽмغͳơ*/ \ No newline at end of file diff --git a/文豪/los_trace_pri.h b/文豪/los_trace_pri.h new file mode 100644 index 0000000..762fd9f --- /dev/null +++ b/文豪/los_trace_pri.h @@ -0,0 +1,150 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. + * Description: LiteOS Trace Module Private HeadFile + * Author: Huawei LiteOS Team + * Create: 2019-08-30 + * 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. + * --------------------------------------------------------------------------- */ + +#ifndef _LOS_TRACE_PRI_H +#define _LOS_TRACE_PRI_H + +#include "los_trace.h" +#include "los_task_pri.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#ifdef LOSCFG_TRACE_CONTROL_AGENT +#define TRACE_CMD_END_CHAR 0xD +#endif + +#define TRACE_ERROR PRINT_ERR +#define TRACE_MODE_OFFLINE 0 +#define TRACE_MODE_ONLINE 1 + +/* just task and hwi were traced */ +#define TRACE_DEFAULT_MASK (TRACE_HWI_FLAG | TRACE_TASK_FLAG) +#define TRACE_CTL_MAGIC_NUM 0xDEADBEEF +#define TRACE_BIGLITTLE_WORD 0x12345678 +#define TRACE_VERSION(MODE) (0xFFFFFFFF & (MODE)) +#define TRACE_MASK_COMBINE(c1, c2, c3, c4) (((c1) << 24) | ((c2) << 16) | ((c3) << 8) | (c4)) + +#define TRACE_GET_MODE_FLAG(type) ((type) & 0xFFFFFFF0) + +extern SPIN_LOCK_S g_traceSpin; +#define TRACE_LOCK(state) LOS_SpinLockSave(&g_traceSpin, &(state)) +#define TRACE_UNLOCK(state) LOS_SpinUnlockRestore(&g_traceSpin, (state)) + +typedef VOID (*TRACE_DUMP_HOOK)(BOOL toClient); +extern TRACE_DUMP_HOOK g_traceDumpHook; + +enum TraceCmd { + TRACE_CMD_START = 1, + TRACE_CMD_STOP, + TRACE_CMD_SET_EVENT_MASK, + TRACE_CMD_RECODE_DUMP, + TRACE_CMD_MAX_CODE, +}; + +/** + * @ingroup los_trace + * struct to store the trace cmd from traceClient. + */ +typedef struct { + UINT8 cmd; + UINT8 param1; + UINT8 param2; + UINT8 param3; + UINT8 param4; + UINT8 param5; + UINT8 end; +} TraceClientCmd; + +/** + * @ingroup los_trace + * struct to store the event infomation + */ +typedef struct { + UINT32 cmd; /* trace start or stop cmd */ + UINT32 param; /* magic numb stand for notify msg */ +} TraceNotifyFrame; + +/** + * @ingroup los_trace + * struct to store the trace config information. + */ +typedef struct { + struct WriteCtrl { + UINT16 curIndex; /* The current record index */ + UINT16 maxRecordCount; /* The max num of track items */ + UINT16 curObjIndex; /* The current obj index */ + UINT16 maxObjCount; /* The max num of obj index */ + ObjData *objBuf; /* Pointer to obj info data */ + TraceEventFrame *frameBuf; /* Pointer to the track items */ + } ctrl; + OfflineHead *head; +} TraceOfflineHeaderInfo; + +extern UINT32 OsTraceGetMaskTid(UINT32 taskId); +extern VOID OsTraceSetObj(ObjData *obj, const LosTaskCB *tcb); +extern VOID OsTraceWriteOrSendEvent(const TraceEventFrame *frame); +extern UINT32 OsTraceBufInit(VOID *buf, UINT32 size); +extern VOID OsTraceObjAdd(UINT32 eventType, UINT32 taskId); +extern BOOL OsTraceIsEnable(VOID); +extern OfflineHead *OsTraceRecordGet(VOID); + +#ifdef LOSCFG_RECORDER_MODE_ONLINE +extern VOID OsTraceSendHead(VOID); +extern VOID OsTraceSendObjTable(VOID); +extern VOID OsTraceSendNotify(UINT32 type, UINT32 value); + +#define OsTraceNotifyStart() do { \ + OsTraceSendNotify(SYS_START, TRACE_CTL_MAGIC_NUM); \ + OsTraceSendHead(); \ + OsTraceSendObjTable(); \ + } while (0) + +#define OsTraceNotifyStop() do { \ + OsTraceSendNotify(SYS_STOP, TRACE_CTL_MAGIC_NUM); \ + } while (0) + +#define OsTraceReset() +#define OsTraceRecordDump(toClient) +#else +extern VOID OsTraceReset(VOID); +extern VOID OsTraceRecordDump(BOOL toClient); +#define OsTraceNotifyStart() +#define OsTraceNotifyStop() +#endif + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _LOS_TRACE_PRI_H */ diff --git a/文豪/trace/los_trace.c b/文豪/trace/los_trace.c new file mode 100644 index 0000000..1f19ec2 --- /dev/null +++ b/文豪/trace/los_trace.c @@ -0,0 +1,424 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. + * Description: LiteOS Trace Implementation + * Author: Huawei LiteOS Team + * Create: 2019-08-31 + * 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 "uart.h" +#include "los_trace_pri.h" +#include "trace_pipeline.h" + +#ifdef LOSCFG_KERNEL_SMP +#include "los_mp_pri.h" +#endif + +#ifdef LOSCFG_SHELL +#include "shcmd.h" +#include "shell.h" +#endif + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#ifdef LOSCFG_KERNEL_TRACE +LITE_OS_SEC_BSS STATIC UINT32 g_traceEventCount; //׷¼// +LITE_OS_SEC_BSS STATIC volatile enum TraceState g_traceState = TRACE_UNINIT; //׷״̬// +LITE_OS_SEC_DATA_INIT STATIC volatile BOOL g_enableTrace = FALSE; //Ƿ׷ٹ// +LITE_OS_SEC_BSS STATIC UINT32 g_traceMask = TRACE_DEFAULT_MASK; //׷룬ڹ׷¼// + +#ifdef LOSCFG_TRACE_CONTROL_AGENT +LITE_OS_SEC_BSS STATIC UINT32 g_traceTaskId; //׷ID// +#endif + +#define EVENT_MASK 0xFFFFFFF0 +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +LITE_OS_SEC_BSS STATIC TRACE_HWI_FILTER_HOOK g_traceHwiFliterHook = NULL; + +LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_traceSpin); + +STATIC_INLINE BOOL OsTraceHwiFilter(UINT32 hwiNum) //жǷҪijӲж// +{ + BOOL ret = ((hwiNum == NUM_HAL_INTERRUPT_UART) || (hwiNum == OS_TICK_INT_NUM)); +#ifdef LOSCFG_KERNEL_SMP + ret |= (hwiNum == LOS_MP_IPI_SCHEDULE); +#endif + if (g_traceHwiFliterHook != NULL) { + ret |= g_traceHwiFliterHook(hwiNum); + } + return ret; +} + +//׷¼֡Ϣ// +STATIC VOID OsTraceSetFrame(TraceEventFrame *frame, UINT32 eventType, UINTPTR identity, const UINTPTR *params, + UINT16 paramCount) +{ + INT32 i; + UINT32 intSave; + + (VOID)memset_s(frame, sizeof(TraceEventFrame), 0, sizeof(TraceEventFrame)); + + if (paramCount > LOSCFG_TRACE_FRAME_MAX_PARAMS) { + paramCount = LOSCFG_TRACE_FRAME_MAX_PARAMS; + } + + TRACE_LOCK(intSave); + frame->curTask = OsTraceGetMaskTid(OsCurrTaskGet()->taskId); + frame->identity = identity; + frame->curTime = HalClockGetCycles(); + frame->eventType = eventType; + +#ifdef LOSCFG_TRACE_FRAME_CORE_MSG + frame->core.cpuId = ArchCurrCpuid(); //CPUID// + frame->core.hwiActive = OS_INT_ACTIVE ? TRUE : FALSE; //Ӳжϻ״̬// + frame->core.taskLockCnt = MIN(OsPercpuGet()->taskLockCnt, 0xF); /* taskLockCnt is 4 bits, max vaule = 0xF */ //// + frame->core.paramCount = paramCount; //Ŀ// +#endif + +#ifdef LOSCFG_TRACE_FRAME_EVENT_COUNT + frame->eventCount = g_traceEventCount; //׷¼ļ// + g_traceEventCount++; +#endif + TRACE_UNLOCK(intSave); + + for (i = 0; i < paramCount; i++) { + frame->params[i] = params[i]; + } +} + +VOID OsTraceSetObj(ObjData *obj, const LosTaskCB *tcb) //ö׷Ϣ// +{ + errno_t ret; + (VOID)memset_s(obj, sizeof(ObjData), 0, sizeof(ObjData)); + + obj->id = OsTraceGetMaskTid(tcb->taskId); //ȡID// + obj->prio = tcb->priority; //ȡȼ// + + ret = strncpy_s(obj->name, LOSCFG_TRACE_OBJ_MAX_NAME_SIZE, tcb->taskName, LOSCFG_TRACE_OBJ_MAX_NAME_SIZE - 1); + if (ret != EOK) { + TRACE_ERROR("Task name copy failed!\n"); + } +} + +//׷¼// +VOID OsTraceHook(UINT32 eventType, UINTPTR identity, const UINTPTR *params, UINT16 paramCount) +{ + if ((eventType == TASK_CREATE) || (eventType == TASK_PRIOSET)) { + OsTraceObjAdd(eventType, identity); /* handle important obj info, these can not be filtered */ + } + + if ((g_enableTrace == TRUE) && (eventType & g_traceMask)) { + UINTPTR id = identity; + if (TRACE_GET_MODE_FLAG(eventType) == TRACE_HWI_FLAG) { + if (OsTraceHwiFilter(identity)) { + return; + } + } else if (TRACE_GET_MODE_FLAG(eventType) == TRACE_TASK_FLAG) { + id = OsTraceGetMaskTid(identity); + } else if (eventType == MEM_INFO_REQ) { + LOS_MEM_POOL_STATUS status; + LOS_MemInfoGet((VOID *)identity, &status); + LOS_TRACE(MEM_INFO, identity, status.uwTotalUsedSize, status.uwTotalFreeSize); + return; + } + + TraceEventFrame frame; + OsTraceSetFrame(&frame, eventType, id, params, paramCount); + + OsTraceWriteOrSendEvent(&frame); //׷¼Ϣдͳȥ// + } +} + +BOOL OsTraceIsEnable(VOID) //ж׷Ƿ״̬// +{ + return g_enableTrace == TRUE; +} + +STATIC VOID OsTraceHookInstall(VOID) //װ׷ٹ// +{ + g_traceEventHook = OsTraceHook; +#ifdef LOSCFG_RECORDER_MODE_OFFLINE + g_traceDumpHook = OsTraceRecordDump; //߼¼ģʽ׷ת// +#endif +} + +#ifdef LOSCFG_TRACE_CONTROL_AGENT +STATIC BOOL OsTraceCmdIsValid(const TraceClientCmd *msg) //жϴTraceClientCmdṹǷЧ// +{ + return ((msg->end == TRACE_CMD_END_CHAR) && (msg->cmd < TRACE_CMD_MAX_CODE)); +} + +STATIC VOID OsTraceCmdHandle(const TraceClientCmd *msg) //TraceClientCmdṹ// +{ + if (!OsTraceCmdIsValid(msg)) { + return; + } + + switch (msg->cmd) { + case TRACE_CMD_START: //׷// + LOS_TraceStart(); + break; + case TRACE_CMD_STOP: //ֹͣ׷// + LOS_TraceStop(); + break; + case TRACE_CMD_SET_EVENT_MASK: //¼// + /* 4 params(UINT8) composition the mask(UINT32) */ + LOS_TraceEventMaskSet(TRACE_MASK_COMBINE(msg->param1, msg->param2, msg->param3, msg->param4)); + break; + case TRACE_CMD_RECODE_DUMP: //׷ټ¼ת// + LOS_TraceRecordDump(TRUE); + break; + default: + break; + } +} + +VOID TraceAgent(VOID) //ϵȴ׷ݵĵյ׷// +{ + UINT32 ret; + TraceClientCmd msg; + + while (1) { + (VOID)memset_s(&msg, sizeof(TraceClientCmd), 0, sizeof(TraceClientCmd)); + ret = OsTraceDataWait(); + if (ret == LOS_OK) { + OsTraceDataRecv((UINT8 *)&msg, sizeof(TraceClientCmd), 0); + OsTraceCmdHandle(&msg); + } + } +} + +STATIC UINT32 OsCreateTraceAgentTask(VOID) //һ׷ٴִ׷߼// +{ + UINT32 ret; + 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)TraceAgent; + taskInitParam.usTaskPrio = LOSCFG_TRACE_TASK_PRIORITY; + taskInitParam.pcName = "TraceAgent"; + taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; +#ifdef LOSCFG_KERNEL_SMP + taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid()); +#endif + ret = LOS_TaskCreate(&g_traceTaskId, &taskInitParam); + return ret; +} +#endif + +UINT32 LOS_TraceInit(VOID *buf, UINT32 size) //ʼ׷ٹ// +{ + UINT32 intSave; + UINT32 ret; + + TRACE_LOCK(intSave); + if (g_traceState != TRACE_UNINIT) { + TRACE_ERROR("trace has been initialized already, the current state is :%d\n", g_traceState); + ret = LOS_ERRNO_TRACE_ERROR_STATUS; + goto LOS_ERREND; + } + +#ifdef LOSCFG_TRACE_CLIENT_INTERACT //жǷҪʼ׷ٹܵ// + ret = OsTracePipelineInit(); + if (ret != LOS_OK) { + goto LOS_ERREND; + } +#endif + +#ifdef LOSCFG_TRACE_CONTROL_AGENT //жǷҪ׷ٴ// + ret = OsCreateTraceAgentTask(); + if (ret != LOS_OK) { + TRACE_ERROR("trace init create agentTask error :0x%x\n", ret); + goto LOS_ERREND; + } +#endif + + ret = OsTraceBufInit(buf, size); //ʼ׷ٻ// + if (ret != LOS_OK) { + goto LOS_RELEASE; + } + + OsTraceHookInstall(); //װ׷ٹ// + + g_traceEventCount = 0; + + /*жǷҪȴ׷ٿͻ׷*/ +#ifdef LOSCFG_RECORDER_MODE_ONLINE /* Wait trace client to start trace */ + g_enableTrace = FALSE; + g_traceState = TRACE_INITED; +#else + g_enableTrace = TRUE; + g_traceState = TRACE_STARTED; +#endif + TRACE_UNLOCK(intSave); + return LOS_OK; +LOS_RELEASE: +#ifdef LOSCFG_TRACE_CONTROL_AGENT //жǷҪɾ׷ٴ// + LOS_TaskDelete(g_traceTaskId); +#endif +LOS_ERREND: + TRACE_UNLOCK(intSave); + return ret; +} + +UINT32 LOS_TraceStart(VOID) //׷ٹ// +{ + UINT32 intSave; + UINT32 ret = LOS_OK; + + TRACE_LOCK(intSave); + if (g_traceState == TRACE_STARTED) { + goto START_END; + } + + if (g_traceState == TRACE_UNINIT) { + TRACE_ERROR("trace not inited, be sure LOS_TraceInit excute success\n"); + ret = LOS_ERRNO_TRACE_ERROR_STATUS; + goto START_END; + } + + OsTraceNotifyStart(); //֪ͨ׷ٹܿʼ// + + g_enableTrace = TRUE; + g_traceState = TRACE_STARTED; + + TRACE_UNLOCK(intSave); + LOS_TRACE(MEM_INFO_REQ, m_aucSysMem0); //׷Ϣ// + return ret; +START_END: + TRACE_UNLOCK(intSave); + return ret; +} + +VOID LOS_TraceStop(VOID) //ֹͣ׷ٹ// +{ + UINT32 intSave; + + TRACE_LOCK(intSave); + if (g_traceState != TRACE_STARTED) { + goto STOP_END; + } + + g_enableTrace = FALSE; + g_traceState = TRACE_STOPED; + OsTraceNotifyStop(); //֪ͨ׷ٹֹͣ// +STOP_END: + TRACE_UNLOCK(intSave); +} + +VOID LOS_TraceEventMaskSet(UINT32 mask) //׷¼// +{ + g_traceMask = mask & EVENT_MASK; +} + +VOID LOS_TraceRecordDump(BOOL toClient) //ת׷ټ¼// +{ + if (g_traceState != TRACE_STOPED) { + TRACE_ERROR("trace dump must after trace stopped , the current state is : %d\n", g_traceState); + return; + } + OsTraceRecordDump(toClient); +} + +OfflineHead *LOS_TraceRecordGet(VOID) //ȡ׷ټ¼// +{ + return OsTraceRecordGet(); +} + +VOID LOS_TraceReset(VOID) //׷ٹ// +{ + if (g_traceState == TRACE_UNINIT) { + TRACE_ERROR("trace not inited, be sure LOS_TraceInit excute success\n"); + return; + } + + OsTraceReset(); +} + +VOID LOS_TraceHwiFilterHookReg(TRACE_HWI_FILTER_HOOK hook) //עжϹ˹// +{ + UINT32 intSave; + + TRACE_LOCK(intSave); + g_traceHwiFliterHook = hook; + TRACE_UNLOCK(intSave); +} + +#ifdef LOSCFG_SHELL +LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTraceSetMask(INT32 argc, const CHAR **argv) //׷¼// +{ + size_t mask; + CHAR *endPtr = NULL; + + if (argc >= 2) { /* 2:Just as number of parameters */ + PRINTK("\nUsage: trace_mask or trace_mask ID\n"); + return OS_ERROR; + } + + if (argc == 0) { + mask = TRACE_DEFAULT_MASK; + } else { + mask = strtoul(argv[0], &endPtr, 0); + } + LOS_TraceEventMaskSet((UINT32)mask); + return LOS_OK; +} + +LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdTraceDump(INT32 argc, const CHAR **argv) //׷ټ¼ת// +{ + BOOL toClient; + CHAR *endPtr = NULL; + + if (argc >= 2) { /* 2:Just as number of parameters */ + PRINTK("\nUsage: trace_dump or trace_dump [1/0]\n"); + return OS_ERROR; + } + + if (argc == 0) { + toClient = FALSE; + } else { + toClient = strtoul(argv[0], &endPtr, 0) != 0 ? TRUE : FALSE; + } + LOS_TraceRecordDump(toClient); + return LOS_OK; +} + +/*кע*/ +SHELLCMD_ENTRY(tracestart_shellcmd, CMD_TYPE_EX, "trace_start", 0, (CmdCallBackFunc)LOS_TraceStart); //׷ٹܵ// +SHELLCMD_ENTRY(tracestop_shellcmd, CMD_TYPE_EX, "trace_stop", 0, (CmdCallBackFunc)LOS_TraceStop); //׷ٹֹܵͣ// +SHELLCMD_ENTRY(tracesetmask_shellcmd, CMD_TYPE_EX, "trace_mask", 1, (CmdCallBackFunc)OsShellCmdTraceSetMask); //׷¼// +SHELLCMD_ENTRY(tracereset_shellcmd, CMD_TYPE_EX, "trace_reset", 0, (CmdCallBackFunc)LOS_TraceReset); //׷ټ¼// +SHELLCMD_ENTRY(tracedump_shellcmd, CMD_TYPE_EX, "trace_dump", 1, (CmdCallBackFunc)OsShellCmdTraceDump); //ת׷ټ¼// +#endif + +#endif /* LOSCFG_KERNEL_TRACE */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ diff --git a/文豪/trace/pipeline/serial/trace_pipeline_serial.c b/文豪/trace/pipeline/serial/trace_pipeline_serial.c new file mode 100644 index 0000000..e61300b --- /dev/null +++ b/文豪/trace/pipeline/serial/trace_pipeline_serial.c @@ -0,0 +1,98 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: LiteOS Trace Pipeline of Serial Implementation + * Author: Huawei LiteOS Team + * Create: 2020-03-31 + * 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 "trace_pipeline_serial.h" +#include "trace_pipeline.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#ifdef LOSCFG_TRACE_CONTROL_AGENT +UINT32 SerialPipelineInit(VOID) //ڳʼйܵ// +{ + return uart_hwiCreate(); +} + +UINT32 SerialDataReceive(UINT8 *data, UINT32 size, UINT32 timeout) //ڴӴйܵ// +{ + return uart_read(data, size, timeout); +} + +UINT32 SerialWait(VOID) //ڵȴйܵ׼// +{ + return uart_wait_adapt(); +} + +#else//4ų2930 + +UINT32 SerialPipelineInit(VOID) //ʾʼɹ// +{ + return LOS_OK; +} + +UINT32 SerialDataReceive(UINT8 *data, UINT32 size, UINT32 timeout) //ʾյ// +{ + return LOS_OK; +} + +UINT32 SerialWait(VOID) //ʾѾ׼// +{ + return LOS_OK; +} +#endif + +VOID SerialDataSend(UINT16 len, UINT8 *data) //йܵ// +{ + UINT32 i; + + for (i = 0; i < len; i++) { + UART_PUTC(data[i]); + } +} + +STATIC const TracePipelineOps g_serialOps = { + .init = SerialPipelineInit, + .dataSend = SerialDataSend, + .dataRecv = SerialDataReceive, + .wait = SerialWait, +}; + +UINT32 OsTracePipelineInit(VOID) //ڳʼ׷ٹܵע֮صIJӿ// +{ + OsTracePipelineReg(&g_serialOps); + return g_serialOps.init(); +} + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ diff --git a/文豪/trace/pipeline/serial/trace_pipeline_serial.h b/文豪/trace/pipeline/serial/trace_pipeline_serial.h new file mode 100644 index 0000000..a3cf977 --- /dev/null +++ b/文豪/trace/pipeline/serial/trace_pipeline_serial.h @@ -0,0 +1,50 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: LiteOS Trace Pipeline of Serial Implementation HeadFile + * Author: Huawei LiteOS Team + * Create: 2020-03-16 + * 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. + * --------------------------------------------------------------------------- */ + +#ifndef _TRACE_PIPELINE_SERIAL_H +#define _TRACE_PIPELINE_SERIAL_H + +#include "los_typedef.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +extern INT32 uart_putc(CHAR c); //򴮿ڷһַ// + +#define UART_PUTC(c) uart_putc((c)) //uart_putc// + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _TRACE_PIPELINE_SERIAL_H */ diff --git a/文豪/trace/pipeline/trace_pipeline.c b/文豪/trace/pipeline/trace_pipeline.c new file mode 100644 index 0000000..33e5f63 --- /dev/null +++ b/文豪/trace/pipeline/trace_pipeline.c @@ -0,0 +1,156 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: LiteOS Trace Pipeline Implementation + * Author: Huawei LiteOS Team + * Create: 2020-03-31 + * 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 "trace_pipeline.h" +#include "trace_tlv.h" +#include "los_trace_pri.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +//ֹ// +LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_pipeSpin); //ʼһ// +#define PIPE_LOCK(state) LOS_SpinLockSave(&g_pipeSpin, &(state)) //// +#define PIPE_UNLOCK(state) LOS_SpinUnlockRestore(&g_pipeSpin, (state)) //// + +STATIC TlvTable g_traceTlvTblNotify[] = { //ṹijԱͺʹС// + { CMD, LOS_OFF_SET_OF(TraceNotifyFrame, cmd), sizeof(UINT32) }, + { PARAMS, LOS_OFF_SET_OF(TraceNotifyFrame, param), sizeof(UINT32) }, + { TRACE_TLV_TYPE_NULL, 0, 0 }, +}; + +STATIC TlvTable g_traceTlvTblHead[] = { //ṹijԱͺʹС// + { ENDIAN, LOS_OFF_SET_OF(TraceBaseHeaderInfo, bigLittleEndian), sizeof(UINT32) }, + { VERSION, LOS_OFF_SET_OF(TraceBaseHeaderInfo, version), sizeof(UINT32) }, + { CLOCK_FREQ, LOS_OFF_SET_OF(TraceBaseHeaderInfo, clockFreq), sizeof(UINT32) }, + { TRACE_TLV_TYPE_NULL, 0, 0 }, +}; + +STATIC TlvTable g_traceTlvTblObj[] = { //ṹijԱ͡ƫλúʹС// + { ADDR, LOS_OFF_SET_OF(ObjData, id), sizeof(UINT32) }, + { PRIO, LOS_OFF_SET_OF(ObjData, prio), sizeof(UINT32) }, + { NAME, LOS_OFF_SET_OF(ObjData, name), sizeof(CHAR) * LOSCFG_TRACE_OBJ_MAX_NAME_SIZE }, + { TRACE_TLV_TYPE_NULL, 0, 0 }, +}; + +STATIC TlvTable g_traceTlvTblEvent[] = { //ṹijԱͺʹС// +#ifdef LOSCFG_TRACE_FRAME_CORE_MSG + { CORE, LOS_OFF_SET_OF(TraceEventFrame, core), sizeof(UINT32) }, +#endif + { EVENT_CODE, LOS_OFF_SET_OF(TraceEventFrame, eventType), sizeof(UINT32) }, + { CUR_TIME, LOS_OFF_SET_OF(TraceEventFrame, curTime), sizeof(UINT64) }, + +#ifdef LOSCFG_TRACE_FRAME_EVENT_COUNT + { EVENT_COUNT, LOS_OFF_SET_OF(TraceEventFrame, eventCount), sizeof(UINT32) }, +#endif + { CUR_TASK, LOS_OFF_SET_OF(TraceEventFrame, curTask), sizeof(UINT32) }, + { IDENTITY, LOS_OFF_SET_OF(TraceEventFrame, identity), sizeof(UINTPTR) }, + { EVENT_PARAMS, LOS_OFF_SET_OF(TraceEventFrame, params), sizeof(UINTPTR) * LOSCFG_TRACE_FRAME_MAX_PARAMS }, + { TRACE_TLV_TYPE_NULL, 0, 0 }, +}; + +STATIC TlvTable *g_traceTlvTbl[] = { + g_traceTlvTblNotify, + g_traceTlvTblHead, + g_traceTlvTblObj, + g_traceTlvTblEvent +}; + +STATIC UINT32 DefaultPipelineInit(VOID) +{ + return LOS_OK; +} + +STATIC VOID DefaultDataSend(UINT16 len, UINT8 *data) +{ //lendataΪ"δʹ"// + (VOID)len; //// + (VOID)data; +} + +STATIC UINT32 DefaultDataReceive(UINT8 *data, UINT32 size, UINT32 timeout) +{ + (VOID)data; //datasizetimeoutΪ"δʹ"// + (VOID)size; + (VOID)timeout; + return LOS_OK; +} + +STATIC UINT32 DefaultWait(VOID) +{ + return LOS_OK; +} + +STATIC TracePipelineOps g_defaultOps = { + .init = DefaultPipelineInit, + .dataSend = DefaultDataSend, + .dataRecv = DefaultDataReceive, + .wait = DefaultWait, +}; + +STATIC const TracePipelineOps *g_tracePipelineOps = &g_defaultOps; + +VOID OsTracePipelineReg(const TracePipelineOps *ops) +{ + g_tracePipelineOps = ops; //עһTracePipelineOpsṹָ// +} + +VOID OsTraceDataSend(UINT8 type, UINT16 len, UINT8 *data) //ڷ׷// +{ + UINT32 intSave; + UINT8 outBuf[LOSCFG_TRACE_TLV_BUF_SIZE] = {0}; + + if ((type > TRACE_MSG_MAX) || (len > LOSCFG_TRACE_TLV_BUF_SIZE)) { //ĺϷԼ// + return; + } + + //ݽб// + len = OsTraceDataEncode(type, g_traceTlvTbl[type], data, &outBuf[0], sizeof(outBuf)); + + PIPE_LOCK(intSave); //ȡֹ̲ܵ߳// + g_tracePipelineOps->dataSend(len, &outBuf[0]); //ͱ// + PIPE_UNLOCK(intSave); //ͷŹܵ// +} + +UINT32 OsTraceDataRecv(UINT8 *data, UINT32 size, UINT32 timeout) //ڽ׷// +{ + return g_tracePipelineOps->dataRecv(data, size, timeout); +} + +UINT32 OsTraceDataWait(VOID) //ڵȴ׷// +{ + return g_tracePipelineOps->wait(); +} + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ diff --git a/文豪/trace/pipeline/trace_pipeline.h b/文豪/trace/pipeline/trace_pipeline.h new file mode 100644 index 0000000..49e292b --- /dev/null +++ b/文豪/trace/pipeline/trace_pipeline.h @@ -0,0 +1,104 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: LiteOS Trace Pipeline Implementation HeadFile + * Author: Huawei LiteOS Team + * Create: 2020-03-16 + * 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. + * --------------------------------------------------------------------------- */ + +#ifndef _TRACE_PIPELINE_H +#define _TRACE_PIPELINE_H + +#include "los_typedef.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/*ʵ׷ˮߵĹ*/ +typedef struct { + UINT32 (*init)(VOID); //ڳʼ// + VOID (*dataSend)(UINT16 len, UINT8 *data); //ڷ// + UINT32 (*dataRecv)(UINT8 *data, UINT32 size, UINT32 timeout); //ڽ// + UINT32 (*wait)(VOID); //ڵȴ// +} TracePipelineOps; + +/* used as tlv's tag */ +enum TraceMsgType { //ڱʾ׷Ϣ// + //// + NOTIFY, //֪ͨ// + HEAD, //ͷ// + OBJ, //// + EVENT, //¼// + + TRACE_MSG_MAX, //ֵ// +}; + +enum TraceNotifySubType { //ڱʾ֪ͨϢ// + CMD = 0x1, + PARAMS, +}; + +enum TraceHeadSubType { //ڱʾ׷ͷϢ// + ENDIAN = 0x1, //ֽ// + VERSION, //汾// + OBJ_SIZE, //С// + OBJ_COUNT, //// + CUR_INDEX, //ǰ// + MAX_RECODE, + CUR_OBJ_INDEX, + CLOCK_FREQ, +}; + +enum TraceObjSubType { //ڱʾ׷ٶ// + ADDR = 0x1, //ַ// + PRIO, //ȼ/ + NAME, //// +}; + +enum TraceEvtSubType { //ڱʾ׷¼// + CORE = 0x1, //ı// + EVENT_CODE, //¼// + CUR_TIME, //ǰʱ// + EVENT_COUNT, //¼// + CUR_TASK, //ǰ// + IDENTITY, //Ϣ// + EVENT_PARAMS, //¼// +}; + +extern VOID OsTracePipelineReg(const TracePipelineOps *ops); //ע׷ٹܵ// +extern UINT32 OsTracePipelineInit(VOID); //ڳʼ׷ٹܵ// + +extern VOID OsTraceDataSend(UINT8 type, UINT16 len, UINT8 *data); //ڷ׷// +extern UINT32 OsTraceDataRecv(UINT8 *data, UINT32 size, UINT32 timeout); //ڽ׷// +extern UINT32 OsTraceDataWait(VOID); //ڵȴ׷// + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _TRACE_PIPELINE_H */ diff --git a/文豪/trace/pipeline/trace_tlv.c b/文豪/trace/pipeline/trace_tlv.c new file mode 100644 index 0000000..4545766 --- /dev/null +++ b/文豪/trace/pipeline/trace_tlv.c @@ -0,0 +1,121 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: LiteOS Trace Tlv Implementation + * Author: Huawei LiteOS Team + * Create: 2020-03-31 + * 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 "trace_tlv.h" +#include "securec.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define CRC_WIDTH 8 //CRCλ// +#define CRC_POLY 0x1021 //CRCʽ// +#define CRC_TOPBIT 0x8000 //CRCеλ// + +STATIC UINT16 CalcCrc16(const UINT8 *buf, UINT32 len) //ڼ16λCRCУֵ// +{ + UINT32 i; + UINT16 crc = 0; + + for (; len > 0; len--) { + crc = crc ^ (*buf++ << CRC_WIDTH); + for (i = 0; i < CRC_WIDTH; i++) { + if (crc & CRC_TOPBIT) { + crc = (crc << 1) ^ CRC_POLY; + } else { + crc <<= 1; + } + } + } + return crc; +} + +STATIC UINT32 OsWriteTlv(UINT8 *tlvBuf, UINT8 type, UINT8 len, UINT8 *value) //TLVдTLV// +{ + TraceMsgTlvBody *body = (TraceMsgTlvBody *)tlvBuf; + + if (len == 0) { + return 0; + } + + body->type = type; + body->len = len; + /* Do not check return value for performance, if copy failed, only this package will be discarded */ + (VOID)memcpy_s(body->value, len, value, len); + return len + sizeof(body->type) + sizeof(body->len); //ʵдֽ// +} + +/*TLVеĶ壬ԴݱTLVʽдTLV*/ +STATIC UINT32 OsTlvEncode(const TlvTable *table, UINT8 *srcBuf, UINT8 *tlvBuf, INT32 tlvBufLen) +{ + UINT32 len = 0; + const TlvTable *tlvTableItem = table; + + while (tlvTableItem->tag != TRACE_TLV_TYPE_NULL) { + if ((len + tlvTableItem->elemSize + sizeof(UINT8) + sizeof(UINT8)) > tlvBufLen) { + break; + } + len += OsWriteTlv(tlvBuf + len, tlvTableItem->tag, tlvTableItem->elemSize, srcBuf + tlvTableItem->elemOffset); + tlvTableItem++; + } + return len; +} + +/*ԴݰTLVĶ룬дĿ껺*/ +UINT32 OsTraceDataEncode(UINT8 type, const TlvTable *table, UINT8 *src, UINT8 *dest, INT32 destLen) +{ + UINT16 crc; + INT32 len; + INT32 tlvBufLen; + UINT8 *tlvBuf = NULL; + + TraceMsgTlvHead *head = (TraceMsgTlvHead *)dest; + tlvBufLen = destLen - sizeof(TraceMsgTlvHead); + + if ((tlvBufLen <= 0) || (table == NULL)) { + return 0; + } + + tlvBuf = dest + sizeof(TraceMsgTlvHead); + len = OsTlvEncode(table, src, tlvBuf, tlvBufLen); + crc = CalcCrc16(tlvBuf, len); + + head->magicNum = TRACE_TLV_MSG_HEAD; + head->msgType = type; + head->len = len; + head->crc = crc; + return len + sizeof(TraceMsgTlvHead); +} + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ diff --git a/文豪/trace/pipeline/trace_tlv.h b/文豪/trace/pipeline/trace_tlv.h new file mode 100644 index 0000000..1871012 --- /dev/null +++ b/文豪/trace/pipeline/trace_tlv.h @@ -0,0 +1,95 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: LiteOS Trace Tlv Implementation HeadFile + * Author: Huawei LiteOS Team + * Create: 2020-03-16 + * 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. + * --------------------------------------------------------------------------- */ + +#ifndef _TRACE_TLV_H +#define _TRACE_TLV_H + +#include "los_typedef.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define TRACE_TLV_MSG_HEAD 0xFF +#define TRACE_TLV_TYPE_NULL 0xFF + +typedef struct { + UINT8 magicNum; //ħ// + UINT8 msgType; //Ϣ// + UINT16 len; //Ϣ// + UINT16 crc; //CRCУ// +} TraceMsgTlvHead; //TLVϢͷ// + +typedef struct { + UINT8 type; //Ϣ/// + UINT8 len; //Ϣ// + UINT8 value[]; //// +} TraceMsgTlvBody; //TLVϢϢ// + +typedef struct { + UINT8 tag; //ǩ// + UINT8 elemOffset; //Ԫƫ// + UINT8 elemSize; //ԪشС// +} TlvTable; //TLV// + +/** + * @ingroup los_trace + * @brief Encode trace raw data. + * + * @par Description: + * This API is used to encode trace raw data to tlv data. + * @attention + * + * + * @param type [IN] Type #UINT8. The type stands for different struct of src data. + * @param src [IN] Type #UINT8 *. The raw trace data. + * @param table [IN] Type #const TlvTable *. The tlv table descript elemOffset and elemSize. + * @param dest [OUT] Type #UINT8 *. The tlv data. + * @param destLen [IN] Type #UINT8 *. The tlv buf max len. + + * @retval #0 convert failed. + * @retval #UINT32 convert success bytes. + * + * @par Dependency: + * + * @see LOS_TraceDataEncode + * @since Huawei LiteOS V200R005C00 + */ +extern UINT32 OsTraceDataEncode(UINT8 type, const TlvTable *table, UINT8 *src, UINT8 *dest, INT32 destLen); +/*TLVϢԭʼ׷ݽб룬ӦTLV*/ +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _TRACE_TLV_H */ \ No newline at end of file diff --git a/文豪/trace/trace_offline.c b/文豪/trace/trace_offline.c new file mode 100644 index 0000000..f23a43f --- /dev/null +++ b/文豪/trace/trace_offline.c @@ -0,0 +1,264 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: LiteOS Trace Offline Mode Implementation + * Author: Huawei LiteOS Team + * Create: 2020-03-31 + * 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_trace_pri.h" +#include "trace_pipeline.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#ifdef LOSCFG_RECORDER_MODE_OFFLINE +#define BITS_NUM_FOR_TASK_ID 16 //ָIDλ// + +LITE_OS_SEC_BSS STATIC TraceOfflineHeaderInfo g_traceRecoder; //¼߸ټ¼Ϣ// +LITE_OS_SEC_BSS STATIC UINT32 g_tidMask[LOSCFG_BASE_CORE_TSK_LIMIT] = {0}; //ڴ洢ID// + +UINT32 OsTraceGetMaskTid(UINT32 tid) //ڻȡID// +{ + return tid | ((tid < LOSCFG_BASE_CORE_TSK_LIMIT) ? g_tidMask[tid] << BITS_NUM_FOR_TASK_ID : 0); /* tid < 65535 */ +} + +UINT32 OsTraceBufInit(VOID *buf, UINT32 size) //ڳʼ߸ٻ// +{ + UINT32 headSize; + + headSize = sizeof(OfflineHead) + sizeof(ObjData) * LOSCFG_TRACE_OBJ_MAX_NUM; //ڴ洢߸ټ¼ͷϢ// + if (size <= headSize) { + TRACE_ERROR("trace buf size not enough than 0x%x\n", headSize); + return LOS_ERRNO_TRACE_BUF_TOO_SMALL; + } + + if (buf == NULL) { + buf = LOS_MemAlloc(m_aucSysMem1, size); + if (buf == NULL) { + return LOS_ERRNO_TRACE_NO_MEMORY; + } + } + + (VOID)memset_s(buf, size, 0, size); + g_traceRecoder.head = (OfflineHead *)buf; + g_traceRecoder.head->baseInfo.bigLittleEndian = TRACE_BIGLITTLE_WORD; + g_traceRecoder.head->baseInfo.version = TRACE_VERSION(TRACE_MODE_OFFLINE); + g_traceRecoder.head->baseInfo.clockFreq = GET_SYS_CLOCK(); + g_traceRecoder.head->objSize = sizeof(ObjData); + g_traceRecoder.head->frameSize = sizeof(TraceEventFrame); + g_traceRecoder.head->objOffset = sizeof(OfflineHead); + g_traceRecoder.head->frameOffset = headSize; + g_traceRecoder.head->totalLen = size; + + g_traceRecoder.ctrl.curIndex = 0; + g_traceRecoder.ctrl.curObjIndex = 0; + g_traceRecoder.ctrl.maxObjCount = LOSCFG_TRACE_OBJ_MAX_NUM; + g_traceRecoder.ctrl.maxRecordCount = (size - headSize) / sizeof(TraceEventFrame); + g_traceRecoder.ctrl.objBuf = (ObjData *)((UINTPTR)buf + g_traceRecoder.head->objOffset); + g_traceRecoder.ctrl.frameBuf = (TraceEventFrame *)((UINTPTR)buf + g_traceRecoder.head->frameOffset); + + return LOS_OK; +} + +VOID OsTraceObjAdd(UINT32 eventType, UINT32 taskId) //߸ٻӶ// +{ + UINT32 intSave; + UINT32 index; + ObjData *obj = NULL; + + TRACE_LOCK(intSave); + /* add obj begin */ + index = g_traceRecoder.ctrl.curObjIndex; + if (index >= LOSCFG_TRACE_OBJ_MAX_NUM) { /* do nothing when config LOSCFG_TRACE_OBJ_MAX_NUM = 0 */ + TRACE_UNLOCK(intSave); + return; + } + obj = &g_traceRecoder.ctrl.objBuf[index]; + + if (taskId < LOSCFG_BASE_CORE_TSK_LIMIT) { + g_tidMask[taskId]++; + } + + OsTraceSetObj(obj, OS_TCB_FROM_TID(taskId)); + + g_traceRecoder.ctrl.curObjIndex++; + if (g_traceRecoder.ctrl.curObjIndex >= g_traceRecoder.ctrl.maxObjCount) { + g_traceRecoder.ctrl.curObjIndex = 0; /* turn around */ + } + /* add obj end */ + TRACE_UNLOCK(intSave); +} + +VOID OsTraceWriteOrSendEvent(const TraceEventFrame *frame) //߸ٻд¼֡// +{ + UINT16 index; + UINT32 intSave; + + TRACE_LOCK(intSave); + index = g_traceRecoder.ctrl.curIndex; + (VOID)memcpy_s(&g_traceRecoder.ctrl.frameBuf[index], sizeof(TraceEventFrame), frame, sizeof(TraceEventFrame)); + + g_traceRecoder.ctrl.curIndex++; + if (g_traceRecoder.ctrl.curIndex >= g_traceRecoder.ctrl.maxRecordCount) { + g_traceRecoder.ctrl.curIndex = 0; + } + TRACE_UNLOCK(intSave); +} + +VOID OsTraceReset(VOID) //߸ٻ// +{ + UINT32 intSave; + UINT32 bufLen; + + TRACE_LOCK(intSave); + bufLen = sizeof(TraceEventFrame) * g_traceRecoder.ctrl.maxRecordCount; + (VOID)memset_s(g_traceRecoder.ctrl.frameBuf, bufLen, 0, bufLen); + g_traceRecoder.ctrl.curIndex = 0; + TRACE_UNLOCK(intSave); +} + +STATIC VOID OsTraceInfoObj(VOID) //ڴӡ߸ٶϢ// +{ + UINT32 i; + ObjData *obj = &g_traceRecoder.ctrl.objBuf[0]; + + if (g_traceRecoder.ctrl.maxObjCount > 0) { + PRINTK("CurObjIndex = %u\n", g_traceRecoder.ctrl.curObjIndex); + PRINTK("Index TaskID TaskPrio TaskName \n"); + for (i = 0; i < g_traceRecoder.ctrl.maxObjCount; i++, obj++) { + PRINTK("%-7u 0x%-6x %-10u %s\n", i, obj->id, obj->prio, obj->name); + } + PRINTK("\n"); + } +} + +STATIC VOID OsTraceInfoEventTitle(VOID) //ڴӡ߸¼// +{ + PRINTK("CurEvtIndex = %u\n", g_traceRecoder.ctrl.curIndex); + + PRINTK("Index Time(cycles) EventType CurTask Identity "); +#ifdef LOSCFG_TRACE_FRAME_CORE_MSG + PRINTK("cpuId hwiActive taskLockCnt "); +#endif +#ifdef LOSCFG_TRACE_FRAME_EVENT_COUNT + PRINTK("eventCount "); +#endif + if (LOSCFG_TRACE_FRAME_MAX_PARAMS > 0) { + PRINTK("params "); + } + PRINTK("\n"); +} + +STATIC VOID OsTraceInfoEventData(VOID) //ڴӡ߸¼// +{ + UINT32 i, j; + TraceEventFrame *frame = &g_traceRecoder.ctrl.frameBuf[0]; + + for (i = 0; i < g_traceRecoder.ctrl.maxRecordCount; i++, frame++) { + PRINTK("%-7u 0x%-15llx 0x%-12x 0x%-7x 0x%-11x ", i, frame->curTime, frame->eventType, + frame->curTask, frame->identity); +#ifdef LOSCFG_TRACE_FRAME_CORE_MSG + UINT32 taskLockCnt = frame->core.taskLockCnt; +#ifdef LOSCFG_KERNEL_SMP + /* + * For smp systems, TRACE_LOCK will requst taskLock, and this counter + * will increase by 1 in that case. + */ + taskLockCnt -= 1; +#endif + PRINTK("%-11u %-11u %-11u", frame->core.cpuId, frame->core.hwiActive, taskLockCnt); +#endif +#ifdef LOSCFG_TRACE_FRAME_EVENT_COUNT + PRINTK("%-11u", frame->eventCount); +#endif + for (j = 0; j < LOSCFG_TRACE_FRAME_MAX_PARAMS; j++) { + PRINTK("0x%-11x", frame->params[j]); + } + PRINTK("\n"); + } +} + +STATIC VOID OsTraceInfoDisplay(VOID) //ʾ߸Ϣ// +{ + OfflineHead *head = g_traceRecoder.head; + + PRINTK("*******TraceInfo begin*******\n"); + PRINTK("clockFreq = %u\n", head->baseInfo.clockFreq); + + OsTraceInfoObj(); + + OsTraceInfoEventTitle(); + OsTraceInfoEventData(); + + PRINTK("*******TraceInfo end*******\n"); +} + +#ifdef LOSCFG_TRACE_CLIENT_INTERACT +STATIC VOID OsTraceSendInfo(VOID) //ڷ߸Ϣ// +{ + UINT32 i; + ObjData *obj = NULL; + TraceEventFrame *frame = NULL; + + OsTraceDataSend(HEAD, sizeof(OfflineHead), (UINT8 *)g_traceRecoder.head); + + obj = &g_traceRecoder.ctrl.objBuf[0]; + for (i = 0; i < g_traceRecoder.ctrl.maxObjCount; i++) { + OsTraceDataSend(OBJ, sizeof(ObjData), (UINT8 *)(obj + i)); + } + + frame = &g_traceRecoder.ctrl.frameBuf[0]; + for (i = 0; i < g_traceRecoder.ctrl.maxRecordCount; i++) { + OsTraceDataSend(EVENT, sizeof(TraceEventFrame), (UINT8 *)(frame + i)); + } +} +#endif + +VOID OsTraceRecordDump(BOOL toClient) //߸Ϣ// +{ + if (!toClient) { //ָʾǷ߸Ϣ// + OsTraceInfoDisplay(); + return; + } + +#ifdef LOSCFG_TRACE_CLIENT_INTERACT + OsTraceSendInfo(); +#endif +} + +OfflineHead *OsTraceRecordGet(VOID) //ڻȡ߸ټ¼ͷϢ// +{ + return g_traceRecoder.head; +} + +#endif /* LOSCFG_RECORDER_MODE_OFFLINE */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ diff --git a/文豪/trace/trace_online.c b/文豪/trace/trace_online.c new file mode 100644 index 0000000..6faba44 --- /dev/null +++ b/文豪/trace/trace_online.c @@ -0,0 +1,117 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: LiteOS Trace Online Mode Implementation + * Author: Huawei LiteOS Team + * Create: 2020-03-31 + * 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_trace_pri.h" +#include "trace_pipeline.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#ifdef LOSCFG_RECORDER_MODE_ONLINE +UINT32 OsTraceGetMaskTid(UINT32 taskId) //ڻȡID// +{ + return taskId; +} + +UINT32 OsTraceBufInit(VOID *buf, UINT32 size) //ʼٻ// +{ + (VOID)buf; + (VOID)size; + return LOS_OK; +} + +VOID OsTraceSendHead(VOID) //͸ݵͷϢ// +{ + TraceBaseHeaderInfo head = { + .bigLittleEndian = TRACE_BIGLITTLE_WORD, + .version = TRACE_VERSION(TRACE_MODE_ONLINE), + .clockFreq = GET_SYS_CLOCK(), + }; + + OsTraceDataSend(HEAD, sizeof(TraceBaseHeaderInfo), (UINT8 *)&head); +} + +VOID OsTraceSendNotify(UINT32 type, UINT32 value) //֪ͨ͵ĸ// +{ + TraceNotifyFrame frame = { + .cmd = type, + .param = value, + }; + + OsTraceDataSend(NOTIFY, sizeof(TraceNotifyFrame), (UINT8 *)&frame); +} + +STATIC VOID OsTraceSendObj(const LosTaskCB *tcb) //ͶΪobjĸ// +{ + ObjData obj; + + OsTraceSetObj(&obj, tcb); + OsTraceDataSend(OBJ, sizeof(ObjData), (UINT8 *)&obj); +} + +VOID OsTraceSendObjTable(VOID) //Ͷ͵ĸ// +{ + UINT32 loop; + LosTaskCB *tcb = NULL; + + for (loop = 0; loop < g_taskMaxNum; ++loop) { + tcb = g_taskCBArray + loop; + if (tcb->taskStatus & OS_TASK_STATUS_UNUSED) { + continue; + } + OsTraceSendObj(tcb); + } +} + +VOID OsTraceObjAdd(UINT32 eventType, UINT32 taskId) //ټ¼Ӷ// +{ + if (OsTraceIsEnable()) { + OsTraceSendObj(OS_TCB_FROM_TID(taskId)); + } +} + +VOID OsTraceWriteOrSendEvent(const TraceEventFrame *frame) //¼// +{ + OsTraceDataSend(EVENT, sizeof(TraceEventFrame), (UINT8 *)frame); +} + +OfflineHead *OsTraceRecordGet(VOID) //ȡ߸ټ¼ͷ// +{ + return NULL; //ʾû߸ټ¼// +} + +#endif /* LOSCFG_RECORDER_MODE_ONLINE */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ From 2bdb3fa4bd8a2d663d08bec84f4a1c88df64f80a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E8=B1=AA?= <2548632733@qq.com> Date: Mon, 4 Dec 2023 19:10:33 +0800 Subject: [PATCH 2/4] zhangxinyuan --- kkk.zip | Bin 0 -> 53432 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 kkk.zip diff --git a/kkk.zip b/kkk.zip new file mode 100644 index 0000000000000000000000000000000000000000..b5323c3119761ad9240d6743110933dd3af1dad0 GIT binary patch literal 53432 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

@ZQcpVKYH!H)3v})qheLTNSptb-U$6D* zSQ#4`37DPK0tyC=t3nlZ&tIe&MGZhW%)9453VH;y_JVP3Au4)Rq@eVmVI9Q>^1fwm zylXe23$Sc`J!-adKOYZs=ehH*^l$1B1L;B3;#|WI=@#+CMM2Mv9C6nl2E{m(^B)OgsNhHXEm)PS}m?uFrmI4cSM2x&Ua=ScU z*W%#^bNsEz4rIa>tg#hIWR>WpF5HdLQd;>`XD*r(c;t$td)b&on4Dj=DPi!k;zD?rs zC+l%iR|%KsD}uKmbdX#Dizr@{C#_8sB&B_w@F8M`B$QW3k&ssgH`WHbajJGulpl!U zBe=d31Ln(!b�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�Xqvz z3zL6^zgV8;P5i0tLm31oxv%{jHh@iBDl0g%%HH+|U5kpB)8a(6S=rPr;o6+)luETa zP^13p`w3z`W&_%NLyvrK$m5O%XDic=22VRzuyNUx8Q=B?^ZSkBk7W4CQ&l>3>uGO? z%lpsiMK;U7Dc_DA%9Y!km|KJ-^}0sIA}$`DTD}5#N_mGi%ZC7#?;<^TDl(V~Pz}w% z;lPfJs&e#?2X}P|3VkNd^(?Av2W<(H^~m@*XU0NgCkDvyF8FW`{Ln;Q-huBf#bVnM z^4ohF&XjTT@}10+iqMtthoM0z_GM{%7+9=TLR7k*eZrxnitDni5S9TO;R_;yKXN`- zQ7M5fM>7f_a-W3S2cv~g-NvtQR+xDY>R>9hG^!K&rJN{*4v?<+>&U@rdFQh6Im6l6 zM468Jb-o4b3=M_3WQlDm3iF%;L|z^Sa~C?%9e(mdVUX>>(0XMK&vpq>Uf?f(^EP1e zfr{rc4pCMzMWRRoNfy{8gXENSxWNGv_qy4brdbc`(C!rrJss(9`2;zZP|I(W&qbab z`QsODxhU#H?~pt-T0?^@=At~{Xz|!YSb<5o+xDolSk+?7jpko6EiO#96Q*>~8paI% z09zrlRna)&$jO8zQA0aBa&Quzwrp($VONt6je78j$6P<7t$RCl@x_OOHm*as1jfgt zFg6g;EJcwMhPEe5sM5d%G#@7oWX?gubJ%T3D{PI3UcAu?W)yAW<@+=oId_W_%|sn| z`Rj@s`-HpC?}W(%8=3srrt~u!VzX^P4AaX3Z1laY*9QCqx+f9N?UXs!r_@ z*1+A1u?;9>rP=(_YA;Sna@jYqZn zbYv;N3R${U%U;@Un|K;M!Gcvkr%J~U0gH)^A9f!*6PshtYS!1Irf1hvQ|5sH^K)+u5D$b_Nx%pO^cErQ00suO%L) z#L;c6T<%z`Ap=u9E>CSuj@KL|^Ty(y&wI;iW|!y1_FILL$5o$W8X1+7E^Uqhu-YJr zOf)5HQQ>`1d9F3*1e+e2>c17k+GzL*j8;}NN~$Ame|STO-?qDhp5zk--vU&Glw)#f znimWaPn_Wxx#~mb4wXde1NEHFUnCry-X-~BI-I`fIq3!!QH8+&szN21R_6&*vzSC> zxICmT-x$2;3!`7Gs_Eh2rUN!>%+O<^#@4fO)r?>gGKS0ejx^Ghr1%*I{%kF9ucX~E z#AX4B&*I}U->oyh#x`?Q}B?cOH@f+~VP^397322GyPWY)vs15vNi(D`jmmM?cbtu4LarzM~Ms zTQ{L$R!|9h1|SNFz(t2^g{vQXF-@wNX0OJkR*cL#y<7=rQ?m8FXNHZp^V34#mU%s^4*@1SBH-=f==G^l3^OO2a`tactstyrEw&5n6 z93u~g`L}%lU!Jp32V|k{07f`*ZYgx4s-OQcUhb>(}W;#a}P$%i&mu0Tc$! zH{>d9Jh=b!UjsAOi(@rt(@N=!_U?)pHVu{h>=G!~eZ-;}6W-3|5pbX_Fr*^O=7rg{ zw?h+PbW7hH8NvpyuP5>JDLCIH(iCh^Y0y{zev+0L!}XHGkb?Jx_4!fqsH{b`5tF4A z|B1!Q3Y=ys@U#hG6(_`+HnygKfOiq3M4R0hM`jJUI~!aJETSkx?iFbN&-6b4+3kNW zsF_2JfpCAVspWxbU0xY&9c<^BZc=K7_bw~GVc>}<@tB90mk4J5L1{Nx=zC2GJ0ia* zA!izR6Uj*9UpRjU;W}=2g^!ryD+pR``Qv8L*#NoJZ38Kxg0e_$@`Pw`x$uO+VIbf2n*vk~U1L~nV0_u@z7}PNtvOPYh zx?R`a>iswR7?n6$eai7xYiaQg{N3%H{1{Frsi8ag5C3K8ar%)hb+@)_)A#qAFqk1L zY%C0~IOEjXYc6>vw-{Rb1C#o_1?>|I-J&vi9ba3E?!>Vf{|ZZGboDT5pb!Nfw1Yf! z_?kGwu&H-D%|gcR@__0il!FsJCHrTfkvC5HZi(!cw`RXfQ+(%uGv_s(jj*A6$;%ojn$ruyAF^`fjMpQF=bBiHV#>de1!dn;HSxNACrFi{5G;=Qa2gm8Lep9Gvp?^LZ| z+?YF{agcm83$61)v@e#))-6MYlCH39PvrtPIZWS=0uu`*cUMwNqS$iv_OnnHo)CeL zRHR@gi9s;b31Er(CQU>>W};&vI@jFMAh@Lne%GszP|P0byZ5BVq&Ws7^5z4TFtdad zWmBTh7+u^7T^csMNu#so5N-)CO~M}idbH?0P+m}yE#Fvy0tLv!n|~bKd6l}duyWL$ zB<3jMBTa^EMZKfLN$*s%<09tvmLUS=Qe_WHNtD%_B&37erXnGfROi;(CAV4phUFYh z#i5u{=EqJKQDozfLq13>U0XU@!hqaAZ$_yx-0$Z&0lJ2L-(p}^;pk7dlTn!OZJMdL zW~@ksP@DV%q2jfF#Km!F)^Kc9_3zK`rCJ?fg(;U90So0F{inBUmr%E^1rVadlNWV@yg_Xxg_Vi2@_C}sQpH=wQBbB;jLNa*xV21D zydZKVAbt|aXiUX89ZDFGB#2La()GLot=VVa7p{~sMAR&s2qksxkCxRkQTQWxU;u~C z!E-}VW-2)W0dI@5ZC8`>Zr_mQ=$fJ|b(fBKl3R#DuKRYe#UNTU*`+a+_A8%K58aR# zZnNV?$mlRwc0XI&t^L;Mq|KF$1b5+#9w0Lgyw$WHQN6YuFU23IPy9H56j-3l<+ut% zSR+v?(UKfRff)JBR4W`r-=+kWnIsbL=Z4c&(9NiQx{IdgpxEesr9wd}?EBo*Y~-?K z6$U1S-WlZaU+pV(rgZ_mIoyBk2qE?Y$E2Us>Rt%WZSNnFf|s&(Y8ZNh4#5cPLo z@gx*h4Avv!A*zY*yI;3ojnu$7-f;MAih@Y07n-X7qH8ghn!wkf743)q&lb5YT>?tlO*mNIVq@r~*+-#>eX`4Ht`Xyt%Xe##5b?7jait#CSkNQIv>tgd%K_Mjxz`8^{Yg z%GVZ+ry8PUqoprw1JqeRRv)w#o0xs1)lfkYgwi5qBqBCMwq43aC0khXt?q_tC}=

SoB(`zLD@-gobDY-liCq2?`QOaYICBhPK|?6gz`A@e1yy9F zQB$*kS#kbl{y_o|98m}=Z3@EbE5nM=DP}^x%hRCx(-1}ZL+!~w`ZuIN2#obfM+GC~ z@=Yst6S3%!&MBf({HODUB2d{1%H za!xvnO9y17( z7HJgAiCp0|fQ5s!qJX2H5I1H@l!_74&Rj7T`Ht{43Msy!`@x=w9N~>OZ4xeml2F7` zcA$ViVZA?*qrO&;>}%awa!i6GUZQ_7It$tB!I71mFwF-N67JT>Dq>24sEa2JnIyv4 zNf-x1Itl$wv-NDROdna3jF5ZG18P*!|mOzl_;sR%;3#7GzmC4tCWfPY{U z$Ub>2J38MQpo-*^5&lCz`*$>p;MITVdpQ84A${a90Ehrj7k|f-Ks)ZDj_a{z9X_Ik zY$s%(6t_!oRy9nRloEuA8-onR=J#JKVnh6O&c>yP67$pIL$qo6D5BP3K-RD5!yzbS z`p!|1U0Da+!7NOi$PsCwg3bfuS-0r=6yc61i&FR<#0k2KaMmLz1kxOXH4+g2Eg0s; zNkH{1HA0xHCk4CC{pM2f;)(HP0ZzCNaht)K?rRZ^Vi~rP>Qh0Vm*T>oK0f*hNakDd z$$E@?>3mL5HjfK%y~V}Uw6xU3zyo<|=Ib3cA0&VG)5aIDsYq~+66)6{FD|i`&yU1j zuZ~Ky3ySgw5Cgxriv8Ps8MNCjnis2^R)&Qic;^M-s$g$wth1X`GTSKk2@hy`DX(NN zy{9ZNTN7JK*yniTkpqHMH_vy|-F@CDAF4rc4 zh=<31E>q*B)McjAZjG*%_wDB(7oW~n+q=1k)Awy9{^x$w!^3B*6`%LR+my7H77e8F zGnyd;e-$@JujBRPbLS+}YOlsy560QeI4S zUgru#0%%1JSt2NwsU4i0bchIu-yVNHzlKC{k|fxYsXw?BTFx=gW~gGIdfYGZjN057 z!_br>9_(#77Y(Km8>a9w#2h}}uCgn;oc2(FP`AN(@wnN5#|PI^M6W|55UaFkO_tLkBjs}fHO+uRjKiYL|*SarHZI=I+9xvPzcwX|4yMIG3NNYH~@U?A$^LlA&^ z@XA=IZh3P)vwwJ60prL3SkO&6>RVgT;E7KQOT={r_8{w2KCQx75zrS|+_|9M`c%b3 z`jEV!bR(^SnCi3Sq$;Y2!ff3Pjjo;thxA1<4>RT59)(EEo8}TXwjU*#fyc;;q%AQQ z$AVEr<>jRb~BL}(}~V2 zl-vaa=6KYOElzZ2q>OP?^k)=4i@ogl4GUgs-d-Np76DNm44>2>RT!t4pJkR`UY{Ui z#xgF{;Cxwisv2^O9?IaVpAa4a=WoA-4h_Fi5q}v}Xi)g@sh?t40raJ@aR=ULg-TI! z)^;GO&}}+*Ju#JU^KqJLNWn(rt({|`#ybp6`sQ6Wwwte~hV|R>sqJ7g0Xm7;QkM|_ zYmD_(v&}@Q`9G*>i%TbZ=p!F?!U^K;b)3u}9DvDuC>A(XCR&;lYOQ(~qmKA*T{C|c&4zrSf%e|$!)?p(l`R?PVC5L1_Kg*i4RJ8LrOZwG&`fmu z%@A4xtDkMCM>}S-Z;j{dH7=i5$Om!8%-J#G`HDi&6lAYS$Jw3wEaZQm^7TSAuU9)m zt*W8!r)<~$IB-}9bg(IN@hARRlYN~6Cf-^E{mHSDwsi=5++^LWZMPSW_V*5c5@#;*;m z_{SNl#{9?lks|7cMVe%ESq}P$s11tI5Fv4Hc|9B=pSj=0Ol@GXP-ICdbgstwK-nm4 z9}R9$Dd6=6D5IJ2?g}3s;E~_Xg%ao-;vI4!C_&zUu&W|Nz*gk>+$jHxs&i}(Y>m2Y zY}-l4wr$(CZQHhO+crA3?T&5TocC5;{Db}Fsa_~6XyuVmtxToP|b z<7ZvqU-GUzFyvuy6}9dK35fpf5i`9R<=(9@2>DIEWX%jJltuzE3--^X+sf|{?jLs* zHibqoqR*FGl7Hj;sH5|c{do+h+0bw6 zDac~IJLbgmo=T&ogkHwYJs_v*MPUE^4lY_@jMD6X61!HYOqv#|m@y`Uc?ACJz9R>H z&jB59KwzXo#&a?KFR=Lur%@S7h(b?3?Ug$|tZaU!bahUr#F_Q*jNNij1LJG*|(GamGVQ)pv^?nTb1>M4EFIX+qYQx`|@xN=LsF!s1y`c zjHp9t1A+Q#X7yS_KwcG+Ze<4W@daH_SYqR?+EOhrwj(6wLE3$<^5O#cVKLxCPQ3fP zW#RRLf-sw!sM^lijcM~++Ve;9mk<%lyxnRUd^zV|F(LdTuC%rJ$dFKlyVYmK$VwMjPkMBRA`LwC&e06nAi7fC>rhs;0l%G@6W@l?>YG!mi zn3=SE?Q9&bsAGv#Pgz&$Y$sR$TURug)EECi(>X(hRm z02qE!Ql2oo$*YRit6dbOWeP+eT4ZxD##Qq&%ol&dRImp>OVh|lMZAU(OA15H=D!|P zkY&1WGSV!+DCMV;|MvoA=o_fi?VPV35c}ht09WD!dOh{MAqkn2>l<|!6 zk|->QRmwRsZ_s9<98H&{NuS66BcXLc76kmE=Vf89Z=athOockwPi?3em04E468G<5 zi89l3dnIN=AaThiQ&l`PlVqs6vW1X@NK~c`7WvyU28zV7MYljjvq>eGA7nmMhjl6l zj_j8OSE({uBcYOoca#lt8TNB)lWN&%lJ#y5+h?v22rNS!|0{<_ycbX0jaWN4{5~9PQA< zDjF#&vxqoj$gg6FFAVbW@wZRWsbJl1 z6@&1h4+w+7Ac3m7ytEt{lCERYBw`rP3z)7B{w@)D4udjgWtl=K^tx`;Wv$GdF3;30 zVGZj{uc@D7#4HV6E*Gy5$y)Tsag(6AbO7LY&b6%!m4Q@4@CTB`oytkp_pcgelze8d z?J<&3%|V;b1`rn`Vw#Uk_h3qDq!x?S7E}#S#GAp5GbI7aV_JV?;Gi8DpM%6m7N^eP zNJxnzb|g-a9WALAEUaMfmN{;`m*-8Jp$s>bQwH4Qv8K-C6ewn6(vVOP=af21kX8iq z<|n|GIX0GvK;S@?IyrPa7Y_!2OO!nQjn^hP(bJ^G+V>VCh$rHa5-GB#`q$0>;h;E` zrB57kqzyR=4bV+CE?m#XnItRH7)~BHW3mt-B-hhcH5@PJCLH+)0MC~yHd3S%OBQC% zfI&qk*0;S$N`sN;w{a$?aPTCs)t-@Tz?nGy#ghG|M2&;VF)2ugz=er>C<2t{FC!q% z!R9Cz>Lu#DR51h(`N$-E#YaclykrSPXU^GYIth(qN9n~l zgyYSF%xP-H5D4QUm^S=?mP&AcIA1xF)r?DpI8u@t*S$%}%9Ie|7RLlc`YllM52e@7 zP?9j4Q)Y7cyUSr((V|-pAt6H>%k@fI$SZ{auSOhuGsJ%bq7RT#iVF$F-olb2#05{x zgq*Zg3%cq&8Uq}RWWL-`$q&-5+AMo9evg<=!8J4qVH)yr_(=(V4EQjD2_awfPa{Zz zA5#>rl3HEv;=8@MxjsHV;m@!!siV?G3S_85l>S7i>ZXQ52=!}!B`jCWOTq$r^3yB< z1flBvL!y&$X^A~`{n0&Rz;*_PH5(TE{d>U?H<4YSn%*b9FrY#UU!#FF-mR~jg8Ll8Pp6qBR9L# z{%dCCv*V0!W=CkR5$ceb zjMY-8bW{I?77&6XHR-Uhd8)1qc%Q`WT^KK37I%F$GSCyoiM>FJNhMHDag$iKZ>%fv zs!r%rS(<^E820F@AFuvi_fJ-v(W$Hy@(EdW5_~+qlHtKlJ&>EDR27S!{ua$z;l4P!joLo`EPfH^8iDOwl2lr-`o!IEgha6(og)%^FdXD zbGCp;d|E(H7YcPjCKeU`#WI+ayrSY0)UJF;L`R>==i6lL0ZANS_jqJOxCeK20fV3$f#@9JVC;Rq^! zqmSGwg4J?0AhT;`EZtj%D52e#TVu8!~H@H^zT7vEN*BZJ#uI01YckHBHKprpY%WX@q5u4Q97mhU;927&2Rzk;`dF zw4-q{yX(4*O+5d&5fTaDMc9+73$R=AQw|NKST2_f;5izm^o2eGHrZdQCJlJcVJbq# zy9g1{eR2hv76GlyGH}%^P~lA?8Y=V;FUi}uYXYpobk8_Xgq zVtJW+xOf|}6m!CnXRS76nW^^bbv57f(5bP}+3k$A;rq0>*nKg3BNxe%Y*pLG8eKnb zI8()j?B@NvbXc*w9!D?{fy5DFbUc$sBYJn;Zg0j+=n0oxMEYI^)uF(b>@Za`pX~x_?KB zovAfUn3a(Iad`M%`O3JV{qpcS+-k$dX1ekDG`H}%8yJgorT#D)eEkx^ZKKFDQ^AgK z(0KSzrp^He70^JNqrq|J)kze^zW2W{7F zvThnUf02baXfUS+tRfyzMTHMSSrup@T$)ZUA0ce1rj?KW8%fw9{i?8sXfF0=<38VQ zGH5FmyoU=fv~gaUdcJs8znvm=c>`mUZ#haQA8OxZN!bd4FR(jU-~ScS0*+uX)cs$& z*FR`nr8GKf?om0WT^YX4rtaI<&l@{mmacQpWMoZ2>sT++0Q93p__WhDeC>`Kw?lcR zL;6i<^q)qarUpdLo{@6)sg1>lJ}uqMx5dw6EvuZp_LD&R)zZ}+cr%)8wENYB)Gf)$ z01GLqVR81O&*$e4h;7ITImpwG@?ep=b(P+BjGEpaEe4Bi`P8)*S41HTzcTHvC=^*;yGRs)l1QYz|8@hm z)O2lFo=IpSVm4FTy(64y%w#Y1&)s1W z!NhqL?HzcqgpYNl|AXcseL?H=;^T4pTI@68H6E!stjcwermfNLX$}Nmp)Q!MMdG+- zPc#GAp?*A`lc*o`PF1R9li9QSCo|Ak5E8FW!eHfjJed(C<7CY6S27}G_Ir!@vNC;E zv)Ap=4Lfhkw+-6vM*E&i^Hact@4?rXbB^94ENB_SMV8gF8c_7HeeV(H0$V?H*?$X6 zul@r-3w{_fXj72DwaJ~^{|jpA0CAAR_5HlGj(3tq9*R!-~*?f6rVr!TT-2u@ZVSO7xG+ZKh36a+=px}x+ zpSXC4*<(+VpdUQ#MxJWgHxN2M(U>`2_-|1{y_>YMF)W7=p$!CjPtEmQ6sC?9Y z0517q3unX?S;~tVlTqN){@chxz^CdWEkJsnF<5*@0Mp&?jD4Cd&!V03{q7oJm1E^9 zqy)KnAUGvRAu8ZXPpzrfy~|aL-7QBH&_?K)>24h-R|l)LhR%-3gFe}j*x#=b9cVze9`D1$}-$Ml7%j}<{6-Dee4f+wxFUCP6RcFShn_|MaU#k^hy4lr-r4X!9gOP)X5R|woYIe%cmifa6Fc6%AQJl^j^ z)bw=SyB$rg&Qi!;@j5a-+r}%L;!ax$rVd-D*O9Dkt-F6N#<71;n$sIRtPZlY9}D51l)@-Z!jO`&k>NatXH2vV_8(O zte}!-7BBA!slju4j|K2drqKnwbAHS8-s&0xBv_2<>}Q}i%@n>{n=(bqG90J zuDzFJ5XF?)s%!>EVPbR*B{+MI4SSS8G?&i9l~)AuYTuz!!=OlR%iXQ4TZ&n@iA_>T zrJNJ^hC;bmC0Kde0p)Z+A5tH<@H69@wCLfza zh9HO7*Dq#y-HT$cLvco;7nG;q+ zldPr}h@Gsg^}F*kY@IACO(KauN$FwN`paeieqptZxBXT_4f82RK`CsDb@@+!SkZk9 zzCxXfq9y7JQI|<@BlH0IrnDvW%ztIFa)hvv#bCYpeE)>w?Ur{h)}ceL{v$NfW=^)O zPY)ua1-|}5Zpc(EAF&!)dM8KL3T*{$4Q@{wb9roZO{G&)=r1~rVnGW-*Ouh6LZK!} zG#D>ml2RW5W4hwiQs;81IN<%Ryt)Ob;T$;YLw|o}M~tCQsYw>Al}I}$&OK3M z-fhtstXhAXVpuL}PUHSA~*cxJNviU?mgoGxQLJu%b@COci zfPPWLS8yr}q6zz4QEpa`A%W4lhdF=@vOctjA5MF1yY1EYe8~8#;j-pS&f6D630i2! z(xg|z04($z?R9NBXJR4y)!->s40hJmAcy(k6LXbba&fe^JI}hKba`Y}ZPz1pxB6W) zo2XL|Xm;rb{{JRkkiy;68q9sst6%^CD%k%2in+a`g{|}N#_&q(f3uHkf3?cqziH*v z#VaW!loXN)((1N^#Kn9n5Y6t!2+3km#pl36K2l_Ql$?eYiDY(HZMud{Vo79ZUoF#S z^?DQR`27A%Lm4ijk(mw@lElOVHWsY_2nXqHuWP3no|moDY^epIpraN%UvK01;Fbjs zos3LY2|ru^=#&zT%6R5!nJP_zEX8s_q+c^nhNFKr3|!y$#`xa2zJD+j=wK+Oa2eRL zSvd}WI|Pekry?V&43CImW&+Jwq~*ytM#@pSVm>)CW!7S*?}RFvl5{4DK$)^J*qJip z8HJRFJ;t{|6~D>#55+03nkw@5?3D!_sN4!REQgg-s35QAI$p2H!z^5^p5~a*S;*}Dr56Jv)UII~7 zMXfk6;IE9??~0HJ7g>MNlZPKk*+8g4FC`KMcJLx~eNj^Y3{b@ivVldOfOfzc`adg= zZ?3drG$!VNOpLrrC|o2W&dKr^k~wT2BnSnD z5w}R(#Azs=5ylJej6s*!kTH`N8;KogmEsS_fLJ>OCI@&94kVeKp|A;o@of1bLopekb`q=mceP z@rQkBYGMLKN}}RKLNR+^L|vFMLGSD+kbbZ^sdh-(1kwX_a=h(MIM7V0$ zm|=D)d}+2pXl?eG2TPrhfhc{GDY;=3^pky{fc7@_bQN*-Q?Xru>c3x%z>afrgaz*A zD5UFseO~%0gO~wPMR$A13`~TjZ_cFC3G>E`gP*jHgCO`P!;8eJC>f`Wgs0#nX9)kJ zn-Z2yIKwgAF)= z$>OTTS~Jz*3|yaGNxfANJx_qdyR!Q$#2@ZWGr=()c~mga!~1q3X@Qt89u#2eogZ9E)LZ=hpqU9i#Z)bZ3&zk5rI zm^ge_ZIGqq+3KqAYW>)_T)n5f`Kg>(wy~z7^=|J}@$|{x73kJs9MoK|2XaAQ$o(`s zx!fook4n1Om>GOP!Uz#<4_*8AwP@*7t)lZiS(0b!fAVcQE}x zkhvD|{-~JPI=MKx?SIJiS{KkCg=O_s)&BY3xW1w@cpRjh0S;+%rTc!9n_a1Tp}ktN zA)<7ma${{pI5}A8;h1EJdO<)Uq4lw9S>Y3r7%u0nvZ3MW@x3^Cs_A<2w82y6>3#9ZS>AfEq-KA3|5Wb`_x`|kc9WX8bg7`2U0X5hR zKn3ze|v zEVXCElN;Tf!n(Frm8C+fLAh!j4_UZry*D#<-)mO|dTPsXUoarl<_{AtuNBe(G{@aq z3HF!s%bM@0M|$O%H$Az)oeC}#AJMEYDu7E4EudNSG9bwdC*7?6^f-M=Rn}*u4kP*H zX>FeOTdtkg_o9!AwkJq`l)j08=S?^_ZjBVlB1}q#ZG$&3#kCWnQ`DR&TU{m=z0V zCm9qGE=suNxXoo?kT%p&3HnpA_aqHFd34NzO z*6KhfIl`mnQDp%uq2x+?!3GwdIA+!noeA9rNV0}Yy9J2?zS9y^sz6q!WDM(` zCfoUA0imr51~>R;wi#|ibHGrG9#?kkEi~s+Rd}tDWjA=S0usBWVvw~P`6*8=t_tJ&zx8dAPRFf4-+V!NyvYc88aCv zObxbtzT#ALY1p2g93*IHUq9Xn;D@x<#dD#G=4yE{}J)zop0$#X)h8 zkXR}#RDrE}K7jm!dTYJ9pXdUr1yW%sq@udY;SUM1i5LV9G3k|1m663d;z9?n*+x?` z6<p9LpoFnYZu0fpTpp!^e*4%}spQzpq1ws~n3RmS}ej2xz66k6qu)rTVqVv z&_rSiR9auxm+{xh=)y?fdMEuZ;}EBr7V|W$6`A}L-^?;$jIz3y^O=^R7hGJ zSDw1q^eo=hQdL(v5d-4R4}zEcC>KM2#kKC+09w_|?)w^NOP63iquO@Q*A_+a>4T{@ zeSDXdYabJp(XjFfTA#+3n9FolY6N`J?TA$x9*5ZFQd`}wUS}uxczYyo)93mx_sL$s z#p8Hj#w^dzKAQWA-4iEnv|;OJ;sB2(?BJf_d8sJZIz&Ms;kv81Yjoo4+<^JZI1~M;V(uyy#i#D%{Aw8jUYG z$gg_uYX_;9vlstq9=4v?(Ia=S3aTV7=Ev9(Ew*OehF2+52WKC2G`pI}FoK3dbLwln z_0a>Gm@zYlxXLeeoDn}5G_ftBM)yfu~Ehi+qe7xvknljwTVXdThiG=nsn(eY( zU?evleGaS;r@*He7hX&iXdPR~!~v`QV4vCv`#!u2hNf(SDTCSI-iw9WVZMHQ>)< zgqL@<*4scgxH??;6Mcr4X_IS*I{!90NNss>_>gqs`uwYMI%8#4Wku-n_iU3t3c<$? zFEbpHK(TGaj7(0mxey=RXEi)N`;((vaTAkr7T+jP7Y^}cUEwYOQQ7p)IMJ{Vqg1vh z&B`Ko92_5XYSn^29U(D!c58xT-F*2WudcGUbPRuxSbZkQ`u^`= zqa5j`22lXnukq`3xh(_$_@z<*ALpopi;0WLFFH&6#|c?2@n_p_gzA0>kR%u;*qWdv zB;J_2rS(YM2qH_eLv-P9u3)Busi?o*%{RuJt`6;KB~Q=@I#+)nZg0B&hd(=o<%=y{ zmNA>e)v}Ia$|m&4vP&Nw6Ol!6MgoIDm1>KI@wC_W*Zb4O_oLUB>5XmUDTi<9U)w~+ z^QKZ(9;2k35*_2_f@}pA!m1L??Q*QeOiO_%_vq;LWA^nljGaF4@0%xf3Dv4#*QVc- zX{CoI%~*oAW{YI0Y8#6XpYV=#IV`H54C^K45I6DPIE&UyDgg8nQ4xBT5mk7G`v`+q z{O?S)$xM?h&4z&C@WM2SA;pMN@>!^+~?OqS`^WyXrEQHvTFy-UoI&>y7$*%r&}`9}*y#>d9cFY1ko(v7hA ze*11A+9(XvKl0<`LX)8;L6X*>zW{2Va)vv z$|}v7mWm`d7pXw)9?pM?{Si~K2{gzBe&-3&VuIkfI_qRC7L_(s1}QHCAQ*SUM69XG z3JMiy3a*LLBw;U4F#fO>KH0`f(XIn0or(%_1Yft2T!u;$^L%VuB2I8Db;9r&a;#F& zEi(xPkt_-#hfRV?-B55!O$c!%ChHV>Pyx04iU8OoC~keqhUiEiuv1<2Bo#HO|7cl4 z|K%T?Ie%$clSqg0VkJNnN1{i_A$xC&ig+w3$-@k19Aki9VkhpT6bS=n4%QPcZ45x2 z=iIx*BFuPJ4`=G3*8%%QMc$-D2kq-N6m!I4oT!9BVN#L-bmC+WD&Qi?6S+}&HvZOl z4=1FJ0jEUSShBbQ0ynTKa8nAFjM?a-+x(=#qxnGU@g&DkoXO(_<(m-c@Al*g6u6`Y z?Ep*L#`p+8WDW@rU`Tnbefq>8zBpMl;z}V3Dzp2yaY&5`lY#LQS^r4>1>#3pC6m)e z=c)V}?Qh}*5tF%&{K6cJ>HZ?_^E6AEh;wrPXT`=cl131diQIui>yx!~XX+#wllB!S z@qfX}e=h^qlc3f_4X5OY10INRxn_Q8)V-e39HOVG;zUaoWpPsEe0K0)3i0h<@=qnA z9nWWl5RoE?yv8p(1qD4_Zba)uCM}FMSTURxSSw3i81`HBP9WN7KCY51E-jqGT)l-V z&i{l<^`Xl8Wl5QoiiGO==`w3ue;{O@6k7mgeZZ0EC{wZW*5~i2JY_#o&lDS#N<3Q( z_WfR!Hh0f8?87*PAI$FxXSRSnLzz=9jC46?nrBW{H`L;?4E;=*B1MkByBf>FXnV%jUtp%?lSO9 z_p`Ib@vJ9IuUglq+54eaj;-<4#p!zRZJH`=r_1AKaO0fmpg;%>UtaPwQ|V6Vx5?A&Tdryq-^b}}emdr9SLds_rE#JAZn@)RZZ5?nc|YmL zqq*DjbO#>&hDW>e{%bIArMK%z#_4+gzKCoM-b*0sNBhSp)T#|m_F>+O8> z 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 literal 0 HcmV?d00001 From 0771df2fb35a5731773ee0767b6a95b49a203aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E8=B1=AA?= <2548632733@qq.com> Date: Sat, 30 Dec 2023 16:01:48 +0800 Subject: [PATCH 3/4] new code-reading --- debug/los_mux_deadlock.c | 257 +++++++++++++++++++++++++++++ debug/los_mux_debug.c | 189 +++++++++++++++++++++ debug/los_queue_debug.c | 206 +++++++++++++++++++++++ debug/los_sched_debug.c | 347 +++++++++++++++++++++++++++++++++++++++ debug/los_sem_debug.c | 299 +++++++++++++++++++++++++++++++++ kkk.zip | Bin 53432 -> 0 bytes 6 files changed, 1298 insertions(+) create mode 100644 debug/los_mux_deadlock.c create mode 100644 debug/los_mux_debug.c create mode 100644 debug/los_queue_debug.c create mode 100644 debug/los_sched_debug.c create mode 100644 debug/los_sem_debug.c delete mode 100644 kkk.zip diff --git a/debug/los_mux_deadlock.c b/debug/los_mux_deadlock.c new file mode 100644 index 0000000..6862541 --- /dev/null +++ b/debug/los_mux_deadlock.c @@ -0,0 +1,257 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved. + * Description: Mutex Deadlock Check + * 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_mux_debug_pri.h" +#include "los_typedef.h" +#include "los_task.h" +#include "arch/exception.h" +#ifdef LOSCFG_SHELL +#include "shcmd.h" +#endif /* LOSCFG_SHELL */ + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */nbb + +typedef struct { + LOS_DL_LIST muxListHead; /* Task-held mutexs list */ //ڹеĻб// + UINT64 lastAccessTime; /* The last operation time */ //¼һβʱ// +} MuxDLinkCB; + +/*еĻб͸*/ +typedef struct { + LOS_DL_LIST muxList; /* Insert mutex into the owner task CB */ //ڽ뵽Ŀƿ// + VOID *muxCB; /* The Mutex CB pointer */ //ָ򻥳ƿָ// +} MuxDLinkNode; + +STATIC MuxDLinkCB *g_muxDeadlockCBArray = NULL; + +/* + * Mutex deadlock detection time threshold, will print out task information + * that has not been scheduled within this time. + * The unit is tick. + */ +#define OS_MUX_DEADLOCK_CHECK_THRESHOLD 60000 //μ黥֮СʱλΪ// + +UINT32 OsMuxDlockCheckInit(VOID) //ڷڴ沢ʼƿб// +{ + UINT32 index; + UINT32 size = (LOSCFG_BASE_CORE_TSK_LIMIT + 1) * sizeof(MuxDLinkCB); + + /* system resident memory, don't free */ + g_muxDeadlockCBArray = (MuxDLinkCB *)LOS_MemAlloc(m_aucSysMem1, size); + if (g_muxDeadlockCBArray == NULL) { + PRINT_ERR("%s: malloc failed!\n", __FUNCTION__); + return LOS_NOK; + } + + for (index = 0; index < LOSCFG_BASE_CORE_TSK_LIMIT + 1; index++) { + g_muxDeadlockCBArray[index].lastAccessTime = 0; + LOS_ListInit(&g_muxDeadlockCBArray[index].muxListHead); + } + return LOS_OK; +} + +VOID OsMuxDlockNodeInsert(UINT32 taskId, VOID *muxCB) //ָĻвһڵ// +{ + MuxDLinkNode *muxDLNode = NULL; + + if ((taskId > LOSCFG_BASE_CORE_TSK_LIMIT) || (muxCB == NULL)) { + return; + } + + muxDLNode = (MuxDLinkNode *)LOS_MemAlloc(m_aucSysMem1, sizeof(MuxDLinkNode)); + if (muxDLNode == NULL) { + return; + } + (VOID)memset_s(muxDLNode, sizeof(MuxDLinkNode), 0, sizeof(MuxDLinkNode)); + muxDLNode->muxCB = muxCB; + + LOS_ListTailInsert(&g_muxDeadlockCBArray[taskId].muxListHead, &muxDLNode->muxList); +} + +VOID OsMuxDlockNodeDelete(UINT32 taskId, const VOID *muxCB) //ڴָĻɾָĻڵ// +{ + MuxDLinkCB *muxDLCB = NULL; + LOS_DL_LIST *list = NULL; + MuxDLinkNode *muxDLNode = NULL; + + if ((taskId > LOSCFG_BASE_CORE_TSK_LIMIT) || (muxCB == NULL)) { + return; + } + + muxDLCB = &g_muxDeadlockCBArray[taskId]; + LOS_DL_LIST_FOR_EACH(list, &muxDLCB->muxListHead) { + muxDLNode = LOS_DL_LIST_ENTRY(list, MuxDLinkNode, muxList); + if (muxDLNode->muxCB == muxCB) { + LOS_ListDelete(&muxDLNode->muxList); + (VOID)LOS_MemFree(m_aucSysMem1, muxDLNode); + return; + } + } +} + +VOID OsTaskTimeUpdate(UINT32 taskId, UINT64 tickCount) //ڸʱ// +{ + if (taskId > LOSCFG_BASE_CORE_TSK_LIMIT) { + return; + } + + g_muxDeadlockCBArray[taskId].lastAccessTime = tickCount; +} + +STATIC VOID OsDeadlockBackTrace(const LosTaskCB *taskCB) //ڴӡĺջϢ// +{ + TaskContext *context = NULL; + + PRINTK("*******backtrace begin*******\n"); + context = (TaskContext *)taskCB->stackPointer; + ArchBackTraceWithSp(context); + PRINTK("********backtrace end********\n"); + return; +} + +STATIC VOID OsMutexPendTaskList(LOS_DL_LIST *list) //ڴӡȴбϢ// +{ + LOS_DL_LIST *listTmp = NULL; + LosTaskCB *pendedTask = NULL; + CHAR *name = NULL; + UINT32 index = 0; + UINT32 id, intSave; + + SCHEDULER_LOCK(intSave); + if (LOS_ListEmpty(list) == TRUE) { + SCHEDULER_UNLOCK(intSave); + PRINTK("Pended Task: null\n"); + return; + } + + LOS_DL_LIST_FOR_EACH(listTmp, list) { + pendedTask = OS_TCB_FROM_PENDLIST(listTmp); + name = pendedTask->taskName; + id = pendedTask->taskId; + SCHEDULER_UNLOCK(intSave); + if (index == 0) { + PRINTK("Pended task: %u. name:%-15s, id:0x%-5x\n", index, name, id); + } else { + PRINTK(" %u. name:%-15s, id:0x%-5x\n", index, name, id); + } + index++; + SCHEDULER_LOCK(intSave); + } + SCHEDULER_UNLOCK(intSave); +} + +STATIC VOID OsTaskHoldMutexList(MuxDLinkCB *muxDLCB) //ڴӡеĻϢ// +{ + UINT32 index = 0; + MuxDLinkNode *muxDLNode = NULL; + CHAR *ownerName = NULL; + LosMuxCB *muxCB = NULL; + LOS_DL_LIST *list = NULL; + LOS_DL_LIST *listTmp = NULL; + UINT32 count, intSave; + + SCHEDULER_LOCK(intSave); + if (LOS_ListEmpty(&muxDLCB->muxListHead) == TRUE) { + SCHEDULER_UNLOCK(intSave); + PRINTK("null\n"); + } else { + LOS_DL_LIST_FOR_EACH(list, &muxDLCB->muxListHead) { + muxDLNode = LOS_DL_LIST_ENTRY(list, MuxDLinkNode, muxList); + muxCB = (LosMuxCB *)muxDLNode->muxCB; + count = muxCB->muxCount; + ownerName = muxCB->owner->taskName; + SCHEDULER_UNLOCK(intSave); + PRINTK("\n", index); + PRINTK("Ptr handle:%p\n", muxCB); + PRINTK("Owner:%s\n", ownerName); + PRINTK("Count:%u\n", count); + + listTmp = &muxCB->muxList; + OsMutexPendTaskList(listTmp); + + index++; + SCHEDULER_LOCK(intSave); + } + SCHEDULER_UNLOCK(intSave); + } +} + +VOID OsMutexDlockCheck(VOID) //ڼ⻥Ϣ// +{ + UINT32 loop, intSave; + UINT32 taskId; + CHAR *name = NULL; + LosTaskCB *taskCB = NULL; + MuxDLinkCB *muxDLCB = NULL; + + SCHEDULER_LOCK(intSave); + for (loop = 0; loop < g_taskMaxNum; loop++) { + taskCB = (LosTaskCB *)g_taskCBArray + loop; + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + continue; + } + + muxDLCB = &g_muxDeadlockCBArray[taskCB->taskId]; + if ((LOS_TickCountGet() - muxDLCB->lastAccessTime) > OS_MUX_DEADLOCK_CHECK_THRESHOLD) { + name = taskCB->taskName; + taskId = taskCB->taskId; + SCHEDULER_UNLOCK(intSave); + PRINTK("Task_name:%s, ID:0x%x, holds the Mutexs below:\n", name, taskId); + OsTaskHoldMutexList(muxDLCB); + OsDeadlockBackTrace(taskCB); + PRINTK("\n"); + SCHEDULER_LOCK(intSave); + } + } + SCHEDULER_UNLOCK(intSave); +} + +#ifdef LOSCFG_SHELL //ִл鲢Ϣ// +UINT32 OsShellCmdMuxDeadlockCheck(UINT32 argc, const CHAR **argv) +{ + if (argc > 0) { + PRINTK("\nUsage: dlock\n"); + return OS_ERROR; + } + PRINTK("Start mutexs deadlock check: \n"); + OsMutexDlockCheck(); + PRINTK("-----------End-----------\n"); + return LOS_OK; +} +SHELLCMD_ENTRY(deadlock_shellcmd, CMD_TYPE_EX, "dlock", 0, (CmdCallBackFunc)OsShellCmdMuxDeadlockCheck); +#endif /* LOSCFG_SHELL */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ diff --git a/debug/los_mux_debug.c b/debug/los_mux_debug.c new file mode 100644 index 0000000..5008bc5 --- /dev/null +++ b/debug/los_mux_debug.c @@ -0,0 +1,189 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved. + * Description: Mutex Debug + * 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_mux_debug_pri.h" +#include "los_typedef.h" +#include "los_task.h" +#include "los_misc_pri.h" +#include "arch/exception.h" +#ifdef LOSCFG_SHELL +#include "shcmd.h" +#endif /* LOSCFG_SHELL */ + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +#ifdef LOSCFG_DEBUG_MUTEX //ڱʾĵϢ// +typedef struct { + TSK_ENTRY_FUNC creator; /* The task entry who created this mutex */ + UINT64 lastAccessTime; /* The last access time */ +} MuxDebugCB; +STATIC MuxDebugCB *g_muxDebugArray = NULL; + +//ڱȽϢʱ// +STATIC BOOL MuxCompareValue(const SortParam *sortParam, UINT32 left, UINT32 right) +{ + return (*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, left)) > + *((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, right))); +} + +UINT32 OsMuxDbgInit(VOID) //ڳʼϢ// +{ + UINT32 size = LOSCFG_BASE_IPC_MUX_LIMIT * sizeof(MuxDebugCB); + /* system resident memory, don't free */ + g_muxDebugArray = (MuxDebugCB *)LOS_MemAlloc(m_aucSysMem1, size); + if (g_muxDebugArray == NULL) { + PRINT_ERR("%s: malloc failed!\n", __FUNCTION__); + return LOS_NOK; + } + (VOID)memset_s(g_muxDebugArray, size, 0, size); + return LOS_OK; +} + +VOID OsMuxDbgTimeUpdate(UINT32 muxId) //ڸָʱ// +{ + MuxDebugCB *muxDebug = &g_muxDebugArray[GET_MUX_INDEX(muxId)]; + muxDebug->lastAccessTime = LOS_TickCountGet(); +} + +VOID OsMuxDbgUpdate(UINT32 muxId, TSK_ENTRY_FUNC creator) //ڸָĴߺʱ// +{ + MuxDebugCB *muxDebug = &g_muxDebugArray[GET_MUX_INDEX(muxId)]; + muxDebug->creator = creator; + muxDebug->lastAccessTime = LOS_TickCountGet(); +} + +//ڶԻ򣬲ܴڵĻй©// +STATIC VOID SortMuxIndexArray(UINT32 *indexArray, UINT32 count) +{ + LosMuxCB muxNode = {{0, 0}, 0, 0, 0, 0}; + MuxDebugCB muxDebugNode = {0}; + UINT32 index, intSave; + SortParam muxSortParam; + muxSortParam.buf = (CHAR *)g_muxDebugArray; + muxSortParam.ctrlBlockSize = sizeof(MuxDebugCB); + muxSortParam.ctrlBlockCnt = LOSCFG_BASE_IPC_MUX_LIMIT; + muxSortParam.sortElemOff = LOS_OFF_SET_OF(MuxDebugCB, lastAccessTime); + + if (count > 0) { + SCHEDULER_LOCK(intSave); + OsArraySort(indexArray, 0, count - 1, &muxSortParam, MuxCompareValue); + SCHEDULER_UNLOCK(intSave); + for (index = 0; index < count; index++) { + SCHEDULER_LOCK(intSave); + (VOID)memcpy_s(&muxNode, sizeof(LosMuxCB), + GET_MUX(indexArray[index]), sizeof(LosMuxCB)); + (VOID)memcpy_s(&muxDebugNode, sizeof(MuxDebugCB), + &g_muxDebugArray[indexArray[index]], sizeof(MuxDebugCB)); + SCHEDULER_UNLOCK(intSave); + /* + * muxStat may be altered after the g_taskSpin is unlocked in OsMutexCheck. + * We should recheck the muxStat before the print. + */ + if ((muxNode.muxStat != LOS_USED) || + ((muxNode.muxStat == LOS_USED) && ((muxDebugNode.creator == NULL) || (muxNode.owner == NULL)))) { + continue; + } + PRINTK("Mutex ID <0x%x> may leak, TaskID of owner:0x%x, TaskEntry of owner: %p," + "TaskEntry of creator: %p,Latest operation time: 0x%llx\n", + muxNode.muxId, muxNode.owner->taskId, muxNode.owner->taskEntry, muxDebugNode.creator, + muxDebugNode.lastAccessTime); + } + } + (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, indexArray); +} + +VOID OsMutexCheck(VOID) //ڼ黥״̬ԿܴڵĻй©д// +{ + LosMuxCB muxNode = {{0, 0}, 0, 0, 0, 0}; + MuxDebugCB muxDebugNode = {0}; + UINT32 index, intSave; + UINT32 count = 0; + + /* + * This return value does not need to be judged immediately, + * and the following code logic has already distinguished the return value from null and non-empty, + * and there is no case of accessing the null pointer. + */ + UINT32 *indexArray = (UINT32 *)LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, LOSCFG_BASE_IPC_MUX_LIMIT * sizeof(UINT32)); + + for (index = 0; index < LOSCFG_BASE_IPC_MUX_LIMIT; index++) { + SCHEDULER_LOCK(intSave); + (VOID)memcpy_s(&muxNode, sizeof(LosMuxCB), GET_MUX(index), sizeof(LosMuxCB)); + (VOID)memcpy_s(&muxDebugNode, sizeof(MuxDebugCB), &g_muxDebugArray[index], sizeof(MuxDebugCB)); + SCHEDULER_UNLOCK(intSave); + + if ((muxNode.muxStat != LOS_USED) || + ((muxNode.muxStat == LOS_USED) && (muxDebugNode.creator == NULL))) { + continue; + } else if ((muxNode.muxStat == LOS_USED) && (muxNode.owner == NULL)) { + PRINTK("Mutex ID <0x%x> may leak, Owner is null, TaskEntry of creator: %p," + "Latest operation time: 0x%llx\n", + muxNode.muxId, muxDebugNode.creator, muxDebugNode.lastAccessTime); + } else { + if (indexArray != NULL) { + *(indexArray + count) = index; + count++; + } else { + PRINTK("Mutex ID <0x%x> may leak, TaskID of owner:0x%x, TaskEntry of owner: %p," + "TaskEntry of creator: %p,Latest operation time: 0x%llx\n", + muxNode.muxId, muxNode.owner->taskId, muxNode.owner->taskEntry, muxDebugNode.creator, + muxDebugNode.lastAccessTime); + } + } + } + + if (indexArray != NULL) { + SortMuxIndexArray(indexArray, count); + } +} + +#ifdef LOSCFG_SHELL +//ڻȡϢ// +LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdMuxInfoGet(UINT32 argc, const CHAR **argv) +{ + if (argc > 0) { + PRINTK("\nUsage: mutex\n"); + return OS_ERROR; + } + PRINTK("used mutexs information: \n"); + OsMutexCheck(); + return LOS_OK; +} +SHELLCMD_ENTRY(mutex_shellcmd, CMD_TYPE_EX, "mutex", 0, (CmdCallBackFunc)OsShellCmdMuxInfoGet); +#endif /* LOSCFG_SHELL */ +#endif /* LOSCFG_DEBUG_MUTEX */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ diff --git a/debug/los_queue_debug.c b/debug/los_queue_debug.c new file mode 100644 index 0000000..43ba6ad --- /dev/null +++ b/debug/los_queue_debug.c @@ -0,0 +1,206 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved. + * Description: Queue Debug + * 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_queue_debug_pri.h" +#include "los_misc_pri.h" +#ifdef LOSCFG_SHELL +#include "shcmd.h" +#endif /* LOSCFG_SHELL */ + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +#ifdef LOSCFG_DEBUG_QUEUE //ڱеĵϢ// +typedef struct { + TSK_ENTRY_FUNC creator; /* The task entry who created this queue */ + UINT64 lastAccessTime; /* The last access time */ +} QueueDebugCB; +STATIC QueueDebugCB *g_queueDebugArray = NULL; + +//ڱȽ϶еԪֵ// +STATIC BOOL QueueCompareValue(const SortParam *sortParam, UINT32 left, UINT32 right) +{ + return (*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, left)) > + *((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, right))); +} + +UINT32 OsQueueDbgInit(VOID) //ڳʼеĵϢ// +{ + UINT32 size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(QueueDebugCB); + + /* system resident memory, don't free */ + g_queueDebugArray = (QueueDebugCB *)LOS_MemAlloc(m_aucSysMem1, size); + if (g_queueDebugArray == NULL) { + PRINT_ERR("%s: malloc failed!\n", __FUNCTION__); + return LOS_NOK; + } + (VOID)memset_s(g_queueDebugArray, size, 0, size); + return LOS_OK; +} + +VOID OsQueueDbgTimeUpdate(UINT32 queueId) //ڸ¶еʱ// +{ + QueueDebugCB *queueDebug = &g_queueDebugArray[GET_QUEUE_INDEX(queueId)]; + queueDebug->lastAccessTime = LOS_TickCountGet(); + return; +} + +VOID OsQueueDbgUpdate(UINT32 queueId, TSK_ENTRY_FUNC entry) //ڸ¶еĵϢ// +{ + QueueDebugCB *queueDebug = &g_queueDebugArray[GET_QUEUE_INDEX(queueId)]; + queueDebug->creator = entry; + queueDebug->lastAccessTime = LOS_TickCountGet(); + return; +} + +STATIC INLINE VOID OsQueueInfoOutPut(const LosQueueCB *node) //еϢ// +{ + PRINTK("Queue ID <0x%x> may leak, queue len is 0x%x, " + "readable cnt:0x%x, writeable cnt:0x%x, ", + node->queueId, + node->queueLen, + node->readWriteableCnt[OS_QUEUE_READ], + node->readWriteableCnt[OS_QUEUE_WRITE]); +} + +STATIC INLINE VOID OsQueueOpsOutput(const QueueDebugCB *node) //вϢ// +{ + PRINTK("TaskEntry of creator:0x%p, Latest operation time: 0x%llx\n", + node->creator, node->lastAccessTime); +} + +STATIC VOID SortQueueIndexArray(UINT32 *indexArray, UINT32 count) //ڶԶӦĶϢ// +{ + LosQueueCB queueNode = {0}; + QueueDebugCB queueDebugNode = {0}; + UINT32 index, intSave; + SortParam queueSortParam; + queueSortParam.buf = (CHAR *)g_queueDebugArray; + queueSortParam.ctrlBlockSize = sizeof(QueueDebugCB); + queueSortParam.ctrlBlockCnt = LOSCFG_BASE_IPC_QUEUE_LIMIT; + queueSortParam.sortElemOff = LOS_OFF_SET_OF(QueueDebugCB, lastAccessTime); + + if (count > 0) { + SCHEDULER_LOCK(intSave); + OsArraySort(indexArray, 0, count - 1, &queueSortParam, QueueCompareValue); + SCHEDULER_UNLOCK(intSave); + for (index = 0; index < count; index++) { + SCHEDULER_LOCK(intSave); + (VOID)memcpy_s(&queueNode, sizeof(LosQueueCB), + GET_QUEUE_HANDLE(indexArray[index]), sizeof(LosQueueCB)); + (VOID)memcpy_s(&queueDebugNode, sizeof(QueueDebugCB), + &g_queueDebugArray[indexArray[index]], sizeof(QueueDebugCB)); + SCHEDULER_UNLOCK(intSave); + if (queueNode.queueState == LOS_UNUSED) { + continue; + } + OsQueueInfoOutPut(&queueNode); + OsQueueOpsOutput(&queueDebugNode); + } + } + (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, indexArray); +} + +VOID OsQueueCheck(VOID) //ڼе״̬ӦϢ// +{ + LosQueueCB queueNode = {0}; + QueueDebugCB queueDebugNode = {0}; + UINT32 index, intSave; + UINT32 count = 0; + + /* + * This return value does not need to be judged immediately, + * and the following code logic has already distinguished the return value from null and non-empty, + * and there is no case of accessing the null pointer. + */ + UINT32 *indexArray = (UINT32 *)LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(UINT32)); + + for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) { + SCHEDULER_LOCK(intSave); + (VOID)memcpy_s(&queueNode, sizeof(LosQueueCB), + GET_QUEUE_HANDLE(index), sizeof(LosQueueCB)); + (VOID)memcpy_s(&queueDebugNode, sizeof(QueueDebugCB), + &g_queueDebugArray[index], sizeof(QueueDebugCB)); + SCHEDULER_UNLOCK(intSave); + if ((queueNode.queueState == LOS_UNUSED) || + ((queueNode.queueState == LOS_USED) && (queueDebugNode.creator == NULL))) { + continue; + } + if ((queueNode.queueState == LOS_USED) && + (queueNode.queueLen == queueNode.readWriteableCnt[OS_QUEUE_WRITE]) && + LOS_ListEmpty(&queueNode.readWriteList[OS_QUEUE_READ]) && + LOS_ListEmpty(&queueNode.readWriteList[OS_QUEUE_WRITE]) && + LOS_ListEmpty(&queueNode.memList)) { + PRINTK("Queue ID <0x%x> may leak, No task uses it, " + "QueueLen is 0x%x, ", + queueNode.queueId, + queueNode.queueLen); + OsQueueOpsOutput(&queueDebugNode); + } else { + if (indexArray != NULL) { + *(indexArray + count) = index; + count++; + } else { + OsQueueInfoOutPut(&queueNode); + OsQueueOpsOutput(&queueDebugNode); + } + } + } + + if (indexArray != NULL) { + SortQueueIndexArray(indexArray, count); + } + + return; +} + +#ifdef LOSCFG_SHELL +//û "queue" ʱʹöеϢ// +LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdQueueInfoGet(UINT32 argc, const CHAR **argv) +{ + if (argc > 0) { + PRINTK("\nUsage: queue\n"); + return OS_ERROR; + } + PRINTK("used queues information: \n"); + OsQueueCheck(); + return LOS_OK; +} + +SHELLCMD_ENTRY(queue_shellcmd, CMD_TYPE_EX, "queue", 0, (CmdCallBackFunc)OsShellCmdQueueInfoGet); +#endif /* LOSCFG_SHELL */ +#endif /* LOSCFG_DEBUG_QUEUE */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ diff --git a/debug/los_sched_debug.c b/debug/los_sched_debug.c new file mode 100644 index 0000000..ec4a78b --- /dev/null +++ b/debug/los_sched_debug.c @@ -0,0 +1,347 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved. + * Description: Schedule Statistics + * Author: Huawei LiteOS Team + * Create: 2018-11-16 + * 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_task_pri.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#ifdef LOSCFG_DEBUG_SCHED_STATISTICS +#define HIGHTASKPRI 16 +#define NS_PER_MS 1000000 +#define DECIMAL_TO_PERCENTAGE 100 + +typedef struct { + UINT64 idleRuntime; //ʱ// + UINT64 idleStarttime; //ʱ// + UINT64 highTaskRuntime; //ȼʱ// + UINT64 highTaskStarttime; //ȼʱ// + UINT64 sumPriority; //ȼ֮// + UINT32 prioritySwitch; //л// + UINT32 highTaskSwitch; //ȼл// + UINT32 contexSwitch; //л// + UINT32 hwiNum; //Ӳжϴ// +#ifdef LOSCFG_KERNEL_SMP + UINT32 ipiIrqNum; //жϴڶ¶壩// +#endif +} StatPercpu; + +STATIC BOOL g_statisticsStartFlag = FALSE; +STATIC UINT64 g_statisticsStartTime; +STATIC StatPercpu g_statPercpu[LOSCFG_KERNEL_CORE_NUM]; + +//ÿ CPU Ͻеͳ// +STATIC VOID OsSchedStatisticsPerCpu(const LosTaskCB *runTask, const LosTaskCB *newTask) +{ + UINT32 cpuId; + UINT32 idleTaskId; + UINT64 now, runtime; + + if (g_statisticsStartFlag != TRUE) { + return; + } + + cpuId = ArchCurrCpuid(); + idleTaskId = OsGetIdleTaskId(); + now = LOS_CurrNanosec(); + + g_statPercpu[cpuId].contexSwitch++; + + if ((runTask->taskId != idleTaskId) && (newTask->taskId == idleTaskId)) { + g_statPercpu[cpuId].idleStarttime = now; + } + + if ((runTask->taskId == idleTaskId) && (newTask->taskId != idleTaskId)) { + runtime = now - g_statPercpu[cpuId].idleStarttime; + g_statPercpu[cpuId].idleRuntime += runtime; + g_statPercpu[cpuId].idleStarttime = 0; + } + + if ((runTask->priority >= HIGHTASKPRI) && (newTask->priority < HIGHTASKPRI)) { + g_statPercpu[cpuId].highTaskStarttime = now; + } + + if ((runTask->priority < HIGHTASKPRI) && (newTask->priority >= HIGHTASKPRI)) { + runtime = now - g_statPercpu[cpuId].highTaskStarttime; + g_statPercpu[cpuId].highTaskRuntime += runtime; + g_statPercpu[cpuId].highTaskStarttime = 0; + } + + if (newTask->priority < HIGHTASKPRI) { + g_statPercpu[cpuId].highTaskSwitch++; + } + + if (newTask->taskId != idleTaskId) { + g_statPercpu[cpuId].sumPriority += newTask->priority; + g_statPercpu[cpuId].prioritySwitch++; + } + + return; +} + +//ڸµͳϢ// +LITE_OS_SEC_TEXT_MINOR VOID OsSchedStatistics(LosTaskCB *runTask, LosTaskCB *newTask) +{ + UINT64 runtime; + UINT32 cpuId = ArchCurrCpuid(); + UINT64 now = LOS_CurrNanosec(); + + SchedStat *schedRun = &runTask->schedStat; + SchedStat *schedNew = &newTask->schedStat; + SchedPercpu *cpuRun = &schedRun->schedPercpu[cpuId]; + SchedPercpu *cpuNew = &schedNew->schedPercpu[cpuId]; + + /* calculate one chance of running time */ + runtime = now - schedRun->startRuntime; + + /* add running timer to running task statistics */ + cpuRun->runtime += runtime; + schedRun->allRuntime += runtime; + + /* add context switch counters and schedule start time */ + cpuNew->contexSwitch++; + schedNew->allContextSwitch++; + schedNew->startRuntime = now; + OsSchedStatisticsPerCpu(runTask, newTask); +} + +LITE_OS_SEC_TEXT_MINOR VOID OsHwiStatistics(size_t intNum) //ڸӲжϵͳϢ// +{ + UINT32 cpuId = ArchCurrCpuid(); + + if ((g_statisticsStartFlag != TRUE) || (intNum == OS_TICK_INT_NUM)) { + return; + } + + g_statPercpu[cpuId].hwiNum++; +#ifdef LOSCFG_KERNEL_SMP + /* 16: 0~15 is ipi interrupts */ + if (intNum < 16) { + g_statPercpu[cpuId].ipiIrqNum++; + } +#endif + return; +} + +LITE_OS_SEC_TEXT_MINOR VOID OsShellCmdDumpSched(VOID) //ڴӡĵͳϢ// +{ + LosTaskCB *taskCB = NULL; + UINT32 loop; + UINT32 cpuId; +#ifdef LOSCFG_KERNEL_SMP + UINT32 affinity; +#endif + + PRINTK("\n"); + PRINTK("Task TID Total Time Total CST " + "CPU Time CST\n"); + PRINTK("---- --- ------------------ ---------- -" + "--- ------------------ ----------\n"); + + for (loop = 0; loop < g_taskMaxNum; loop++) { + taskCB = (((LosTaskCB *)g_taskCBArray) + loop); + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { + continue; + } +#ifdef LOSCFG_KERNEL_SMP + affinity = (UINT32)taskCB->cpuAffiMask; +#endif + PRINTK("%-30s0x%-6x%+16lf ms %10u\n", taskCB->taskName, taskCB->taskId, + (DOUBLE)(taskCB->schedStat.allRuntime) / NS_PER_MS, + taskCB->schedStat.allContextSwitch); + + for (cpuId = 0; cpuId < LOSCFG_KERNEL_CORE_NUM; cpuId++) { +#ifdef LOSCFG_KERNEL_SMP + if (!((1U << cpuId) & affinity)) { + continue; + } +#endif + PRINTK(" " + "CPU%u %+16lf ms %12u\n", cpuId, + (DOUBLE)(taskCB->schedStat.schedPercpu[cpuId].runtime) / NS_PER_MS, + taskCB->schedStat.schedPercpu[cpuId].contexSwitch); + } + } + + PRINTK("\n"); +} + +LITE_OS_SEC_TEXT_MINOR VOID OsStatisticsShow(UINT64 statisticsPastTime) //ʾϵͳͳϢ// +{ + UINT32 cpuId; + PRINTK("\n"); + PRINTK("Passed Time: %+16lf ms\n", ((DOUBLE)statisticsPastTime / NS_PER_MS)); + PRINTK("--------------------------------\n"); + PRINTK("CPU Idle(%%) ContexSwitch HwiNum " + "Avg Pri HiTask(%%) HiTask SwiNum HiTask P(ms)" +#ifdef LOSCFG_KERNEL_SMP + " MP Hwi\n"); +#else + "\n"); +#endif + PRINTK("---- --------- ----------- -------- --------- " + "---------- ------------ ----------" +#ifdef LOSCFG_KERNEL_SMP + " ------\n"); +#else + "\n"); +#endif + + for (cpuId = 0; cpuId < LOSCFG_KERNEL_CORE_NUM; cpuId++) { +#ifdef LOSCFG_KERNEL_SMP + PRINTK("CPU%u %+10lf%14u%14u %+11lf %+11lf%14u %+11lf %11u\n", cpuId, +#else + PRINTK("CPU%u %+10lf%14u%14u %+11lf %+11lf%14u %+11lf\n", cpuId, +#endif + ((DOUBLE)(g_statPercpu[cpuId].idleRuntime) / statisticsPastTime) * DECIMAL_TO_PERCENTAGE, + g_statPercpu[cpuId].contexSwitch, + g_statPercpu[cpuId].hwiNum, + (g_statPercpu[cpuId].prioritySwitch == 0) ? OS_TASK_PRIORITY_LOWEST : + ((DOUBLE)(g_statPercpu[cpuId].sumPriority) / (g_statPercpu[cpuId].prioritySwitch)), + ((DOUBLE)(g_statPercpu[cpuId].highTaskRuntime) / statisticsPastTime) * DECIMAL_TO_PERCENTAGE, + g_statPercpu[cpuId].highTaskSwitch, + (g_statPercpu[cpuId].highTaskSwitch == 0) ? 0 : + ((DOUBLE)(g_statPercpu[cpuId].highTaskRuntime) / (g_statPercpu[cpuId].highTaskSwitch)) / NS_PER_MS +#ifdef LOSCFG_KERNEL_SMP + , g_statPercpu[cpuId].ipiIrqNum); +#else + ); +#endif + } + + PRINTK("\n"); +} + +LITE_OS_SEC_TEXT_MINOR VOID OsShellStatisticsStart(VOID) //ڶϵͳͳƹ// +{ + LosTaskCB *taskCB = NULL; + UINT32 loop; + UINT32 cpuId = 0; + UINT32 intSave; + + SCHEDULER_LOCK(intSave); + + if (g_statisticsStartFlag) { + SCHEDULER_UNLOCK(intSave); + PRINT_WARN("mp static has started\n"); + return; + } + + g_statisticsStartTime = LOS_CurrNanosec(); + + for (loop = 0; loop < g_taskMaxNum; loop++) { + taskCB = (((LosTaskCB *)g_taskCBArray) + loop); + if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) { +#ifdef LOSCFG_KERNEL_SMP + cpuId = taskCB->currCpu; +#endif + if ((UINT32)(OS_TASK_INVALID_CPUID) == cpuId) { + continue; + } + if (!strcmp(taskCB->taskName, "IdleCore000")) { + g_statPercpu[cpuId].idleStarttime = g_statisticsStartTime; + } + if (taskCB->priority < HIGHTASKPRI) { + g_statPercpu[cpuId].highTaskStarttime = g_statisticsStartTime; + g_statPercpu[cpuId].highTaskSwitch++; + } + if (strcmp(taskCB->taskName, "IdleCore000")) { + g_statPercpu[cpuId].sumPriority += taskCB->priority; + g_statPercpu[cpuId].prioritySwitch++; + } + } + } + g_statisticsStartFlag = TRUE; + SCHEDULER_UNLOCK(intSave); + + PRINTK("mp static start\n"); + + return; +} + +//ڶϵͳֹͣͳƹܣͳݵĴչʾ// +LITE_OS_SEC_TEXT_MINOR VOID OsShellStatisticsStop(VOID) +{ + LosTaskCB *taskCB = NULL; + UINT32 loop; + UINT32 cpuId = 0; + UINT64 statisticsStopTime; + UINT64 statisticsPastTime; + UINT64 runtime; + UINT32 intSave; + + SCHEDULER_LOCK(intSave); + + if (g_statisticsStartFlag != TRUE) { + SCHEDULER_UNLOCK(intSave); + PRINT_WARN("Please set mp static start\n"); + return; + } + + g_statisticsStartFlag = FALSE; + statisticsStopTime = LOS_CurrNanosec(); + statisticsPastTime = statisticsStopTime - g_statisticsStartTime; + + for (loop = 0; loop < g_taskMaxNum; loop++) { + taskCB = (((LosTaskCB *)g_taskCBArray) + loop); + if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) { +#ifdef LOSCFG_KERNEL_SMP + cpuId = taskCB->currCpu; +#endif + if (cpuId == (UINT32)(OS_TASK_INVALID_CPUID)) { + continue; + } + if (!strcmp(taskCB->taskName, "IdleCore000")) { + runtime = statisticsStopTime - g_statPercpu[cpuId].idleStarttime; + g_statPercpu[cpuId].idleRuntime += runtime; + g_statPercpu[cpuId].idleStarttime = 0; + } + if (taskCB->priority < HIGHTASKPRI) { + runtime = statisticsStopTime - g_statPercpu[cpuId].highTaskStarttime; + g_statPercpu[cpuId].highTaskRuntime += runtime; + g_statPercpu[cpuId].highTaskStarttime = 0; + } + } + } + SCHEDULER_UNLOCK(intSave); + OsStatisticsShow(statisticsPastTime); + + (VOID)memset_s(g_statPercpu, sizeof(g_statPercpu), 0, sizeof(g_statPercpu)); + g_statisticsStartTime = 0; + return; +} +#endif + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ diff --git a/debug/los_sem_debug.c b/debug/los_sem_debug.c new file mode 100644 index 0000000..8f1774b --- /dev/null +++ b/debug/los_sem_debug.c @@ -0,0 +1,299 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved. + * Description: Sem Debug + * 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_sem_debug_pri.h" +#include "stdlib.h" +#include "los_typedef.h" +#include "los_task_pri.h" +#include "los_misc_pri.h" +#ifdef LOSCFG_SHELL +#include "shcmd.h" +#endif /* LOSCFG_SHELL */ + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +#ifdef LOSCFG_DEBUG_SEMAPHORE +#define OS_ALL_SEM_MASK 0xffffffff + +STATIC VOID OsSemPendedTaskNamePrint(LosSemCB *semNode) //ڴӡȴijźб// +{ + LosTaskCB *tskCB = NULL; + CHAR *nameArr[LOSCFG_BASE_CORE_TSK_LIMIT] = {0}; + UINT32 i, intSave; + UINT32 num = 0; + + SCHEDULER_LOCK(intSave); + if ((semNode->semStat == LOS_UNUSED) || (LOS_ListEmpty(&semNode->semList))) { + SCHEDULER_UNLOCK(intSave); + return; + } + + LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &semNode->semList, LosTaskCB, pendList) { + nameArr[num++] = tskCB->taskName; + if (num == LOSCFG_BASE_CORE_TSK_LIMIT) { + break; + } + } + SCHEDULER_UNLOCK(intSave); + + PRINTK("Pended task list : "); + for (i = 0; i < num; i++) { + if (i == 0) { + PRINTK("%s\n", nameArr[i]); + } else { + PRINTK(", %s", nameArr[i]); + } + } + PRINTK("\n"); +} + +typedef struct { //ڼ¼źĵϢ// + UINT16 origSemCount; /* Number of original available semaphores */ + UINT64 lastAccessTime; /* The last operation time */ + TSK_ENTRY_FUNC creator; /* The task entry who created this sem */ +} SemDebugCB; +STATIC SemDebugCB *g_semDebugArray = NULL; //ڴ洢źĵϢ// + +//ڱȽԪصֵ// +STATIC BOOL SemCompareValue(const SortParam *sortParam, UINT32 left, UINT32 right) +{ + return (*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, left)) > + *((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, right))); +} + +UINT32 OsSemDbgInit(VOID) //ڳʼźĵϢ// +{ + UINT32 size = LOSCFG_BASE_IPC_SEM_LIMIT * sizeof(SemDebugCB); + /* system resident memory, don't free */ + g_semDebugArray = (SemDebugCB *)LOS_MemAlloc(m_aucSysMem1, size); + if (g_semDebugArray == NULL) { + PRINT_ERR("%s: malloc failed!\n", __FUNCTION__); + return LOS_NOK; + } + (VOID)memset_s(g_semDebugArray, size, 0, size); + return LOS_OK; +} + +VOID OsSemDbgTimeUpdate(UINT32 semId) //ڸָźһηʱ// +{ + SemDebugCB *semDebug = &g_semDebugArray[GET_SEM_INDEX(semId)]; + semDebug->lastAccessTime = LOS_TickCountGet(); + return; +} + +VOID OsSemDbgUpdate(UINT32 semId, TSK_ENTRY_FUNC creator, UINT16 count) //ڸָźĵϢ// +{ + SemDebugCB *semDebug = &g_semDebugArray[GET_SEM_INDEX(semId)]; + semDebug->creator = creator; + semDebug->lastAccessTime = LOS_TickCountGet(); + semDebug->origSemCount = count; + return; +} + +/*ڰźʱԵǰʹõź*/ +/*ӡÿźĵϢ͵ȴź*/ +STATIC VOID OsSemSort(UINT32 *semIndexArray, UINT32 usedCount) +{ + UINT32 i, intSave; + LosSemCB *semCB = NULL; + LosSemCB semNode = {0}; + SemDebugCB semDebug = {0}; + SortParam semSortParam; + semSortParam.buf = (CHAR *)g_semDebugArray; + semSortParam.ctrlBlockSize = sizeof(SemDebugCB); + semSortParam.ctrlBlockCnt = LOSCFG_BASE_IPC_SEM_LIMIT; + semSortParam.sortElemOff = LOS_OFF_SET_OF(SemDebugCB, lastAccessTime); + + /* It will Print out ALL the Used Semaphore List. */ + PRINTK("Used Semaphore List: \n"); + PRINTK("\r\n SemID Count OriginalCount Creater(TaskEntry) LastAccessTime\n"); + PRINTK(" ------ ------ ------------- ------------------ -------------- \n"); + + SCHEDULER_LOCK(intSave); + OsArraySort(semIndexArray, 0, usedCount - 1, &semSortParam, SemCompareValue); + SCHEDULER_UNLOCK(intSave); + for (i = 0; i < usedCount; i++) { + semCB = GET_SEM(semIndexArray[i]); + SCHEDULER_LOCK(intSave); + (VOID)memcpy_s(&semNode, sizeof(LosSemCB), semCB, sizeof(LosSemCB)); + (VOID)memcpy_s(&semDebug, sizeof(SemDebugCB), &g_semDebugArray[semIndexArray[i]], sizeof(SemDebugCB)); + SCHEDULER_UNLOCK(intSave); + if ((semNode.semStat != LOS_USED) || (semDebug.creator == NULL)) { + continue; + } + PRINTK(" 0x%-07x0x%-07u0x%-14u%-22p0x%llx\n", semNode.semId, semDebug.origSemCount, + semNode.semCount, semDebug.creator, semDebug.lastAccessTime); + if (!LOS_ListEmpty(&semNode.semList)) { + OsSemPendedTaskNamePrint(semCB); + } + } +} +/*ڻȡǰʹõźϢźʱź*/ +UINT32 OsSemInfoGetFullData(VOID) +{ + UINT32 usedSemCnt = 0; + LosSemCB *semNode = NULL; + SemDebugCB *semDebug = NULL; + UINT32 i; + UINT32 *semIndexArray = NULL; + UINT32 count, intSave; + + SCHEDULER_LOCK(intSave); + /* Get the used semaphore count. */ + for (i = 0; i < LOSCFG_BASE_IPC_SEM_LIMIT; i++) { + semNode = GET_SEM(i); + semDebug = &g_semDebugArray[i]; + if ((semNode->semStat == LOS_USED) && (semDebug->creator != NULL)) { + usedSemCnt++; + } + } + SCHEDULER_UNLOCK(intSave); + + if (usedSemCnt > 0) { + semIndexArray = (UINT32 *)LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, usedSemCnt * sizeof(UINT32)); + if (semIndexArray == NULL) { + PRINTK("LOS_MemAlloc failed in %s \n", __func__); + return LOS_NOK; + } + + /* Fill the semIndexArray with the real index. */ + count = 0; + + SCHEDULER_LOCK(intSave); + for (i = 0; i < LOSCFG_BASE_IPC_SEM_LIMIT; i++) { + semNode = GET_SEM(i); + semDebug = &g_semDebugArray[i]; + if ((semNode->semStat != LOS_USED) || (semDebug->creator == NULL)) { + continue; + } + *(semIndexArray + count) = i; + count++; + /* if the count is touched usedSemCnt break. */ + if (count >= usedSemCnt) { + break; + } + } + SCHEDULER_UNLOCK(intSave); + OsSemSort(semIndexArray, count); + + /* free the index array. */ + (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, semIndexArray); + } + return LOS_OK; +} + +#ifdef LOSCFG_SHELL +STATIC UINT32 OsSemInfoOutput(size_t semId) //źϢ// +{ + UINT32 loop, semCnt, intSave; + LosSemCB *semCB = NULL; + LosSemCB semNode = {0}; + + if (semId == OS_ALL_SEM_MASK) { + for (loop = 0, semCnt = 0; loop < LOSCFG_BASE_IPC_SEM_LIMIT; loop++) { + semCB = GET_SEM(loop); + SCHEDULER_LOCK(intSave); + if (semCB->semStat == LOS_USED) { + (VOID)memcpy_s(&semNode, sizeof(LosSemCB), semCB, sizeof(LosSemCB)); + SCHEDULER_UNLOCK(intSave); + semCnt++; + PRINTK("\r\n SemID Count\n ---------- -----\n"); + PRINTK(" 0x%08x %u\n", semNode.semId, semNode.semCount); + continue; + } + SCHEDULER_UNLOCK(intSave); + } + PRINTK(" SemUsingNum : %u\n\n", semCnt); + return LOS_OK; + } else { + semCB = GET_SEM(semId); + SCHEDULER_LOCK(intSave); + (VOID)memcpy_s(&semNode, sizeof(LosSemCB), semCB, sizeof(LosSemCB)); + SCHEDULER_UNLOCK(intSave); + if ((semNode.semId != semId) || (semNode.semStat != LOS_USED)) { + PRINTK("\nThe semaphore is not in use!\n"); + return LOS_OK; + } + + PRINTK("\r\n SemID Count\n ---------- -----\n"); + PRINTK(" 0x%08x 0x%u\n", semNode.semId, semNode.semCount); + + if (LOS_ListEmpty(&semNode.semList)) { + PRINTK("No task is pended on this semaphore!\n"); + return LOS_OK; + } else { + OsSemPendedTaskNamePrint(semCB); + } + } + return LOS_OK; +} + +//ڻȡźϢ// +LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdSemInfoGet(UINT32 argc, const CHAR **argv) +{ + size_t semId; + CHAR *endPtr = NULL; + UINT32 ret; + + if (argc > 1) { + PRINTK("\nUsage: sem [fulldata|ID]\n"); + return OS_ERROR; + } + + if (argc == 0) { + semId = OS_ALL_SEM_MASK; + } else { + if (strcmp(argv[0], "fulldata") == 0) { + ret = OsSemInfoGetFullData(); + return ret; + } + + semId = strtoul(argv[0], &endPtr, 0); + if ((*endPtr != 0) || (GET_SEM_INDEX(semId) >= LOSCFG_BASE_IPC_SEM_LIMIT)) { + PRINTK("\nsem ID can't access %s.\n", argv[0]); + return OS_ERROR; + } + } + + ret = OsSemInfoOutput(semId); + return ret; +} + +SHELLCMD_ENTRY(sem_shellcmd, CMD_TYPE_EX, "sem", 1, (CmdCallBackFunc)OsShellCmdSemInfoGet); +#endif /* LOSCFG_SHELL */ +#endif /* LOSCFG_DEBUG_SEMAPHORE */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ diff --git a/kkk.zip b/kkk.zip deleted file mode 100644 index b5323c3119761ad9240d6743110933dd3af1dad0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53432 zcmYhiL$EMRv#h&p+qP}nwr$(CZ5!{hZQHhO>wI@||2^$dMMpU{4G2Ujov0QnRE0LcHHT3cJw+t@qn+nDH^+L+l`8qrzYX#LqEpJD#(_>WM( z8zOW_2IPaOh8pW9Dbu&Qn+rEtM$PuFJ=C0ao%i;4*Z9L|WLaR>$d13UC`d?!3rl2$ z2q3CLTXor~lBe35T2D2fdG2++U#|~?k(5~~N?&{D+uuF;<=NkrmPdC#UW##q(d!6EgWT6Q^h z#!!yz98>I1yansRF+v3jeoO;P$vX;4)t4gn!+4gg(LoJ{^j_!wAFFXx2wZ#ldGGw;J68iqJRNJLiTv82Iz6=De zHy9x!Cqk6$S=cszPjFo(Ie} z;7YgHfU}@a#u1&ipxADKU}e=Ph(M?>GwDci00*QVUj|$$0f62njZ<})JKO-ba2mD1 zI{=a43Yr!}$+WSDpd5pIO~gb&Eh_nBE;nuz*mu^F%SA#K3VMbeDiS!Xe6FW~gE1R7 zkdlIE6f&9s;gK~nX`s)RoPdhrL{JX+0ML#m4UfFn(n3QCEioa2D++Md?&f$UhFQrIC650`wuYlly70?YeIlTBB8=)G4e+mfq zU$Te|1sgy%PjjF5e#)VyCWg?_0J&7F{6s{ijTixNrAp9;F51-W4T^izo229R?~E-m7hrjmRP(t=+;9zbCPpI^q;VQ}x8roy#)F4sGu zE^nfQygGUmZ{@;Zg{`OYaD5Kq485R2)H0F?m0w`<2*d$eTJcFUks)XP4JrBt>aka`YUbtDttS-S>HAu=Zm8^{wOklgBk!&je(6Uc4AlaVHO=#303;SnGdj(<#s zEpXo`@5(FvhW>V=CYsg<#fsGf>XsYuns>EWXGQ)p4J&T393Rc~*x) zR#E~b?`IxFk6@4nAglyzEJY6X|JCK<@Ao^3o?d5fXHVP5&-!w*{E_Ky7t`0);%n|@ z`e^p@FbaNkMtziMoquPuJSCDZ=cC*cQj(mnw^JKaoNyVwzdI7%#`p5m?PmDv=;~+P zQ3e%4c(AwycyuGqz9%HBY%lN6^fvc0cPjWa$h|Ta4X;j>{bFxRBp(gJa$;DN5NTX1RvOVzcrQj0QF^iUe~=1 z{8vxU`)z3ekduqXC-MFfn(=K)&1wPHEEp)-?Fesc29pHK`gC#>2v~vBV`4$POo8E5 z+vSmSQw#yiYf}lp%X^p6uoJ|#W>|d=7%Sv#!F=q-`~|! zd+UCkSrRC(yG7+JB~jmOsKnt~(x!fU!;5rxbCNjsbY7W~VSog%F^%aE7mhVA)j7D! z6|*mDBFn$2Ww$SKER!crW0<#|sqMc`0JSta{rb6ArtWrX=i3uK+EdZz>-YHkj5K!i z`MfC_HWCxb`BaLTw!dmFqY(?JY6 z3F+Jgm>cIj2No8v0x3972v58+V>RpcMzR2$;gDm(VF;k^dPmWK$vBws8iqo~tPqye z!V(!BMP&y<2n6?Jt_6@D=wCG|{VaqYpFD2)KBibl++XPMDgt-64Xjjdm=d~_BF*qF zVFtL#BB~Qth+GY$<&FW%h4QNcETr%p7T7>RSh43sqkDGZ83Nk$9~X9|b>kak5SbAR zG!_{~lPXUeFwYV)9dgFBq%1=Qe9Yvtm$P%N%t=nwGO( zVLv_KAm8D4ec0rLou$)TQ$c3)-mJT9zp zDEqXmf0hKG%{A1)*p8Z4Kz|*+gO(gqi0Y&^yqTSxum8(cF6=c(-M`)UG4H>;cbliH z+zx906HYV3Sm^2)ds_RQonG#ab~e7AAeQK+bh=vopY!e4wiS5uzMj{&nv(*Bxj(-X zJn9j7oN^PvOBzYuaH5|*<=mO_x~a-m=tpJIhd+V$TlJuU;G4Dmp8Au9r!oGSzxsQ0 z94BogIhsdIj>aE^Gsc)i>S_#9^|G{9I{pB@x7q2?>}U-7)Q8HIOOV!aLSS;Vx<6}7 zv-%eBH`D8R#>r+D!0CgdMv|ziZtgGK~>pC0z8*kiE?tN`9bspxR<^Q zpZx}mlfWKVa${RGpR_HIWu#@|UOrGgk6Y#?G~iNwegqp1H9ImG14|0E<2a$8YkV4~ z=~!v0!HL5?lk;-D6ICxZ1dQ_vj)@sj*bC?K2{*8|OO2nh?ZyH16DHz*1*82z_Vi9$ z@r!DCZqi~^1&GVFuazx@beLWpSeL2mNL%KPY}@V5rQ>iDw2LWPbB!z(yD9voo`RZ3 zYu9KkZ)9ohv&awO#Bq&Q_5tQn{ZD|P$O}wcudy9Fl`2^f>m5z_nh5U{D|0e>Kj{th zTtfl;q;hc4{lMBM`XD&sK6o-`lX)0+5*n@ya&M0gJ&5Ss3tHFeQb9Z*tlwTd_ukU< zJIRah^vZ@bbGH*s4{uw{o}JIr?&>p=y|EgB9_3MRV?q4?-O1up}EnN-QxYGNPmo9JEeJ9$QAc4eqfsjA92 zrN2APcgVlthe*Y2s~9b|f2l?P7ISH}

@ZQcpVKYH!H)3v})qheLTNSptb-U$6D* zSQ#4`37DPK0tyC=t3nlZ&tIe&MGZhW%)9453VH;y_JVP3Au4)Rq@eVmVI9Q>^1fwm zylXe23$Sc`J!-adKOYZs=ehH*^l$1B1L;B3;#|WI=@#+CMM2Mv9C6nl2E{m(^B)OgsNhHXEm)PS}m?uFrmI4cSM2x&Ua=ScU z*W%#^bNsEz4rIa>tg#hIWR>WpF5HdLQd;>`XD*r(c;t$td)b&on4Dj=DPi!k;zD?rs zC+l%iR|%KsD}uKmbdX#Dizr@{C#_8sB&B_w@F8M`B$QW3k&ssgH`WHbajJGulpl!U zBe=d31Ln(!b�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�Xqvz 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 z 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 From 68d83fc343ee762138bfa5ac25809859dd92af90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E8=B1=AA?= <2548632733@qq.com> Date: Sun, 31 Dec 2023 21:58:32 +0800 Subject: [PATCH 4/4] wenhao --- 文豪-用例描述.docx | Bin 0 -> 14105 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 文豪-用例描述.docx diff --git a/文豪-用例描述.docx b/文豪-用例描述.docx new file mode 100644 index 0000000000000000000000000000000000000000..a5be5e412a48256759719611f03b383b2d93be84 GIT binary patch literal 14105 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 literal 0 HcmV?d00001