openvela之Trace系统
一、Trace 系统概述
Trace 系统是用于跟踪和记录系统活动的工具,可捕获内核、内核扩展程序及用户程序的关键行为,包括系统调用、内核服务、中断处理等事件,以微秒为单位按时间顺序记录,支持图形化展示分析。
核心原理:通过在系统关键点插桩收集数据(如任务启动时调用sched_note_start,中断函数中调用sched_note_irqhandle)。
支持的事件类型:任务执行 / 终止 / 切换、系统调用进出、中断处理程序进出、应用代码自定义插桩事件等。
二、配置说明
通过/drivers/note/Kconfig配置需要跟踪的事件和通道。
1. Kernel Events 配置
- 总开关:
CONFIG_SCHED_INSTRUMENTATION=y(必须开启)。 - 常用配置项:
SCHED_INSTRUMENTATION_SWITCH:任务调度埋点。SCHED_INSTRUMENTATION_IRQHANDLER:中断处理埋点。SCHED_INSTRUMENTATION_DUMP:用户自定义 trace。SCHED_INSTRUMENTATION_SYSCALL:系统调用埋点。
- 其他可选项:调度锁、临界区、自旋锁等相关配置(按需开启,可能增加数据量)。
2. 自定义 Trace 配置
仅使用 API 添加自定义 Trace 时,需开启以下配置:
CONFIG_SCHED_INSTRUMENTATION=y
CONFIG_SCHED_INSTRUMENTATION_FILTER_DEFAULT_MODE=0x3e
CONFIG_SCHED_INSTRUMENTATION_FILTER=y
CONFIG_SCHED_INSTRUMENTATION_DUMP=y
CONFIG_DRIVERS_NOTE=y
CONFIG_DRIVERS_NOTERAM=y
CONFIG_DRIVERS_NOTECTL=y
CONFIG_SYSTEM_TRACE=y
CONFIG_SYSTEM_TRACE_STACKSIZE=4096
CONFIG_ARCH_PERF_EVENTS=y
CONFIG_PERF_OVERFLOW_CORRECTION=y
# 建议调整Buffer大小(默认2K,如改为2M)
CONFIG_DRIVERS_NOTERAM_BUFSIZE=204800
- 可选配置:指定 Buffer 存储位置(
CONFIG_DRIVERS_NOTERAM_SECTION=".bss.xxx")、增加特定事件跟踪(如任务切换、中断处理)。
3. 打点时间精度配置
三种时钟源方案,推荐第一种:
| 方案 | 配置 | 精度 | 特点 |
|---|---|---|---|
| 硬件 PMU | CONFIG_ARCH_PERF_EVENTS=y+CONFIG_PERF_OVERFLOW_CORRECTION=y | 纳秒级 | 支持时间回滚处理 |
| 硬件定时器 | CONFIG_ARCH_PERF_EVENTS=n | 与 oneshot timer 一致 | 支持时间回滚处理 |
| 系统滴答时钟 | 关闭所有时钟配置(CONFIG_ALARM_ARCH=n等) | 默认 10ms(与CONFIG_USEC_PER_TICK一致) | 精度最低 |
三、Trace 系统原理

- 数据收集:通过插桩 API(如
sched_note_*)在关键点收集系统数据。 - 数据分发:收集的数据分发到不同 Channel,支持后端包括 RAM、Syslog、RTT、SysView、RPMsg。
- 处理流程:插桩 API→数据过滤→Buffer 存储(
/dev/note相关设备)→通过trace命令导出为文本,再用 Perfetto 图形化分析。
四、API 使用说明
1. 内核打点函数
用于内核代码插桩,需配合对应配置项使用:
- 任务相关:
sched_note_start(启动)、sched_note_stop(终止)、sched_note_suspend(挂起)等。
// 任务开始结束,始终开启
void sched_note_start(FAR struct tcb_s *tcb);
void sched_note_stop(FAR struct tcb_s *tcb);
// 任务调度, CONFIG_SCHED_INSTRUMENTATION_SWITCH
void sched_note_suspend(FAR struct tcb_s *tcb);
void sched_note_resume(FAR struct tcb_s *tcb);
// 多核任务调度, CONFIG_SMP && CONFIG_SCHED_INSTRUMENTATION_SWITCH
void sched_note_cpu_start(FAR struct tcb_s *tcb, int cpu);
void sched_note_cpu_started(FAR struct tcb_s *tcb);
void sched_note_cpu_pause(FAR struct tcb_s *tcb, int cpu);
void sched_note_cpu_paused(FAR struct tcb_s *tcb);
void sched_note_cpu_resume(FAR struct tcb_s *tcb, int cpu);
void sched_note_cpu_resumed(FAR struct tcb_s *tcb);
- 锁相关:
sched_note_spinlock(自旋锁)、sched_note_csection(临界区)等。
// 调度锁,CONFIG_SCHED_INSTRUMENTATION_PREEMPTION
void sched_note_premption(FAR struct tcb_s *tcb, bool locked);
// 临界区, CONFIG_SCHED_INSTRUMENTATION_CSECTION
void sched_note_csection(FAR struct tcb_s *tcb, bool enter);
// 自旋锁,CONFIG_SCHED_INSTRUMENTATION_SPINLOCK
void sched_note_spinlock(FAR struct tcb_s *tcb, FAR volatile spinlock_t *spinlock, int type);
- 中断与系统调用:
sched_note_irqhandler(中断处理)、sched_note_syscall_enter(系统调用进入)等。
//中断处理(需启用 CONFIG_SCHED_INSTRUMENTATION_IRQHANDLER
void sched_note_irqhandler(int irq, FAR void *handler, bool enter);
//系统调用(需启用 CONFIG_SCHED_INSTRUMENTATION_SYSCALL)
void sched_note_syscall_enter(int nr, int argc, ...);
void sched_note_syscall_leave(int nr, uintptr_t result);
2. 自定义打点 API
需启用CONFIG_SCHED_INSTRUMENTATION_DUMP,用于应用代码插桩,主要宏包括:
- 事件输出:
sched_note_event(事件信息)、sched_note_printf(格式化输出)等。 - 函数打点:
sched_note_begin/end(单次使用)、sched_note_beginex/endex(多次使用)。 - 标记与计数器:
sched_note_mark(标记事件)、sched_note_counter(计数器)。

