一、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=yCONFIG_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 日志抓取与分析

  1. 抓取日志
ap> trace start  # 开始记录
ap> 执行目标程序(如hello)
ap> trace dump /data/trace.txt  # 导出日志
  1. 分析:将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;
}

七、函数自动插桩

通过编译选项自动记录函数进出,无需手动插桩。

  1. 原理:
    利用__cyg_profile_func_enter(函数进入)和__cyg_profile_func_exit(函数退出)自动记录,配合-finstrument-functions编译选项生效。
  2. 使用方法:
  • 启用配置: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 和自动插桩功能,能满足不同场景的跟踪需求。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