OpenHarmony设备开发小型系统内核(LiteOS-A) 调测与工具

zh_ff
发布于 2023-3-27 16:22
浏览
0收藏

版本:V3.2Beta

Trace调测

基本概念

Trace调测旨在帮助开发者获取内核的运行流程,各个模块、任务的执行顺序,从而可以辅助开发者定位一些时序问题或者了解内核的代码运行过程。

运行机制

内核提供一套Hook框架,将Hook点预埋在各个模块的主要流程中, 在内核启动初期完成Trace功能的初始化,并注册Trace的处理函数到Hook中。

当系统触发到一个Hook点时,Trace模块会对输入信息进行封装,添加Trace帧头信息,包含事件类型、运行的cpuid、运行的任务id、运行的相对时间戳等信息;

Trace提供2种工作模式,离线模式和在线模式。

离线模式会将trace frame记录到预先申请好的循环buffer中。如果循环buffer记录的frame过多则可能出现翻转,会覆盖之前的记录,故保持记录的信息始终是最新的信息。Trace循环buffer的数据可以通过shell命令导出进行详细分析,导出信息已按照时间戳信息完成排序。

OpenHarmony设备开发小型系统内核(LiteOS-A) 调测与工具-鸿蒙开发者社区

在线模式需要配合IDE使用,实时将trace frame记录发送给IDE,IDE端进行解析并可视化展示。

接口说明

内核态

LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以查看​​API​​参考。

表1 Trace模块接口说明

功能分类

接口描述

启停控制

LOS_TraceStart:启动Trace

LOS_TraceStop:停止Trace

操作Trace记录的数据

LOS_TraceRecordDump:输出Trace缓冲区数据

LOS_TraceRecordGet:获取Trace缓冲区的首地址

LOS_TraceReset:清除Trace缓冲区中的事件

过滤Trace记录的数据

LOS_TraceEventMaskSet:设置事件掩码,仅记录某些模块的事件

屏蔽某些中断号事件

LOS_TraceHwiFilterHookReg:注册过滤特定中断号事件的钩子函数

插桩函数

LOS_TRACE_EASY:简易插桩

LOS_TRACE:标准插桩

●    当用户需要针对自定义事件进行追踪时,可按规则在目标源代码中进行插桩,系统提供如下2种插桩接口:

●    LOS_TRACE_EASY(TYPE, IDENTITY, params…) 简易插桩。

●    用户在目标源代码中插入该接口即可。

●    TYPE有效取值范围为[0, 0xF],表示不同的事件类型,不同取值表示的含义由用户自定义。

●    IDENTITY类型UINTPTR,表示事件操作的主体对象。

●    Params类型UINTPTR,表示事件的参数。 示例:

假设需要新增对文件(fd1、fd2)读写操作的简易插桩,
自定义读操作为type:1, 写操作为type:2,则
在读fd1文件的适当位置插入:
LOS_TRACE_EASY(1, fd1, flag, size);
在读fd2文件的适当位置插入:
LOS_TRACE_EASY(1, fd2, flag, size);
在写fd1文件的适当位置插入:
LOS_TRACE_EASY(2, fd1, flag, size);
在写fd2文件的适当位置插入:
LOS_TRACE_EASY(2, fd2,flag, size);

●    LOS_TRACE(TYPE, IDENTITY, params…) 标准插桩。

●    相比简易插桩,支持动态过滤事件和参数裁剪,但使用上需要用户按规则来扩展。

●    TYPE用于设置具体的事件类型,可以在头文件los_trace.h中的enum LOS_TRACE_TYPE中自定义事件类型。定义方法和规则可以参考其他事件类型。

●    IDENTITY和Params的类型及含义同简易插桩。 示例:

1.在enum LOS_TRACE_MASK中定义事件掩码,即模块级别的事件类型。
  定义规范为TRACE_#MOD#_FLAG,#MOD#表示模块名。
  例如:
  TRACE_FS_FLAG = 0x4000
2.在enum LOS_TRACE_TYPE中定义具体事件类型。
  定义规范为#TYPE# = TRACE_#MOD#_FLAG | NUMBER,
  例如:
  FS_READ  = TRACE_FS_FLAG | 0; // 读文件
  FS_WRITE = TRACE_FS_FLAG | 1; // 写文件