Tag 参数:用于指定模块(如NOTE_TAG_ALWAYS(始终输出)、NOTE_TAG_APP(应用)、NOTE_TAG_NET(网络)等)。
3. 自定义 Trace Buffer
用于内核模块私有事件跟踪,步骤:
启用配置:CONFIG_SCHED_INSTRUMENTATION_DUMP=y、CONFIG_DRIVERS_NOTERAM=y等。
注册驱动:通过noteram_initialize创建专用 Buffer(如/dev/note/rpmsg,大小 16K)。
设置过滤器:指定关注的事件类型(如仅NOTE_TAG_RPMSG)。
插桩:在模块中调用自定义打点 API 记录事件。
五、使用示例
1. 应用代码打点示例
#include <nuttx/config.h>
#include <stdio.h>
#include <nuttx/sched_note.h>
int main(int argc, FAR char *argv[])
{
printf("Hello, World!!\n");
sched_note_begin(0);
sleep(5);
sched_note_beginex(0, "=============================");
sleep(5);//task
sched_note_endex(0, "============================");
char *str = "shced note test string";
sched_note_beginex(0, "sleep");
sleep(1);
sched_note_endex(0, "sleep");
sched_note_vprintf(0, "sched note test vprintf", 1);
sched_note_printf(0,"sched note test printf");
int count = 0;
sched_note_printf(NOTE_TAG_ALWAYS,
"sched note test count = %d.", count++);
sched_note_beginex(0, "sched note test beginex");
sched_note_endex(0, "sched note test endex");
sched_note_end(0);
printf("test\n");
return 0;
}
2. Trace 日志抓取与分析
- 抓取日志:
ap> trace start # 开始记录
ap> 执行目标程序(如hello)
ap> trace dump /data/trace.txt # 导出日志
- 分析:将
trace.txt导入 Chrome 浏览器的 Perfetto 工具,查看 CPU 活动、调度等时序图。
六、ATRACE 使用
ATRACE 是性能分析工具,提供宏用于记录事件,支持函数耗时、异步事件等跟踪。
1. 主要宏
ATRACE_BEGIN(name)/ATRACE_END():跟踪上下文开始 / 结束。ATRACE_INSTANT(name):记录瞬时事件。ATRACE_ASYNC_BEGIN/END:跟踪异步事件。ATRACE_CALL():自动以函数名为标识跟踪函数执行。
2. TAG 类型
指定跟踪的模块(如ATRACE_TAG_GRAPHICS(图形)、ATRACE_TAG_APP(应用)、ATRACE_TAG_ALWAYS(始终启用)等)。
3. 使用示例:
#define ATRACE_TAG ATRACE_TAG_ALWAYS
#include <cutils/trace.h>
int main() {
ATRACE_BEGIN("hello_main"); // 开始跟踪
ATRACE_INSTANT("printf"); // 记录瞬时事件
printf("hello");
ATRACE_END(); // 结束跟踪
return 0;
}
七、函数自动插桩
通过编译选项自动记录函数进出,无需手动插桩。
- 原理:
利用__cyg_profile_func_enter(函数进入)和__cyg_profile_func_exit(函数退出)自动记录,配合-finstrument-functions编译选项生效。 - 使用方法:
- 启用配置:
CONFIG_SCHED_INSTRUMENTATION_FUNCTION。 - 模块编译选项:
CFLAGS += -finstrument-functions。 - 排除特定内容:
# 排除函数名含up/mm的函数
CFLAGS += -finstrument-functions-exclude-function-list=up,mm
# 排除路径含arch/board的文件
CFLAGS += -finstrument-functions-exclude-file-list=arch,board
总结
openvela Trace 系统通过灵活的配置、丰富的 API 和工具链,支持系统级和应用级事件跟踪,可用于性能分析和调试。核心包括内核 / 自定义插桩、多精度时间配置、日志抓取与图形化分析,结合 ATRACE 和自动插桩功能,能满足不同场景的跟踪需求。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐

所有评论(0)