29 可观测性与遥测洞察
- 章节编号:29
- 所属层:X 横向(贯穿 09 Driver、12 Runtime、23 Fleet、18 autotune 回写)
- 关联 ADR:ADR-111(端侧 Profiler 与 HAL trace)、ADR-112(Fleet 遥测 schema)、ADR-113(问题归因:编译/运行时/驱动)、ADR-114(隐私分级与采样)
- 上游依赖:09(profiler ioctl)、18(telemetry→spec)、23(Fleet)、24(上传边界)、30(Agent 归因)
学习目标
- 前置知识:读过 12/13 章(运行时与实时调度)与 21 章(具身模型部署形态);知道 π0 类「VLM prefill + 流匹配去噪 chunk」的流水结构、什么是 chunk 延迟;对「分位数(p50/p99)」「trace / span」「时间序列指标(gauge / histogram)」有基本概念。无需机器人操作系统背景——本章从「怎么把一次推理的延迟拆开、上报、归因」而非「怎么写控制器」切入。
- 学完产出:① 能说清一套具身遥测栈 的三层结构——端侧 Profiler(单次推理 trace)、端侧指标聚合(chunk_ms / Hz / thermal / power)、Fleet 云端聚合(跨机队 SLO 看板)——各自采什么、上报什么、谁消费;② 能把「为什么监控 chunk 延迟的 p99 而非均值」用尾延迟算一遍,理解一个 chunk 卡顿如何击穿实时控制;③ 能解释 tracing(OpenTelemetry / IREE VM trace / ros2_tracing)如何把一次跨节点(感知→VLM→动作头→执行)的延迟拆到具体 span、定位瓶颈在哪一跳;④ 能读懂 §3.2 的归因树,把一次「chunk p99 回归」翻译成「bundle / thermal / driver / runtime / sim2real」五条可执行的排查路径;⑤ 能对照 §3.3 隐私分级(L0–L3)与现场遥测回传设计,说清「失败样本如何回传而不泄露原始视频」的取舍。
- 阅读姿势:盯住一条主线——「可观测性的价值,全部由『能不能把一个数字拆回到某一层某一跳』决定」。一个笼统的「今天平均延迟 80ms」毫无归因价值;有价值的是「p99 从 90ms 涨到 140ms,trace 显示 DiT 去噪第 3 步的 dispatch 变慢,且发生在 thermal throttle 触发之后」。读表格时不要只看采了哪些字段,要问「这个字段能把问题定位到哪一层」。
1. 范围与目标
定义 Profiler/Debugger、端侧指标、Fleet 遥测、性能回归归因。支撑 27 benchmark CI 与 31 field 闭环。
核心问题
- 对标 Nsight Systems、IREE trace、Chrome trace、DCGM Fleet?
- 具身须采哪些 SLO 指标(chunk_ms/Hz/thermal/power)?
- 如何 归因:compiler vs runtime vs driver?
- 隐私(摄像头)与 28/24 如何一致?
2. 需求洞察
| 角色 | 需要 |
|---|---|
| 算子工程师 | per-op timeline;roofline |
| Runtime | VM/module fence;RTC 状态 |
| AE/客户 | Fleet dashboard:Hz/p99/OTA 版本 |
| 安全 | 无默认 raw video |
2.1 三层遥测栈的职责边界
可观测性不是「多采一点数据」,而是三个数据密度、时效、消费者都不同的层次。把它们混为一谈,是端侧遥测最常见的设计错误——高频 trace 采太多会拖慢推理本身,低频聚合又丢掉了归因所需的细节。
- 端侧 Profiler(高密度):采单次推理的 per-op / per-dispatch timeline,粒度到「DiT 去噪第 3 步 dispatch 12ms」。开销高(trace 本身会拖慢推理),默认关闭,仅在 debug / CI / 现场排障时按需开启。
- 端侧指标聚合(中密度):常驻运行,把每次推理的关键数值(chunk_ms、effective_hz、power、thermal)聚合成 histogram / 滑窗统计后周期上报。这是常态化 SLO 监控的主力,开销必须低到不影响实时控制。
- Fleet 聚合(低密度):云端跨机队汇总,回答「整个机队的 p99 是否达标、哪个 OTA 版本引入了回归」。数据密度最低,但归因维度(bundle_version / spec_hash)最全。
3. 技术现状与趋势(2025–2026)
3.1 TOP 级可观测性方案深度对比
| 栈 | 端侧 Profiler | Fleet/云 | 机器人 | 优势 | 劣势 |
|---|---|---|---|---|---|
| NVIDIA Nsight Systems | CUDA+CPU system trace | Nsight Cloud K8s(以官方命名为准) | Jetson/Thor | 成熟;JetPack 集成 | GPU 中心;闭源 |
| NVIDIA Nsight Compute | kernel 级 | — | GPU kernel | 深度 | 非 VLA E2E |
| IREE runtime trace | VM/HAL timeline | — | 我们主线 | 与编译同源 | DSA 待扩展 |
| Chrome/Perfetto trace | 通用 | — | Android 常用 | 开放格式 | 无 NPU 语义 |
| DCGM / Fleet Intelligence | GPU 健康 | 数据中心 Fleet | 少端侧 | 规模运维 | 非具身 SLO |
| AWS CloudWatch IoT | agent | 托管 | 通用 IoT | 托管 | 无 chunk_ms 语义 |
| ROS2 ros2_tracing | DDS timeline | — | ROS 通用 | 开源 | 不含 NPU |
| Weave/W&B(ML) | 训练 | 实验 | 训练为主 | 实验管理 | 非端侧 RT |
| 我们 dsa-telemetry | HAL+VM+power | 23 Fleet API | manifest 绑定 | VLA 原生指标 | 待建 |
3.1a 方案深度对比
Nsight + Nsight Cloud(2025–2026)
产品名以 NVIDIA 官方命名为准;下表能力描述为公开资料整理。
| 优势 | 劣势 | 我们借鉴 |
|---|---|---|
| K8s Operator 无侵入注入;Streamer 浏览器 UI | CUDA 专用 | Fleet 远程 trace 拉取 |
| Thor JetPack 文档齐全 | 难映射 IREE VM | 导出 Perfetto 兼容 |
IREE trace
| 优势 | 劣势 | 我们借鉴 |
|---|---|---|
| compile+run 同源;dispatch region 可见 | 默认 CPU/GPU 后端 | DSA HAL trace 扩展 |
我们的 VLA 原生 telemetry
| 字段 | 用途 |
|---|---|
chunk_ms_p50/p99 | 27 SLO |
effective_hz | RTC |
power_w/thermal_c | 11 |
bundle_version/spec_hash | OTA 归因 |
npu_throttle | 11/09 |
ROS2 ros2_tracing + dsa 扩展(ADR-111)
| 维度 | ros2_tracing | dsa-telemetry 扩展 |
|---|---|---|
| 覆盖 | DDS pub/sub;executor | + IREE VM/HAL;chunk 边界 |
| 格式 | LTTng → Perfetto | 统一 Perfetto 导出 |
| Fleet | 本地 | 29→23 聚合 chunk_ms_p99 |
| 隐私 | 可关 | 默认 L0 无图像 |
OpenTelemetry 映射(ADR-112)
| OTel 概念 | dsa 字段 | 示例 |
|---|---|---|
trace.span | iree.dispatch | DiT step 12ms |
metric.gauge | effective_hz | RTC 瞬时频率 |
metric.histogram | chunk_ms 分桶 | 27 SLO(p99 从分桶算) |
resource.attr | bundle_version | semver |
log.record | thermal_throttle | 11 联动 |
指标类型选型要点:分位数(p99)必须走 histogram 而非 gauge。gauge 只存「当前瞬时值」,跨机队 / 跨时窗聚合时无法还原分位数——把 100 台机器的 p99 gauge 再求平均,得到的不是机队 p99,而是一个没有统计意义的数。正确做法是端侧上报
chunk_ms的 histogram 分桶(bucket 计数),云端合并各机分桶后再从合并直方图里算真实分位数。effective_hz这类「当前值即语义」的量才适合 gauge。
3.1b OpenTelemetry span 树:一次跨节点推理的拆解
具身推理是一条跨节点、跨设备的流水:相机采图 → 前处理 → VLM prefill(NPU)→ 动作头多步去噪(NPU / DiT)→ 动作输出 → ROS2 发布 → 执行器。任一跳变慢都会推高 chunk 延迟,而单看一个总延迟数字无法知道慢在哪。OpenTelemetry 的 trace / span 模型正是为此设计:每一跳是一个 span,span 之间的父子 / 因果关系还原出完整调用链。
怎么用这棵树定位跨节点延迟:root span(chunk_e2e)记录总延迟 140ms,子 span 把它拆成感知 / 前处理 / prefill / 去噪 / 发布五段。一眼看出瓶颈在 action_denoise(74ms,异常);再下钻到步级 span,发现是 denoise_step_3 单步膨胀到 38ms(其余步只有 12ms);该 span 上挂了一条 thermal_throttle 的 log.record——归因链闭合:热节流在第 3 步触发,NPU 降频,拖慢了这一步的 dispatch。没有 span 树,你只能看到「总延迟 140ms」这个孤立的数字,根本不知道该去查感知、查模型、还是查散热。
跨节点的关键在 trace context 传播:感知节点、推理节点、ROS2 执行节点可能是不同进程甚至不同设备。OpenTelemetry 用 trace_id + span_id 在节点间透传上下文(ros2_tracing 侧走 DDS 消息头,NPU 侧走 IREE VM trace),使一次物理推理的所有 span 挂在同一个 trace_id 下——这是把「跨节点延迟」拼成一条完整链路的前提。
3.2 归因树(ADR-113)
chunk p99 回归
├─ bundle/spec 差异? → 18 diff
├─ thermal throttle? → 11
├─ driver regression? → 09 CI
├─ runtime scheduling? → 14 VM 争用
└─ sim2real? → 31 field
3.3 隐私(ADR-114)
| 级别 | 内容 | 默认 |
|---|---|---|
| L0 | 聚合 ms/Hz/W | ✅ |
| L1 | 失败 episode metadata | ✅ opt-in |
| L2 | 缩略图/关键帧 | 客户 opt-in |
| L3 | 原始视频 | 禁止默认 |
3.3a 现场失败样本回传:隐私分级下的取舍
现场遥测最有价值的不是「一切正常」的数据,而是失败样本——机器人抓空、动作卡顿、rollout 中断的那几帧。这些样本直接喂给 31 章 field 闭环与 18 章 autotune 回写。但摄像头原始视频是隐私红线,直接回传既违规又占带宽。工程解法是分级回传:优先回传能定位问题的最小信息,逐级 opt-in 才升级到图像。
回传优先级的核心逻辑:多数现场失败(延迟抖动、热节流、调度争用)靠 L0 聚合遥测 + 失败时刻的 span 树就能定位,根本不需要图像——这正是 §3.1b span 树的价值延伸到现场。只有当问题疑似「感知看错了 / 语义理解失败」时,才逐级 opt-in 到 L1(动作 / 状态元数据,仍无像素)乃至 L2(脱敏缩略图)。L3 原始视频默认禁止,需 28 章合规单独审批。带宽与隐私双约束下,「回传能定位问题的最小信息」是第一原则,而非「把现场画面都拉回来慢慢看」。
6. 结论与 ADR
- 端侧:IREE trace + HAL counters + power;导出 Perfetto。
- Fleet:chunk_ms/Hz/W + version;对接 23。
- 18 autotune 回写:硅后 telemetry 触发 L2(30)。
- ADR-111 端侧 Profiler:IREE trace flags;HAL trace ioctl;与 Demo 集成。
- ADR-112 Fleet schema:OpenTelemetry 式;manifest/bundle 字段 mandatory;p99 走 histogram 分桶,非 gauge。
- ADR-113 归因:分层归因树;CI 自动 bisect spec。
- ADR-114 隐私:L0–L3;默认 L0;28 合规;失败样本分级回传,优先无图像。
深入思考
每题先给题干,再折叠一份图文并茂的参考答案。建议先合上答案自己想 3 分钟,再展开对照。
思考题 1:为何监控 chunk 延迟的 p99 而非均值
具身控制里,遥测栈上报 chunk_ms 时既可以报均值(mean),也可以报 p99。业界(含我们 §3.1c 的 dsa-telemetry)坚持采 p99 且用 histogram 存储。结合 §2.1 三层栈与 21 章「chunk 延迟必须小于执行时长」的实时性口径,把尾延迟算一遍,论证为什么均值会「骗过」你,以及为什么 p99 必须走 histogram 而非 gauge。
展开参考答案(含尾延迟击穿实时性图 + 算一遍)
结论:实时控制的成败由最慢的那几次推理决定,而不是平均水平;均值会把偶发的致命卡顿稀释到看不见,p99 才暴露「有百分之一的 chunk 赶不上执行、机器人会断供停顿」。而 p99 只能从延迟分布(histogram)里算,gauge 存的瞬时值跨机队 / 跨时窗一聚合就失真。
用具体数字算一遍(以 π0 类 @端侧 chunk 生成为参考,H=50 / 50Hz 控制,数量级估算,以官方为准):
- 执行时长基准:一个 chunk 覆盖 H=50 个动作,50Hz 每动作 20ms → 一个 chunk 覆盖 50 × 20ms = 1000ms 的执行。只要下一个 chunk 在 1000ms 内生成好,流水就不断供(21 章口径)。
- 正常主体:99 次推理延迟在 58~66ms,远小于 1000ms,绰绰有余。
- 偶发尖峰:第 100 次因热节流叠加 VM 争用,延迟飙到 1050ms。
- 算均值:(99 × 62 + 1050) / 100 = (6138 + 1050) / 100 ≈ 71.9ms。均值只从 62 涨到 72,看起来依旧健康 —— 均值把 1050ms 的尖峰稀释掉了。
- 算 p99:第 99 百分位落在那次尖峰上,p99 = 1050ms。1050ms > 1000ms 执行时长 → 这个 chunk 没赶上,机器人在这一拍断供、停顿。
- 结论:均值 72ms「达标」,p99 1050ms「击穿」。实时控制里,1% 的卡顿就是 1% 的动作停顿,用户能直接看到机器人「顿一下」。所以 SLO 必须盯 p99(甚至 p999),而非均值。
为什么 p99 必须走 histogram:p99 是「分布的第 99 百分位」,需要延迟分布才能算。若端侧只上报一个 p99 gauge(瞬时快照),云端把 100 台机器的 p99 gauge 再平均,得到的不是机队 p99——分位数不能这样合并。正确做法:端侧把 chunk_ms 落进 histogram 分桶(如 [0,50)、[50,60)、[60,80)、[80,200)、[200,+∞) 各自计数),云端合并各机的分桶计数后,再从合并直方图里算真实分位数(§3.1a OTel 映射把 chunk_ms 明确归为 metric.histogram)。
回链:详见 §2.1 三层栈(端侧指标聚合层做 histogram 分桶)、§3.1a OpenTelemetry 映射(
metric.histogram行)、§3.1c dsa-telemetrychunk_ms_p50/p99字段,以及 21 章「chunk 延迟 < 执行时长」实时性口径。
思考题 2:tracing 如何定位跨节点延迟
一次具身推理横跨感知节点、VLM 推理节点、动作头、ROS2 执行节点,可能分布在不同进程 / 设备上。当 chunk p99 回归时,只有「总延迟变大」这个数字远远不够。结合 §3.1b 的 OpenTelemetry span 树与 §3.2 归因树,分析 tracing(trace_id / span / context 传播)如何把一个总延迟拆回到具体某一跳,以及它如何与 §3.2 的五条归因路径衔接。
展开参考答案(含跨节点 trace 拆解与归因衔接图)
结论:tracing 的本质是给一次物理推理分配一个全局 trace_id,让跨进程 / 跨设备的每一跳都记成挂在同一 trace_id 下的 span;拆开 span 树就能看出总延迟里哪一段膨胀,再顺着膨胀 span 上挂的 log / attribute 关联到具体成因,最后落进 §3.2 归因树的某一条分支——这就是从「总延迟变大」到「driver 第几号提交回归」的完整链路。
用一次排查走一遍:
- 总延迟报警:Fleet 看板显示某批机器 chunk p99 从 90ms 涨到 140ms。
- 按 trace_id 拉出一条完整 trace:感知 8ms、prefill 46ms、去噪 74ms、发布 6ms —— 一眼定位膨胀在
action_denoise(去噪本应 ~30ms)。跨节点能拼成一条链,靠的是 trace_id 通过 DDS 消息头(ros2_tracing 侧)与 IREE VM trace(NPU 侧)在节点间透传(§3.1b context 传播)。 - 下钻步级 span:去噪 5 步里
denoise_step_3单步 38ms(其余 12ms)— — 精确到「第几步」。 - 看膨胀 span 上的线索:该 span 挂了
thermal_throttle的log.record,且bundle_version未变、无 VM 争用重叠。 - 落进归因树:线索指向 §3.2 的
thermal throttle? → 11分支——根因是热节流触发 NPU 降频,而非 driver / bundle / 调度回归。若线索是 bundle_version 变化,则走bundle/spec → 18 diff;若是 HAL dispatch 普遍变慢,则走driver regression → 09 CI。
为什么单靠指标(metric)不够、必须要 trace:metric(如 chunk_ms histogram)告诉你**「有问题、多严重」,但它是聚合后的标量,丢掉了因果结构;trace 保留了「一次具体推理的完整调用链」,能回答「问题在哪一跳、为什么」**。两者互补:metric 触发报警(p99 超阈),trace 完成归因(定位到 denoise_step_3 + thermal)。这正是 §3.2 归因树能「自动 bisect」的数据基础——没有跨节点 trace,归因树的每一个分支都无从判断。
回链:详见 §3.1b OpenTelemetry span 树(trace_id / context 传播)、§3.2 归因树五分支、§3.1a OTel 映射(
trace.span→iree.dispatch),以及 ADR-113「分层归因树 + CI 自动 bisect spec」。
思考题 3:现场遥测如何回传失败样本
31 章 field 闭环与 18 章 autotune 回写都渴求现场失败样本,但摄像头原始视频是隐私红线(§3.3 L3 默认禁止)、且回传带宽有限。结合 §3.3 隐私分级(L0–L3)与 §3.3a 分级回传流程,论证「优先回传能定位问题的最小信息」这一原则,并说明什么情况下才应逐级 opt-in 到图像。
展开参考答案(含失败样本分级回传决策 + 对比表)
结论:现场失败样本的回传要在「归因价值」「隐私红线」「带宽成本」三者间权衡;绝大多数失败(延迟 / 热 / 调度)靠 L0 聚合遥测加失败时刻的 span 树就能定位,根本不需要图像;只有当问题疑似「感知看错 / 语义失败」这类必须视觉证据的场景,才逐级 opt-in 到 L1 元数据、L2 脱敏缩略图,L3 原始视频始终需单独合规审批。
四级回传的成本 / 价值 / 隐私对比:
| 级别 | 回传内容 | 归因能力 | 带宽 | 隐私风险 | 默认 |
|---|---|---|---|---|---|
| L0 | 聚合 ms/Hz/W + 失败时刻 span 树 | 定位延迟 / 热 / 调度 / driver 类(§3.2 归因树多数分支) | 极低 | 无 | ✅ 常开 |
| L1 | 失败 episode metadata:动作序列 / 状态向量 / 时间戳 | + 定位动作 / 状态异常(仍无像素) | 低 | 低(无原始感知) | ✅ opt-in |
| L2 | 脱敏缩略图 / 关键帧(降分辨率) | + 视觉证据(看错了什么) | 中 | 中(需脱敏) | 客户 opt-in |
| L3 | 原始视频 | 完整场景复现 | 高 | 高 | ❌ 禁止默认 |
为什么「最小信息优先」是对的:
- 归因效率:§3.2 归因树的五条分支里,bundle / thermal / driver / runtime 四条完全不需要图像——L0 的 span 树 + 聚合指标就能定位(见思考题 2)。只有 sim2real / 感知失败这一类才需要视觉。既然多数失败 L0 就能闭合,默认拉图像是浪费带宽 + 徒增隐私风险。
- 隐私红线不可逆:一旦原始视频回传上云,泄露风险与合规责任就已发生;而 L0/L1 从设计上就不含原始像素,风险从源头消除(§3.3 L3「禁止默认」、ADR-114「默认 L0」)。
- 带宽约束:现场机队规模大,若每个失败都回传视频,上行带宽与存储成本不可承受;分级回传让「昂贵的图像」只在真正必要时(客户显式授权)才动用。
什么时候才升级到图像:当且仅当 L0/L1 无法归因、且问题本质是视觉 / 语义的(如「机器人把红色积木当成番茄抓了」——这只能从图像看出),才在客户 opt-in 下升级到 L2 脱敏缩略图。L3 原始视频即便到这一步也需 28 章单独合规审批,不因排障需要就自动放行。这与 §5.3 类推理里「在能覆盖需求的前提下选择成本 / 风险最低的那个子集」是同一取舍哲学。
回链:详见 §3.3 隐私分级表(L0–L3)、§3.3a 分级回传流程图、§3.2 归因树(判断哪些分支需要图像),以及 ADR-114「L0–L3;默认 L0;失败样本分级回传,优先无图像」。
附:信息来源
区分公开/估计;参考时间 2026-06。产品名(Nsight Systems / Nsight Cloud / DCGM 等)以厂商官方命名为准。
- NVIDIA Nsight Systems / Nsight Cloud(K8s Operator + Streamer 浏览器 UI):NVIDIA developer docs;命名与能力以官方为准。[公开]
- IREE profiling / tracing(Tracy / VM+HAL timeline;compile+run 同源):iree.dev profiling docs。[公开]
- OpenTelemetry(trace / span / metric.gauge / metric.histogram / resource / log 数据模型):opentelemetry.io specification。[公开]
- ROS2 ros2_tracing(LTTng → Perfetto;DDS pub/sub + executor trace):github.com/ros2/ros2_tracing;design.ros2.org。[公开]
- Perfetto(开放 trace 格式与 UI):perfetto.dev。[公开]
- NVIDIA DCGM / Fleet Intelligence(数据中心 GPU 健康与机队运维):developer.nvidia.com DCGM docs;定位为数据中心,非具身端侧 SLO。[公开]
- p99 / histogram 聚合口径、chunk 尾延迟算例:基于 21 章 π0 chunk 实时性口径的工程估算;具体 ms 以官方 / 实测为准。[估计]
- 失败样本分级回传(L0–L3)与隐私边界:对齐 28/24 章合规;为本项目内部设计。[内部]