pull/10/head
commit
579b2ed97e
@ -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("<Mutex%u info>\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 */
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
@ -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) //用于打印等待某个信号量的任务列表//
|
||||
{
|
||||
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 */
|
Binary file not shown.
@ -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_end的CHAR类型变量//
|
||||
|
||||
#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 */
|
@ -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 */
|
@ -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) //用于判断是否需要过滤某个硬件中断//
|
||||
{
|
||||
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(); //CPU的ID//
|
||||
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 */
|
@ -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 */
|
@ -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[] = { //定义结构体的成员变量类型和大小//
|
||||
{ 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[] = { //定义结构体的成员变量类型和大小//
|
||||
{ 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[] = { //定义结构体的成员变量类型、偏移位置和大小//
|
||||
{ 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[] = { //定义结构体的成员变量类型和大小//
|
||||
#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)
|
||||
{ //将len和data参数标记为"未使用"//
|
||||
(VOID)len; //避免编译器产生警告//
|
||||
(VOID)data;
|
||||
}
|
||||
|
||||
STATIC UINT32 DefaultDataReceive(UINT8 *data, UINT32 size, UINT32 timeout)
|
||||
{
|
||||
(VOID)data; //将data、size和timeout参数标记为"未使用"//
|
||||
(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 */
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
Loading…
Reference in new issue