3.定义事件参数。定义规范为#TYPE#_PARAMS(IDENTITY, parma1...) IDENTITY, ...
  其中的#TYPE#就是上面2中的#TYPE#,
  例如:
  #define FS_READ_PARAMS(fp, fd, flag, size)    fp, fd, flag, size
  宏定义的参数对应于Trace缓冲区中记录的事件参数,用户可对任意参数字段进行裁剪:
  当定义为空时,表示不追踪该类型事件:
  #define FS_READ_PARAMS(fp, fd, flag, size) // 不追踪文件读事件
4.在适当位置插入代码桩。
  定义规范为LOS_TRACE(#TYPE#, #TYPE#_PARAMS(IDENTITY, parma1...))
  LOS_TRACE(FS_READ, fp, fd, flag, size); // 读文件的代码桩,
  #TYPE#之后的入参就是上面3中的FS_READ_PARAMS函数的入参

 

说明:

 预置的Trace事件及参数均可以通过上述方式进行裁剪,参数详见 

​kernel\include\los_trace.h​

●    Trace Mask事件过滤接口LOS_TraceEventMaskSet(UINT32 mask),其入参mask仅高28位生效(对应LOS_TRACE_MASK中某模块的使能位),仅用于模块的过滤,暂不支持针对某个特定事件的细粒度过滤。例如:LOS_TraceEventMaskSet(0x202),则实际设置生效的mask为0x200(TRACE_QUE_FLAG),QUE模块的所有事件均会被采集。一般建议使用的方法为: LOS_TraceEventMaskSet(TRACE_EVENT_FLAG | TRACE_MUX_FLAG | TRACE_SEM_FLAG | TRACE_QUE_FLAG);

●    如果仅需要使能简易插桩事件,通过设置Trace Mask为TRACE_MAX_FLAG即可。

●    Trace缓冲区有限,事件写满之后会覆盖写,用户可通过LOS_TraceRecordDump中打印的CurEvtIndex识别最新记录。

●    Trace的典型操作流程为:LOS_TraceStart、 LOS_TraceStop、 LOS_TraceRecordDump.

●    针对中断事件的Trace, 提供中断号过滤,用于解决某些场景下特定中断号频繁触发导致其他事件被覆盖的情况,用户可自定义中断过滤的规则, 示例如下:

BOOL Example_HwiNumFilter(UINT32 hwiNum)
{
    if ((hwiNum == TIMER_INT) || (hwiNum == DMA_INT)) {
        return TRUE;
    }
    return FALSE;
}
LOS_TraceHwiFilterHookReg(Example_HwiNumFilter);
    c

则当中断号为TIMER_INT 或者DMA_INT时,不记录中断事件。

用户态

新增trace字符设备,位于"/dev/trace",通过对设备节点的read、write、ioctl,实现用户态trace的读写和控制:

  • read: 用户态读取Trace记录数据
  • write: 用户态事件写入
  • ioctl: 用户态Trace控制操作,包括

#define TRACE_IOC_MAGIC   'T'
#define TRACE_START      _IO(TRACE_IOC_MAGIC, 1)
#define TRACE_STOP       _IO(TRACE_IOC_MAGIC, 2)
#define TRACE_RESET      _IO(TRACE_IOC_MAGIC, 3)
#define TRACE_DUMP		 _IO(TRACE_IOC_MAGIC, 4)
#define TRACE_SET_MASK	 _IO(TRACE_IOC_MAGIC, 5)    c

分别对应Trace启动(LOS_TraceStart)、停止(LOS_TraceStop)、清除记录(LOS_TraceReset)、dump记录(LOS_TraceRecordDump)、设置事件过滤掩码(LOS_TraceEventMaskSet)

具体的使用方法参见​​用户态编程实例​​。

开发指导

内核态开发流程

开启Trace调测的典型流程如下:

  1. 配置Trace模块相关宏。 配置Trace控制宏LOSCFG_KERNEL_TRACE,默认关,在 kernel/liteos_a 目录下执行 make update_config 命令配置 “Kernel->Enable Hook Feature->Enable Trace Feature” 中打开:

配置项

menuconfig选项

含义

设置值

LOSCFG_KERNEL_TRACE

Enable Trace Feature

Trace模块的裁剪开关

YES/NO

LOSCFG_RECORDER_MODE_OFFLINE

Trace work mode ->Offline mode

Trace工作模式为离线模式

YES/NO

LOSCFG_RECORDER_MODE_ONLINE

Trace work mode ->Online mode

Trace工作模式为在线模式

YES/NO

LOSCFG_TRACE_CLIENT_INTERACT

Enable Trace Client Visualization and Control

使能与Trace IDE (dev tools)的交互,包括数据可视化和流程控制

YES/NO

LOSCFG_TRACE_FRAME_CORE_MSG

Enable Record more extended content

->Record cpuid, hardware interrupt status, task lock status

记录CPUID、中断状态、锁任务状态

YES/NO

LOSCFG_TRACE_FRAME_EVENT_COUNT

Enable Record more extended content

 ->Record event count,

 which indicate the sequence of happend events

记录事件的次序编号

YES/NO

LOSCFG_TRACE_FRAME_MAX_PARAMS

Record max params

配置记录事件的最大参数个数

INT

LOSCFG_TRACE_BUFFER_SIZE

Trace record buffer size

配置Trace的缓冲区大小

INT

2.(可选)预置事件参数和事件桩(或使用系统默认的事件参数配置和事件桩)。

3.(可选)调用LOS_TraceStop停止Trace后,清除缓冲区LOS_TraceReset(系统默认已启动trace)。

4.(可选)调用LOS_TraceEventMaskSet设置需要追踪的事件掩码(系统默认的事件掩码仅使能中断与任务事件),事件掩码参见​​los_trace.h​​ 中的LOS_TRACE_MASK定义。

5.在需要记录事件的代码起始点调用LOS_TraceStart。

6.在需要记录事件的代码结束点调用LOS_TraceStop。

7.调用LOS_TraceRecordDump输出缓冲区数据(函数的入参为布尔型,FALSE表示格式化输出,TRUE表示输出到Trace IDE)。

上述第3-7步中的接口,均封装有对应的shell命令,开启shell后可执行相应的命令,对应关系如下:

  • LOS_TraceReset —— trace_reset
  • LOS_TraceEventMaskSet —— trace_mask
  • LOS_TraceStart —— trace_start
  • LOS_TraceStop —— trace_stop
  • LOS_TraceRecordDump —— trace_dump
内核态编程实例

本实例实现如下功能:

  1. 创建一个用于Trace测试的任务。
  2. 设置事件掩码。
  3. 启动trace。
  4. 停止trace。
  5. 格式化输出trace数据。
内核态示例代码

该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试。 实例代码如下:

#include "los_trace.h"
UINT32 g_traceTestTaskId;
VOID Example_Trace(VOID)
{
    UINT32 ret;
    LOS_TaskDelay(10);
    /* 开启trace */
    ret = LOS_TraceStart();
    if (ret != LOS_OK) {
        dprintf("trace start error\n");
        return;
    }
    /* 触发任务切换的事件 */
    LOS_TaskDelay(1);
    LOS_TaskDelay(1);
    LOS_TaskDelay(1);
    /* 停止trace */
    LOS_TraceStop();
    LOS_TraceRecordDump(FALSE);
}
UINT32 Example_Trace_test(VOID)
{
    UINT32 ret;
    TSK_INIT_PARAM_S traceTestTask;
    /* 创建用于trace测试的任务 */
    memset(&traceTestTask, 0, sizeof(TSK_INIT_PARAM_S));
    traceTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Trace;
    traceTestTask.pcName       = "TestTraceTsk";    /* 测试任务名称 */
    traceTestTask.uwStackSize  = 0x800; // 0x800: trace test task stacksize
    traceTestTask.usTaskPrio   = 5; // 5: trace test task priority
    traceTestTask.uwResved   = LOS_TASK_STATUS_DETACHED;
    ret = LOS_TaskCreate(&g_traceTestTaskId, &traceTestTask);
    if (ret != LOS_OK) {
        dprintf("TraceTestTask create failed .\n");
        return LOS_NOK;
    }
    /* 系统默认情况下已启动trace, 因此可先关闭trace后清除缓存区后,再重启trace */
    LOS_TraceStop();
    LOS_TraceReset();
    /* 开启任务模块事件记录 */
    LOS_TraceEventMaskSet(TRACE_TASK_FLAG);
    return LOS_OK;
}
LOS_MODULE_INIT(Example_Trace_test, LOS_INIT_LEVEL_KMOD_EXTENDED);
    c
结果验证

输出结果如下:

***TraceInfo begin***
clockFreq = 50000000
CurEvtIndex = 7
Index   Time(cycles)      EventType      CurTask   Identity      params
0       0x366d5e88        0x45           0x1       0x0           0x1f         0x4       0x0
1       0x366d74ae        0x45           0x0       0x1           0x0          0x8       0x1f
2       0x36940da6        0x45           0x1       0xc           0x1f         0x4       0x9
3       0x3694337c        0x45           0xc       0x1           0x9          0x8       0x1f
4       0x36eea56e        0x45           0x1       0xc           0x1f         0x4       0x9
5       0x36eec810        0x45           0xc       0x1           0x9          0x8       0x1f
6       0x3706f804        0x45           0x1       0x0           0x1f         0x4       0x0
7       0x37070e59        0x45           0x0       0x1           0x0          0x8       0x1f
***TraceInfo end***

输出的事件信息包括:发生时间、事件类型、事件发生在哪个任务中、事件操作的主体对象、事件的其他参数。

  • EventType:表示的具体事件可查阅头文件​​los_trace.h​​ 中的enum LOS_TRACE_TYPE。
  • CurrentTask:表示当前运行在哪个任务中,值为taskid。
  • Identity:表示事件操作的主体对象,可查阅头文件​​los_trace.h​​ 中的#TYPE#_PARAMS。
  • params:表示的事件参数可查阅头文件​​los_trace.h​​ 中的#TYPE#_PARAMS。

下面以序号为0的输出项为例,进行说明。

Index   Time(cycles)      EventType      CurTask   Identity      params
0       0x366d5e88        0x45           0x1       0x0           0x1f         0x4
  • Time cycles可换算成时间,换算公式为cycles/clockFreq,单位为s。
  • 0x45为TASK_SWITCH即任务切换事件,当前运行的任务taskid为0x1。
  • Identity和params的含义需要查看TASK_SWITCH_PARAMS宏定义:

#define TASK_SWITCH_PARAMS(taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus) \
taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus    c

因为#TYPE#_PARAMS(IDENTITY, parma1…) IDENTITY, …,所以Identity为taskId(0x0),第一个参数为oldPriority(0x1f)

说明:

 params的个数由LOSCFG_TRACE_FRAME_MAX_PARAMS配置,默认为3,超出的参数不会被记录,用户应自行合理配置该值。

综上所述,任务由0x1切换到0x0,0x1任务的优先级为0x1f,状态为0x4,0x0任务的优先级为0x0。

Perf调测

基本概念

Perf为性能分析工具,依赖PMU(Performance Monitoring Unit)对采样事件进行计数和上下文采集,统计出热点分布(hot spot)和热路径(hot path)。

运行机制

基于事件采样原理,以性能事件为基础,当事件发生时,相应的事件计数器溢出发生中断,在中断处理函数中记录事件信息,包括当前的pc、当前运行的任务ID以及调用栈等信息。

Perf提供2种工作模式,计数模式和采样模式。

计数模式仅统计事件发生的次数和耗时,采样模式会收集上下文数据到环形buffer中,需要IDE进行数据解析生成热点函数与热点路径。

接口说明

OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细信息可以查看​​API​​参考。

表1 Perf模块接口说明

功能分类

接口描述

开启/停止Perf采样

LOS_PerfInit : 初始化Perf

LOS_PerfStart:开启采样

LOS_PerfStop:停止采样

配置Perf采样事件

LOS_PerfConfig:配置采样事件的类型、周期等

读取采样数据

LOS_PerfDataRead:读取采样数据到指定地址

注册采样数据缓冲区的钩子函数

LOS_PerfNotifyHookReg:注册缓冲区水线到达的处理钩子

LOS_PerfFlushHookReg:注册缓冲区刷cache的钩子

  1. Perf采样事件的结构体为PerfConfigAttr,详细字段含义及取值详见​​kernel\include\los_perf.h​​ 。
  2. 采样数据缓冲区为环形buffer,buffer中读过的区域可以覆盖写,未被读过的区域不能被覆盖写。
  3. 缓冲区有限,用户可通过注册水线到达的钩子进行buffer溢出提醒或buffer读操作。默认水线值为buffer总大小的1/2。 示例如下:

VOID Example_PerfNotifyHook(VOID)
{
    CHAR buf[LOSCFG_PERF_BUFFER_SIZE] = {0};
    UINT32 len;
    PRINT_DEBUG("perf buffer reach the waterline!\n");
    len = LOS_PerfDataRead(buf, LOSCFG_PERF_BUFFER_SIZE);
    OsPrintBuff(buf, len); /* print data */
}
LOS_PerfNotifyHookReg(Example_PerfNotifyHook);
    c

4.若perf采样的buffer涉及到CPU跨cache,则用户可通过注册刷cache的钩子,进行cache同步。 示例如下:

VOID Example_PerfFlushHook(VOID *addr, UINT32 size)
{
    OsCacheFlush(addr, size); /* platform interface */
}
LOS_PerfNotifyHookReg(Example_PerfFlushHook);
    c

刷cache接口视具体的平台自行配置。

开发指导

内核态开发流程

开启Perf调测的典型流程如下:

  1. 配置Perf模块相关宏。 配置Perf控制宏LOSCFG_KERNEL_PERF,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel->Enable Perf Feature"中打开:

配置项

menuconfig选项

含义

设置值

LOSCFG_KERNEL_PERF

Enable Perf Feature

Perf模块的裁剪开关

YES/NO

LOSCFG_PERF_CALC_TIME_BY_TICK

Time-consuming Calc Methods->By Tick

Perf计时单位为tick

YES/NO

LOSCFG_PERF_CALC_TIME_BY_CYCLE

Time-consuming Calc Methods->By Cpu Cycle

Perf计时单位为cycle

YES/NO

LOSCFG_PERF_BUFFER_SIZE

Perf Sampling Buffer Size

Perf采样buffer的大小

INT

LOSCFG_PERF_HW_PMU

Enable Hardware Pmu Events for Sampling

使能硬件PMU事件,需要目标平台支持硬件PMU

YES/NO

LOSCFG_PERF_TIMED_PMU

Enable Hrtimer Period Events for Sampling

使能高精度周期事件,需要目标平台支持高精度定时器

YES/NO

LOSCFG_PERF_SW_PMU

Enable Software Events for Sampling

使能软件事件,需要开启LOSCFG_KERNEL_HOOK

YES/NO

2.调用LOS_PerfConfig配置需要采样的事件。 Perf提供2种模式的配置,及3大类型的事件配置:
2种模式:计数模式(仅统计事件发生次数)、采样模式(收集上下文如任务ID、pc、backtrace等)。
3种事件类型:CPU硬件事件(cycle、branch、icache、dcache等)、高精度周期事件(cpu clock)、OS软件事件(task switch、mux pend、irq等)。

3.在需要采样的代码起始点调用LOS_PerfStart(UINT32 sectionId), 入参sectionId标记不同的采样回话id。

4.在需要采样的代码结束点调用LOS_PerfStop。

5.调用输出缓冲区数据的接口LOS_PerfDataRead读取采样数据,并使用IDE工具进行解析。

内核态编程实例

本实例实现如下功能:

  1. 创建perf测试任务。
  2. 配置采样事件。
  3. 启动perf。
  4. 执行需要统计的算法。
  5. 停止perf。
  6. 输出统计结果。
内核态示例代码

前提条件:在menuconfig菜单中完成perf模块的配置, 并勾选Enable Hook Feature,Enable Software Events for Sampling。

为方便学习,本演示代码直接在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证即可。

实例代码如下:

#include "los_perf.h"
#define TEST_MALLOC_SIZE 200
#define TEST_TIME        5

/* 验证函数中进行malloc和free */
VOID test(VOID)
{
    VOID *p = NULL;
    int i;
    for (i = 0; i < TEST_TIME; i++) {
        p = LOS_MemAlloc(m_aucSysMem1, TEST_MALLOC_SIZE);
        if (p == NULL) {
            PRINT_ERR("test alloc failed\n");
            return;
        }

        (VOID)LOS_MemFree(m_aucSysMem1, p);
    }
}

STATIC VOID OsPrintBuff(const CHAR *buf, UINT32 num)
{
    UINT32 i = 0;
    PRINTK("num: ");
    for (i = 0; i < num; i++) {
        PRINTK(" %02d", i);
    }
    PRINTK("\n");
    PRINTK("hex: ");
    for (i = 0; i < num; i++) {
        PRINTK(" %02x", buf[i]);
    }
    PRINTK("\n");
}
STATIC VOID perfTestHwEvent(VOID)
{
    UINT32 ret;
    CHAR *buf = NULL;
    UINT32 len;

    //LOS_PerfInit(NULL, 0);


    PerfConfigAttr attr = {
        .eventsCfg = {
            .type        = PERF_EVENT_TYPE_SW,
            .events = {
                [0]      = {PERF_COUNT_SW_TASK_SWITCH, 0xff}, /* 抓取调度 */
                [1]      = {PERF_COUNT_SW_MEM_ALLOC, 0xff},   /* 抓取内存分配 */

                PERF_COUNT_SW_TASK_SWITCH
            },
            .eventsNr    = 2,
            .predivided  = 1,             /* cycle counter increase every 64 cycles */
        },
        .taskIds         = {0},
        .taskIdsNr       = 0,
        .needSample      = 0,
        .sampleType      = PERF_RECORD_IP | PERF_RECORD_CALLCHAIN,
    };
    ret = LOS_PerfConfig(&attr);
    if (ret != LOS_OK) {
        PRINT_ERR("perf config error %u\n", ret);
        return;
    }
    PRINTK("------count mode------\n");
    LOS_PerfStart(0);
    test(); /* this is any test function*/
    LOS_PerfStop();
    PRINTK("--------sample mode------ \n");
    attr.needSample = 1;
    LOS_PerfConfig(&attr);
    LOS_PerfStart(2); // 2: set the section id to 2.
    test(); /* this is any test function*/
    LOS_PerfStop();
    buf = LOS_MemAlloc(m_aucSysMem1, LOSCFG_PERF_BUFFER_SIZE);
    if (buf == NULL) {
        PRINT_ERR("buffer alloc failed\n");
        return;
    }
    /* get sample data */
    len = LOS_PerfDataRead(buf, LOSCFG_PERF_BUFFER_SIZE);
    OsPrintBuff(buf, len); /* print data */
    (VOID)LOS_MemFree(m_aucSysMem1, buf);
}

UINT32 Example_Perf_test(VOID)
{
    UINT32 ret;
    TSK_INIT_PARAM_S perfTestTask = {0};
    UINT32 taskID;
    /* 创建用于perf测试的任务 */
    perfTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)perfTestHwEvent;
    perfTestTask.pcName       = "TestPerfTsk";    /* 测试任务名称 */
    perfTestTask.uwStackSize  = 0x1000; // 0x8000: perf test task stack size
    perfTestTask.usTaskPrio   = 5; // 5: perf test task priority
    ret = LOS_TaskCreate(&taskID, &perfTestTask);
    if (ret != LOS_OK) {
        PRINT_ERR("PerfTestTask create failed. 0x%x\n", ret);
        return LOS_NOK;
    }
    return LOS_OK;
}
LOS_MODULE_INIT(perfTestHwEvent, LOS_INIT_LEVEL_KMOD_EXTENDED);
    c
