用 Zephyr CTF 跟踪查看线程与信号量协作
本文依据 Zephyr 4.4.0 的 Tracing 文档整理,范围包括说明性正文、同版 tracing 示例的各后端用法、双线程程序及读取条件;正文按官方仓库 v4.4.0 文档源文件核对。文末保留生成API参考的全部分组入口,不逐条翻译整套API手册。
发布维护方为Zephyr Project,原页未列个人作者。中文翻译、整理与示意图:未完纪。本文把Zephyr锁定在4.4.0,该标签的SDK_VERSION为1.0.1。下述命令面向已准备好的Linux开发环境;本稿没有安装、构建、运行、烧录或解析任何真实trace。

跟踪功能提供什么
Zephyr的跟踪钩子让应用收集运行事件,由主机工具显示内核及各子系统内部发生的事情。传统上,为应用增加专用跟踪,常要逐项确定事件载荷、选择序列化格式、编写目标端序列化、决定并实现I/O传输、编写PC端解析器,最后再开发过滤和展示工具。
应用可以使用现成格式,也可以覆盖 include/zephyr/tracing/tracing.h 中的宏定义自定义格式。Zephyr支持多种格式、传输后端和主机工具。由于不同系统的I/O差异很大,载荷与格式所在的上层和传输所在的下层之间,需要兼顾通用性与效率;后文的I/O分类用于解释这些设计取舍。
命名事件与CTF序列化
除了扩展现有序列化格式或自行实现后端,也可以调用通用的 sys_trace_named_event。它接收一个事件名和两个任意的4字节参数;后端格式可能截断过长名称。本文示例用它记录counter_value,让应用事件和调度事件出现在同一份记录中。
CTF(Common Trace Format)是开放的跟踪格式及描述语言,可以复用babeltrace这样的文本工具或TraceCompass这样的图形工具。它对C程序员很熟悉,同时提供更严格的类型描述;详见 CTF格式说明。把应用载荷和序列化格式明确描述出来后,主机解析、过滤与展示基础设施就可以复用。
一个CTF事件包含一个或多个字段。下层可以在事务开始时加锁,逐字段同步输出、拼接或送入线程对应的FIFO,在事务结束时释放锁或输出整包。下面是原文说明用的上层示例,CTF_EVENT把每个实参序列化为一个字段:
/* 仅用于说明接口 */
static inline void ctf_top_foo(uint32_t thread_id, ctf_bounded_string_t name)
{
CTF_EVENT(
CTF_LITERAL(uint8_t, 42),
thread_id,
name,
"hello, I was emitted from function: ",
__func__ /* C99起的标准标识符 */
);
}
字段的序列化、发送及对齐处理可在下层于编译期静态完成。启用 CONFIG_TRACING_CTF 后,这一上层可与不同传输后端配合,采用同步或异步模式。
先完成native_sim的CTF工作流
samples/subsys/tracing展示多种格式和后端。最简单的起点是在native_sim上使用CTF。同版native_sim文档说明,它生成普通Linux可执行文件,虽然文件名以.exe结尾,却不是Windows程序。默认native_sim使用ILP32,64位Linux需要multilib支持,或使用32位用户空间。本文保持原版目标,不擅自换成64位目标来改变示例ABI。
同版 prj_native_ctf.conf 的内容如下:
CONFIG_TRACING=y
CONFIG_TRACING_CTF=y
CONFIG_TRACING_SYNC=y
CONFIG_TRACING_BACKEND_POSIX=y
CONFIG_TRACING_PACKET_MAX_SIZE=64
在Zephyr工作区准备好工具链后,构建示例。下面把文档中的构建指令展开为west命令;未执行:
west build -b native_sim samples/subsys/tracing -- -DCONF_FILE=prj_native_ctf.conf
然后按原文建立输出目录,复制同一4.4.0源码树中的metadata,指定输出数据流文件。本稿给变量路径加双引号,避免路径有空格时被拆开:
mkdir data
cp "$ZEPHYR_BASE/subsys/tracing/ctf/tsdl/metadata" data/
./build/zephyr/zephyr.exe -trace-file=data/channel0_0
程序会持续运行,需要手工停止,例如Linux下按Ctrl+C。使用新的实验目录,避免覆盖已有channel0_0。预期交付给读取器的结构为:
data/
├── metadata
└── channel0_0
不能只把channel0_0交给解析器,也不能混用别的Zephyr版本metadata。同版metadata头为CTF1.8、小端序,定义了线程切入/切出、信号量give/take等事件;named_event包含20字节名称和两个uint32_t参数。
原文建议把上述目录交给babeltrace或TraceCompass。Babeltrace 2.1.2 的 source.ctf.fs支持CTF 1.8;目录需要包含metadata和至少一个数据流。convert命令接受目录输入,默认产生文本输出。准备好读取工具后可用:
babeltrace2 data
这是格式与接口适配核验,不是解析成功的实测。验收时应先看到两个线程交替问候,再在事件输出中检查线程切换、信号量操作,以及名为counter_value的命名事件。不要把下面对执行顺序的解释当作已捕获的trace。
双线程示例实际做了什么
线程A由 K_THREAD_DEFINE 静态创建,它再通过 k_thread_create 动态建立线程B,以展示两种创建方式;真实应用也可两者都静态创建。两者栈大小2048,优先级7。A的信号量初始为1,B为0,最大计数都为1,因此A先取得执行机会。
每轮先等待自己的信号量,再记录counter_value并递增计数、打印问候、休眠500ms,最后give对方的信号量。下一轮会等待对方归还执行机会。共享counter在这一交替约束下依次访问;如果修改为并行写入,就不能照搬“无需同步”的结论。USB配置启用时,A还负责初始化并启用USB设备,失败则返回。程序主体如下,保留原逻辑并整理注释:
/*
* Copyright (c) 2019 Intel Corporation
* Copyright (c) 2012-2014 Wind River Systems, Inc.
* SPDX-License-Identifier: Apache-2.0
* 中文注释整理;逻辑保持原示例。
*/
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/logging/log.h>
#include <sample_usbd.h>
#include <zephyr/tracing/tracing.h>
#define STACKSIZE (2048)
#define PRIORITY 7
#define SLEEPTIME 500
static uint32_t counter;
void helloLoop(const char *my_name,
struct k_sem *my_sem, struct k_sem *other_sem)
{
const char *tname;
while (1) {
k_sem_take(my_sem, K_FOREVER);
sys_trace_named_event("counter_value", counter, 0);
counter++;
tname = k_thread_name_get(k_current_get());
if (tname == NULL) {
printk("%s: Hello World from %s!\n", my_name, CONFIG_BOARD);
} else {
printk("%s: Hello World from %s!\n", tname, CONFIG_BOARD);
}
k_msleep(SLEEPTIME);
k_sem_give(other_sem);
}
}
K_SEM_DEFINE(threadA_sem, 1, 1);
K_SEM_DEFINE(threadB_sem, 0, 1);
void threadB(void *dummy1, void *dummy2, void *dummy3)
{
ARG_UNUSED(dummy1);
ARG_UNUSED(dummy2);
ARG_UNUSED(dummy3);
helloLoop(__func__, &threadB_sem, &threadA_sem);
}
K_THREAD_STACK_DEFINE(threadB_stack_area, STACKSIZE);
static struct k_thread threadB_data;
void threadA(void *dummy1, void *dummy2, void *dummy3)
{
ARG_UNUSED(dummy1);
ARG_UNUSED(dummy2);
ARG_UNUSED(dummy3);
#if defined(CONFIG_USB_DEVICE_STACK_NEXT)
struct usbd_context *sample_usbd = sample_usbd_init_device(NULL);
if (sample_usbd == NULL) {
printk("Failed to initialize USB device");
return;
}
if (usbd_enable(sample_usbd)) {
printk("usb backend enable failed");
return;
}
#endif
k_tid_t tid = k_thread_create(&threadB_data, threadB_stack_area,
STACKSIZE, threadB, NULL, NULL, NULL,
PRIORITY, 0, K_NO_WAIT);
k_thread_name_set(tid, "thread_b");
helloLoop(__func__, &threadA_sem, &threadB_sem);
}
K_THREAD_DEFINE(thread_a, STACKSIZE, threadA, NULL, NULL, NULL,
PRIORITY, 0, 0);
原文件为 src/main.c。其中 sample_usbd.h 由同版 CMakeLists.txt 引入USB共用目录提供,不应只复制main.c就声称它是独立可编译的应用。
其他传输后端:合并在同一示例中
主文档列出的后端包括UART、USB、POSIX原生目标文件输出、与SystemView配合的RTT,以及由调试器读取的RAM。同版示例README另给出USER和GPIO配置。选择与板卡和用途相符的一项,不能把互斥配置全部叠加。
| 用途 | 原文目标与配置 | 关注点 |
|---|---|---|
| UART | mps2/an521,prj_uart.conf或prj_uart_ctf.conf | 可能需在设备树chosen中设置zephyr,tracing-uart,参考boards/mps2_an521_cpu0.overlay。 |
| USB CTF | reel_board,prj_usb_ctf.conf | 串口稳定输出交替问候后,再连接USB并在主机捕获。 |
| POSIX | native_sim,默认配置或prj_native_ctf.conf | 运行一段时间后检查输出文件。 |
| USER | qemu_x86,prj_user.conf | 用户自定义跟踪实现。 |
| SystemView RTT | frdm_k64f,rtt-tracing snippet | 配合支持的调试探针和SystemView。 |
| GPIO | native_sim,prj_gpio.conf | 示例演示GPIO跟踪配置。 |
各替代构建命令如下。它们是独立构建选项;实际使用应分开构建目录或清理相应构建配置,不能按列表连续执行并假定缓存会自动适配。
# UART,二选一
west build -b mps2/an521 samples/subsys/tracing -- -DCONF_FILE=prj_uart.conf
west build -b mps2/an521 samples/subsys/tracing -- -DCONF_FILE=prj_uart_ctf.conf
# USB
west build -b reel_board samples/subsys/tracing -- -DCONF_FILE=prj_usb_ctf.conf
# POSIX默认配置;CTF专用配置见上文
west build -b native_sim samples/subsys/tracing
# USER
west build -b qemu_x86 samples/subsys/tracing -- -DCONF_FILE=prj_user.conf
# SystemView RTT
west build -b frdm_k64f -S rtt-tracing samples/subsys/tracing
# GPIO
west build -b native_sim samples/subsys/tracing -- -DCONF_FILE=prj_gpio.conf
USB后端在板卡串口稳定输出交替问候后,连接USB到主机,运行仓库的捕获脚本。README展示的问候文字是预期形态,当前main.c还会带板名或线程名,不能据旧README字面输出判定失败。原文使用VID 0x2FE3和PID 0x0001,设备配置不同则相应替换:
# 使用已核对的同版仓库脚本;以下保持原文sudo权限要求
sudo python3 "$ZEPHYR_BASE/scripts/tracing/trace_capture_usb.py" -v 0x2FE3 -p 0x0001 -o channel0_0
脚本源码显示查找USB设备,可能detach接口0的内核驱动,设置USB配置并声明接口,向OUT端点写enable,持续读IN端点,以wb模式写输出文件,最后写disable并释放接口。脚本不会重新附加先前detach的内核驱动,设备恢复需按目标环境处理;set_configuration、端点查找、接口声明或打开输出文件等初始化失败,也可能留下设备状态变化。它会覆盖同名文件,原文sudo提升了权限;使用前应确认VID/PID对应目标设备、输出路径独立且可写。脚本不把参数送入shell,未发现命令注入路径,但异常处理并未覆盖所有初始化故障。此稿未执行它。
RAM后端
没有可用USB/UART等I/O但RAM足够时,可启用 CONFIG_TRACING_BACKEND_RAM,并用 CONFIG_RAM_TRACING_BUFFER_SIZE 调整容量。再用GDB把目标内存缓冲区导出:
(gdb) dump binary memory data/channel0_0 <ram_tracing_start> <ram_tracing_end>
尖括号内容是需要替换的实际内存地址,并非可原样执行参数。channel0_0仍要与同版metadata放在同一目录;缓冲区和时间长度有限,不要把短快照当作完整运行历史。
主机跟踪工具
原文按字母顺序介绍工具,以下保留相应能力、配置和限制;CTF入门流程不要求安装全部工具。
Percepio Tracealyzer与TraceRecorder
Tracealyzer提供可视化、分析和报告,可流式传输,也可把事件留在目标RAM中做快照。启用后会自动捕获Zephyr内核事件,应用也可以通过库记录日志,把内核与用户事件放在同一图中,例如变量曲线和状态图。更完整用法见工具附带手册。
TraceRecorder已列入Zephyr manifest,按Apache2.0许可提供。prj.conf中启用以下配置,或在menuconfig的Subsystems and OS Services → Tracing Support启用支持,再在Tracing Format选择Percepio Tracealyzer:
CONFIG_TRACING=y
CONFIG_PERCEPIO_TRACERECORDER=y
还需选择stream port,即数据如何输出。原文这一清单以2024年7月为时间点:Ring Buffer在RAM中保存循环缓冲;RTT经J-Link探针传输;ITM使用Arm Cortex-M的ITM;Semihost供QEMU写主机文件。menuconfig路径为Modules → percepio → TraceRecorder → Stream Port,或在配置中只选以下一项:
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RINGBUFFER=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RTT=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_ITM=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_ZEPHYR_SEMIHOST=y
各端口自己的选项在Modules → percepio → TraceRecorder → 对应Stream Port Config中。
Tracealyzer RAM快照
Ring Buffer默认循环保存最新事件。RAM有限时只能记录短时间,原文不建议用其做长时间性能剖析;它适合配合断点调试,例如在错误处理处停住,回看错误前的事件,也不依赖特定探针。
CONFIG_TRACING=y
CONFIG_PERCEPIO_TRACERECORDER=y
CONFIG_PERCEPIO_TRC_START_MODE_START=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RINGBUFFER=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RINGBUFFER_SIZE=<size in bytes>
将容量占位符替换为字节数。menuconfig中依次选Tracing Support、Tracealyzer格式、Recorder Start Mode=Start、Stream Port=Ring Buffer,再设Buffer Size。RAM紧张可以减小,想保留更长记录可增大;也可在Tracing Support → Tracing Configuration中过滤不需要的事件。使用west debug后,通过GDB导出:
dump binary value trace.bin *RecorderDataPtr
若未指定路径,原文说文件通常在构建目录根下。用Tracealyzer的File → Open → Open File打开它。
Tracealyzer经SEGGER RTT流式传输
Tracealyzer可直接通过J-Link接收RTT数据,适合很长的记录。配置如下:
CONFIG_TRACING=y
CONFIG_PERCEPIO_TRACERECORDER=y
CONFIG_PERCEPIO_TRC_START_MODE_START_FROM_HOST=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RTT=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RTT_UP_BUFFER_SIZE=<size in bytes>
menuconfig对应Recorder Start Mode=Start From Host、Stream Port=RTT、RTT Config中的向上发送缓冲容量。原文给出的默认值为5000字节,以帮助吞吐较低的板载J-Link;RAM不足时可减小,独立J-Link有时1KB甚至更小也足够,仍应按实际吞吐验证。手册路径为Creating and Loading Traces → Percepio TraceRecorder → Using TraceRecorder v4.6 or later → Stream ports。
Tracealyzer经Arm ITM传输
适用于带ITM的Arm Cortex-M设备,原文建议使用支持10MHz或更高SWO速度的快速探针:
CONFIG_TRACING=y
CONFIG_PERCEPIO_TRACERECORDER=y
CONFIG_PERCEPIO_TRC_START_MODE_START=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_ITM=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_ITM_PORT=1
menuconfig设Recorder Start Mode=Start、Stream Port=ITM,ITM端口为1。端口范围0–31,Tracealyzer需要专用通道;0通常留给printf,因此默认用1。Use internal buffer一般保持关闭:开启会先缓存在RAM,再交给周期性的TzCtrl线程发送。主机配置由具体探针决定,见Tracealyzer手册相应Stream ports章节。
QEMU与Semihost
该端口让QEMU通过semihosting把跟踪写到主机文件,不必先准备高速探针:
CONFIG_SEMIHOST=y
CONFIG_TRACING=y
CONFIG_PERCEPIO_TRACERECORDER=y
CONFIG_PERCEPIO_TRC_START_MODE_START=y
CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_ZEPHYR_SEMIHOST=y
menuconfig中先启用General Architecture Options → Semihosting support for Arm and RISC-V targets,再启用Tracing Support与Tracealyzer,Recorder Start Mode=Start,Stream Port=Semihost。默认输出为构建目录根下的trace.psf,除非另设路径;仍通过Tracealyzer的File → Open → Open File打开。
启动模式、自定义端口与Percepio View
Start在TraceRecorder初始化后立即开始,适合Ring Buffer与Semihost。RTT或ITM还可选Start From Host、Start Await Host,两者等待主机开始命令;后者会阻塞初始化,直到收到该命令。因此主机未连接时的启动等待是配置效果,不能误认为程序必然死锁。
Stream port本质是TraceRecorder中的小模块,指定输出函数,也可实现接收开始/停止命令。自定义传输可以通过文件、socket、串口、命名管道等接入;TraceRecorder仓库还包含lwIP等端口,移植到Zephyr可能需要修改。入门资料见 Tracealyzer Getting Started Guides。
原文还介绍免费的Percepio View:基于Tracealyzer,配合传统调试器显示线程、中断、系统调用和用户事件,采用RAM环形缓冲快照,经普通调试连接保存到主机。流式跟踪需要其Profile或Tracealyzer付费升级;不必改Zephyr源码,启用TraceRecorder即可。原文列出的主机平台为Windows和Linux,产品信息见 Percepio View页面;商业功能应按实际版本核对。
SEGGER SystemView
Zephyr对具备必要硬件的目标提供 SystemView 支持,使用其特定载荷格式,通过RTT传输。原文提醒:SystemView新版本虽支持UART和快照等方式,这些方式并不都在Zephyr中支持。可在构建时加rtt-tracing snippet,例如:
west build -b <board> -S rtt-tracing samples/synchronization
board必须替换为实际支持的板卡。启用 CONFIG_SEGGER_SYSVIEW_POST_MORTEM_MODE 可用于故障后回看:系统崩溃后用west attach连接调试器,把内部RAM最近记录加载到SystemView。工具自带的Zephyr API翻译表可能不完整,与当前支持程度不一致;Linux/macOS可用源码树内的表覆盖本地配置:
cp "$ZEPHYR_BASE/subsys/tracing/sysview/SYSVIEW_Zephyr.txt" ~/.config/SEGGER/
这会写用户配置目录,已有同名表应先保留副本。本文未执行该覆盖。
TraceCompass和用户自定义跟踪
TraceCompass是开源CTF可视化工具,可显示线程调度与中断,帮助发现复杂系统中的非预期交互和资源冲突。原文另引 Ericsson的实时系统高级排障演示。本文的最低验收路径使用Babeltrace2,TraceCompass不作为必需步骤。
用户定义跟踪格式可在线程切入/切出、中断进入/退出和CPU空闲等钩子执行自定操作,例如翻转GPIO供示波器观察,以较小CPU开销跟踪;也可生成现有框架不支持的私有格式。启用 CONFIG_TRACING_USER,并按需定义原文列出的函数:
void sys_trace_thread_create_user(struct k_thread *thread);
void sys_trace_thread_abort_user(struct k_thread *thread);
void sys_trace_thread_suspend_user(struct k_thread *thread);
void sys_trace_thread_resume_user(struct k_thread *thread);
void sys_trace_thread_name_set_user(struct k_thread *thread);
void sys_trace_thread_switched_in_user(struct k_thread *thread);
void sys_trace_thread_switched_out_user(struct k_thread *thread);
void sys_trace_thread_info_user(struct k_thread *thread);
void sys_trace_thread_sched_ready_user(struct k_thread *thread);
void sys_trace_thread_pend_user(struct k_thread *thread);
void sys_trace_thread_priority_set_user(struct k_thread *thread, int prio);
void sys_trace_isr_enter_user(int nested_interrupts);
void sys_trace_isr_exit_user(int nested_interrupts);
void sys_trace_idle_user();
借鉴LTTng的方向
原文指出,当时的CTF上层较为简单,借用了Zephyr的SEGGER SystemView调试模块设计。如果借鉴Linux LTTng并序列化成相近格式,有机会直接复用TraceCompass的Linux分析;另一条路径是定制TraceCompass中的LTTng分析以理解Zephyr。这些属于文档所述的演进工作,不能当作当前Zephyr已自动拥有全部Linux分析功能。
I/O分类:为什么有的后端需要锁或缓冲
对原子的推送、生产、写入或入队操作:同步表示调用返回时传输已完成;异步表示仍在等待或进行,常用中断、回调、信号或轮询判断完成;缓冲则先复制并合并多份数据,以摊薄开销或平滑抖动。典型组合如下。
| 组合 | 写入例子与取舍 | 读取例子与取舍 |
|---|---|---|
| 同步、无缓冲 | 经GPIO的PIO连续输出,不需额外FIFO,抖动小,但不能摊薄写入开销。 | 阻塞read、fread、SPI读取或共享内存零拷贝。 |
| 同步、有缓冲 | fwrite或FIFO入队,超过水位后阻塞地突发输出;突发抖动可能导致错过截止时间。 | 带缓存的阻塞读,适合有空间局部性的访问。 |
| 异步、无缓冲 | DMA或共享内存零拷贝,注意数据冒险和竞争。 | 共享内存零拷贝,同样要考虑竞争。 |
| 异步、有缓冲 | 先入FIFO,再由其他机制输出。 | aio_read或DMA,以较大块读入来摊薄等待时间。 |
对于拉取、消费、读取或出队,同步意味着返回时接收完成,异步意味着尚未完成;缓冲指一次搬入比请求更大的块。I/O未必原子,因此经常需要锁;如果各执行上下文拥有独立通道,可能避免共享竞争:
- 非原子写入、只有共享通道,例如UART:需要把整个事件的多个字段锁在同一事务里。
- 非原子写入、多个通道,例如多UART:若下层把每个线程及ISR映射到自己的通道,可避免彼此交错。
- 原子写入、单通道,例如native_sim或DMA:可先拼接再一次写出,也可用锁包住分字段写;是否需要锁由接口保证决定。
- 原子写入、多通道,例如多通道DMA:原文给出免锁的分通道事件输出设计。
lock(); emit(a); emit(b); emit(c); release(); /* 共享通道 */
emit(a, thread_id); emit(b, thread_id); emit(c, thread_id); /* 分通道 */
emit(a ## b ## c); /* 概念示意:拼接到缓冲 */
lock(); emit(a); emit(b); emit(c); release(); /* 不额外拼接 */
emit(a ## b ## c, thread_id); /* 原子写入且分通道 */
这些是原文解释I/O机制的伪代码,##在这里表达拼接思路,不是可直接放进运行时C代码的字符串拼接实现。
对象跟踪
内核也可维护对象列表,用来观察使用情况。原文列出的列表头包括:
struct k_timer *_track_list_k_timer;
struct k_mem_slab *_track_list_k_mem_slab;
struct k_sem *_track_list_k_sem;
struct k_mutex *_track_list_k_mutex;
struct k_stack *_track_list_k_stack;
struct k_msgq *_track_list_k_msgq;
struct k_mbox *_track_list_k_mbox;
struct k_pipe *_track_list_k_pipe;
struct k_queue *_track_list_k_queue;
struct k_event *_track_list_k_event;
这些全局变量指向对应列表头,用SYS_PORT_TRACK_NEXT遍历。以下为遍历已初始化互斥量的原例:
struct k_mutex *cur = _track_list_k_mutex;
while (cur != NULL) {
/* 在此处理当前对象 */
cur = SYS_PORT_TRACK_NEXT(cur);
}
启用CONFIG_TRACING_OBJECT_TRACKING后,可用各类跟踪配置分别控制列表,例如关闭CONFIG_TRACING_SEMAPHORE便不跟踪信号量。它复用跟踪基础设施,所以配置归在Tracing下。遍历代码仍需考虑应用运行中的对象生命周期,不应由这个简例推导出任意并发访问都安全。
原版API参考分组
下面是文档源文件列出的全部API分组。它们由Doxygen生成,保留原版链接供查签名和参数;本篇定位为完整跟踪教程及示例整理,不展开为整套生成API手册。
静态审核、版本与结果边界
本文面向 Zephyr v4.4.0;native_sim 示例 ABI 为 ILP32,SDK_VERSION 为 1.0.1。CTF 读取命令和目录输入依据 Babeltrace2 v2.1.2 官方手册;示例输出的 metadata 与 trace stream 必须来自同一版本。所有代码和命令均为静态教程内容,未安装、构建、烧录或执行;本文不报告实际 trace 解析结果,也未验证 UART/USB/RTT 硬件吞吐。
native_sim不模拟特定板卡,模拟时间可以与主机墙钟解耦。当前CTF头的普通uint32_t时间戳没有在所核头部映射为时钟类,不能仅凭这个字段就声称测得真实板级延迟、调度精度或绝对时间。同步输出、缓冲大小、事件丢失或截断也会影响观察;实际验收需保留构建配置和工具版本。
Percepio 工具能力说明保留上游文档注明的时间背景,不构成当前商业授权承诺;板卡、地址、缓冲容量等占位符需按目标环境替换。
作者、来源与许可
Zephyr Project;原页页脚署名为“© Copyright 2015-2026 Zephyr Project members and individual contributors”。示例main.c:Copyright (c) 2019 Intel Corporation、Copyright (c) 2012–2014 Wind River Systems, Inc.;USB共用CMake:Copyright (c) 2023 Nordic Semiconductor ASA;USB捕获脚本:Copyright (c) 2019 Intel Corporation。Zephyr仓库根目录提供 Apache License 2.0;官方 LICENSING.rst说明其列出不受Apache-2.0覆盖的导入或复用组件及对应文件路径,其中未列出 doc/services/tracing/index.rst;结合根LICENSE与该例外清单,可推定该文档处于项目级Apache-2.0许可范围。这是对仓库许可结构的推定,不是页面上的单独许可标识。原页面页脚本身列的是版权声明,没有单页SPDX标识。示例代码文件另有明确Apache-2.0 SPDX,随文附Zephyr仓库根LICENSE全文:LICENSE-Apache-2.0.txt。本文区分文档与代码许可对象,不把代码文件标识当作页面页脚内容。
Babeltrace2手册署名Philippe Proulx,2017–2024,源文件许可CC BY-SA4.0;本篇仅核对并链接其格式/命令事实,未搬运该手册全文。示意图为未完纪原创。各配置与程序均按原许可按现状提供,本稿未作运行保证。











暂无评论内容