1. Jetson平台性能诊断总览
Jetson 不是一块“带 GPU 的开发板”,而是一套把 CPU、GPU、内存、视频编解码、ISP、DLA、PVA 等计算单元通过共享内存与片上互联耦合在一起的异构 SoC 系统。理解这一点,是性能诊断的起点:在 Jetson 上,很多“算力不够”的现象,本质并不是某个单元太慢,而是数据在单元之间搬运、等待或格式转换时被卡住了。
以 Orin 系列为例,典型结构包含 8~12 个 Arm Cortex-A78AE CPU 核心、Ampere 架构 GPU(含 Tensor Core)、第二代 DLA、PVA、NVENC/NVDEC、ISP 以及统一的内存子系统。Nano 系列则更精简,CPU 为 Cortex-A57/A78AE,GPU 为 Maxwell/Ampere,通常没有 DLA。不同型号的差异直接决定了瓶颈可能出现在哪里:Nano 上常见的是内存带宽与 CPU 单核性能受限,而 Orin 上更常见的是多单元争抢内存带宽、功耗墙触发降频,或 DLA/GPU 之间的调度不均衡。
因此,性能瓶颈可以按“资源类型”分为几类,而不是按“哪个模块慢”来分。第一类是计算瓶颈:CPU 单核或全核跑满、GPU SM 占用率高、Tensor Core 利用率低。第二类是内存瓶颈:带宽饱和、访问延迟高、缓存命中率低,这在 Jetson 上尤其关键,因为 CPU 与 GPU 共享同一块 LPDDR。第三类是 I/O 与数据搬运瓶颈:PCIe、USB、MIPI CSI、网络以及内存拷贝(cudaMemcpy、DMA)造成的等待。第四类是调度与同步瓶颈:多线程锁竞争、CUDA stream 串行化、CPU 与 GPU 之间的同步点过多。第五类是功耗与热瓶颈:温度升高后 GPU/CPU 降频,表现为“跑一会儿就变慢”。第六类是软件栈瓶颈:算子未融合、精度选择不当、库版本不匹配、TensorRT 未启用 FP16/INT8。
诊断流程不应从“调参”开始,而应从“建立基线”开始。第一步是明确目标:是降低单帧延迟、提高吞吐 FPS、降低功耗,还是让系统在温度稳定后仍保持性能。不同目标对应不同的观测指标。第二步是采集基线数据,至少包括:CPU 各核占用率与频率、GPU 利用率与频率、内存带宽占用、温度与功耗、端到端延迟。第三步是定位瓶颈类型,把观测到的现象映射到上面六类中的一类或几类。第四步是提出假设并做最小化验证,例如怀疑内存带宽,就单独跑一个纯拷贝测试;怀疑 DLA 调度,就对比 GPU-only 与 DLA+GPU 的耗时。第五步是优化并复测,确认指标改善且没有引入新的瓶颈。
在 Jetson 上做诊断,有几个工具是必须熟悉的。tegrastats 是最直接的全局观测工具,它能以固定间隔输出 CPU/GPU 占用、内存带宽、温度、功耗和频率。例如执行 tegrastats --interval 1000,会看到类似 RAM 3200/7620MB、GR3D_FREQ 45%、CPU [25%@1.9GHz]、tj@52C 这样的字段。其中 GR3D_FREQ 反映 GPU 负载与频率,EMC_FREQ 反映内存控制器频率,若 EMC 长期接近 100% 而 GPU 利用率不高,就要优先怀疑内存带宽。对于更细的 GPU 分析,可以用 Nsight Systems 抓取时间线,观察 kernel 之间的空隙、memcpy 与计算是否重叠、是否存在频繁同步。对于 CPU 侧,top、htop、perf 可以定位热点函数与线程竞争。
sudo jetson_clocks 会把 CPU/GPU/EMC 频率锁定到最高,用于排除动态调频对测量的干扰。做性能对比时,应分别在“默认调频”和“锁定频率”两种状态下各测一次,否则很容易把调频波动误判为优化效果。优化目标需要可量化。一个合理的做法是定义三个层次的指标:资源层(CPU 占用、GPU 占用、内存带宽、温度)、系统层(端到端延迟、FPS、功耗)、业务层(精度、召回率、任务完成时间)。优化时优先改善系统层指标,同时用资源层指标解释原因,用业务层指标确认没有退化。例如在目标检测任务中,若把推理从 FP32 改为 INT8,FPS 从 22 提升到 48,但 mAP 从 0.72 降到 0.69,那么是否接受取决于业务容忍度,而不是单纯看 FPS。
最后要建立“瓶颈会转移”的意识。把 GPU 推理优化到极致后,瓶颈可能转移到摄像头采集或内存拷贝;把 CPU 预处理优化后,瓶颈可能转移到 GPU 后处理。因此诊断不是一次性动作,而是一个“观测—假设—验证—复测”的循环。每一轮优化后都应重新采集基线,确认新的瓶颈位置,再决定下一步动作。只有把硬件结构、瓶颈分类、观测工具和量化目标串成一条线,Jetson 的性能诊断才具备可重复性和工程价值。