内核态结果验证

输出结果如下:

type: 2
events[0]: 1, 0xff
events[1]: 3, 0xff
predivided: 1
sampleType: 0x60
needSample: 0
------count mode------
[task switch] eventType: 0x1 [core 0]: 0
[mem alloc] eventType: 0x3 [core 0]: 5
time used: 0.005000(s)
--------sample mode------
type: 2
events[0]: 1, 0xff
events[1]: 3, 0xff
predivided: 1
sampleType: 0x60
needSample: 1
dump perf data, addr: 0x402c3e6c length: 0x5000
time used: 0.000000(s)
num:  00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
hex:  00 ffffffef ffffffef ffffffef 02 00 00 00 14 00 00 00 60 00 00 00 02 00 00 00

根据实际运行环境,过程打印会有差异
  • 针对计数模式,系统在perf stop后会打印: 事件名称(cycles)、事件类型(0xff)、事件发生的次数(5466989440)。
    当采样事件为硬件PMU事件时,打印的事件类型为实际的硬件事件id,非enum PmuHWId中定义的抽象类型。
  • 针对采样模式,系统在perf stop后会打印采样数据的地址和长度: dump section data, addr: (0x8000000) length: (0x5000)
    用户可以通过JTAG口导出该片内存,再使用IDE线下工具解析。
    或者通过LOS_PerfDataRead将数据读到指定地址,进行查看或进一步处理。示例中OsPrintBuff为测试接口,其按字节打印Read到的采样数据,num表示第几个字节,hex表示该字节中的数值。


文章转载自:​​https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/device-dev/kernel/kernel-small-debug-trace.md/​


分类
收藏
回复
举报
回复
    相关推荐