1. Jetson平台与CUDA生态概览

Jetson 是 NVIDIA 面向边缘与嵌入式场景的 AI 计算平台。它与桌面级 GeForce、数据中心级 A100/H100 最大的不同,在于把 CPU、GPU、内存、视频编解码、显示与高速 I/O 集成在一颗 SoC 上,并在同一块板卡上共享功耗与散热预算。理解这一点,是后续做 CUDA 算子加速与性能调优的前提:在 Jetson 上,性能瓶颈往往不是"GPU 算得慢",而是"数据搬得慢、功耗被限住、CPU 与 GPU 抢内存带宽"。

1.1 Jetson 硬件架构:SoC 里的 GPU 与统一内存

以 Jetson Orin 系列为例,其 SoC 内部主要包含:ARM Cortex-A78AE CPU 集群、Ampere 架构 GPU(含 Tensor Core 与 RT Core)、NVDLA 深度学习加速器、PVA 视觉加速器、视频编解码单元(NVENC/NVDEC)、ISP 图像信号处理器,以及内存控制器与各类高速接口。GPU 通过内部互连访问 LPDDR5 内存,CPU 与 GPU 共享同一物理内存,这就是"统一内存"(Unified Memory)架构。

统一内存带来两个直接影响。第一,CPU 与 GPU 之间传输数据时,理论上可以做到零拷贝(zero-copy),省去显式的 cudaMemcpy 往返;第二,CPU 与 GPU 会竞争同一份内存带宽,若 CPU 侧同时在做大量数据搬运,GPU 的有效带宽会被压缩。因此调优时不能只看 kernel 的耗时,还要看内存带宽占用率与 CPU 侧负载。

另一个关键约束是功耗模式。Jetson 通过 nvpmodel 提供多档功耗配置(如 15W、30W、MAXN),不同档位会限制 CPU/GPU 的最高频率与可用核心数。同一段 CUDA 代码在 15W 与 MAXN 下的耗时可能相差一倍以上,所以任何性能数据都必须标注功耗模式与散热条件,否则不可比较。

1.2 CUDA 工具链:从源码到可执行算子

Jetson 上的 CUDA 工具链与桌面平台基本一致,但版本由 JetPack SDK 统一绑定。JetPack 包含 CUDA Toolkit、cuDNN、TensorRT、驱动与系统镜像,安装后 nvcc、nsight-systems、nsight-compute 等工具即可使用。典型编译流程如下:

# 查看当前 CUDA 版本与 GPU 信息
nvcc --version
nvidia-smi

# 编译一个简单的向量加法 kernel
nvcc -O3 -arch=sm_87 vector_add.cu -o vector_add

# 运行并用 Nsight Systems 采集时间线
nsys profile --stats=true ./vector_add

其中 -arch=sm_87 对应 Orin 的 GPU 计算能力(Ampere 架构)。若不确定目标架构,可用 -arch=native 让 nvcc 自动探测。编译完成后,用 nsys 采集时间线,可以直观看到 kernel 执行、内存拷贝与 CPU 调用的时间分布,这是定位"算子慢在哪"的第一步。

1.3 cuDNN 与 TensorRT 的角色分工

在 Jetson 上写算子,通常有三种层次的选择:

  • 手写 CUDA kernel:完全控制线程组织、共享内存与访存模式,适合自定义算子或需要极致优化的热点。
  • cuDNN:提供卷积、池化、归一化、激活等深度学习原语的优化实现,适合直接替换框架中的标准算子。
  • TensorRT:在模型层面做图优化、层融合、精度校准(FP16/INT8)与 kernel 自动选择,适合整网推理部署。

三者的关系可以理解为:TensorRT 负责"整网怎么跑得快",cuDNN 负责"单个标准算子怎么跑得快",手写 CUDA 负责"cuDNN 和 TensorRT 覆盖不到或不够快的地方"。实际项目中,常见做法是先用 TensorRT 构建引擎,再用 Nsight 定位耗时最高的层,若该层是标准卷积则尝试 cuDNN 调优,若是自定义算子则手写 kernel。

1.4 算子加速在边缘计算中的价值

边缘设备与云端最大的差异是资源受限:功耗有上限、内存带宽有限、散热空间小。一个在 A100 上只占 5% 时间的算子,在 Jetson 上可能因为带宽或功耗限制变成瓶颈。因此算子加速在边缘场景的价值不只是"更快",而是"在给定功耗与延迟预算内跑得动"。

举例来说,一个 1080p 的实时目标检测任务,若整网推理需要 40ms,而其中预处理(resize、归一化)占了 12ms,那么把预处理从 CPU 迁移到 GPU 并用 CUDA 实现,可能把总延迟压到 30ms 以内,从而满足 30FPS 的实时要求。这类"非神经网络层"的算子加速,往往是边缘部署中最容易被忽视、却收益明显的部分。

调优前先固定变量:记录 JetPack 版本、nvpmodel 功耗档、散热方式(被动/主动)、环境温度。否则同一份代码在不同条件下测出的数据没有可比性。
Jetson 平台 CUDA 生态与算子加速路径 Jetson SoC(Orin 示例) ARM CPU 集群 Cortex-A78AE Ampere GPU Tensor Core / RT Core NVDLA / PVA 深度学习 / 视觉加速 NVENC / NVDEC 视频编解码 统一内存 LPDDR5(CPU / GPU 共享) 零拷贝可行,但带宽需竞争 nvpmodel 功耗档:15W / 30W / MAXN CUDA 工具链与算子加速层次 ① 手写 CUDA Kernel 线程组织 / 共享内存 / 访存优化 ② cuDNN 原语库 卷积 / 池化 / 归一化 / 激活 ③ TensorRT 整网优化 层融合 / FP16·INT8 / kernel 自动选择 算子加速调优闭环 定位热点 nsys / ncu 时间线 选择层次 kernel / cuDNN / TRT 实现与优化 访存 / 并行 / 精度 验证与对比 延迟 / 功耗 / 精度 未达标则回到定位热点,迭代优化

1.5 一个可复现的入门验证

在正式调优前,建议先做一次基线测量,确认工具链与功耗配置正常。以下流程可作为本章的实践起点:

  1. 用 sudo nvpmodel -q 查看当前功耗档,用 sudo jetson_clocks 锁定最高频率(仅测试时使用)。
  2. 编译并运行一个向量加法 kernel,记录 kernel 时间与端到端时间。
  3. 用 nsys profile 采集时间线,确认 kernel 确实在 GPU 上执行,且没有意外的同步或拷贝。
  4. 切换功耗档(如从 15W 到 MAXN),重复测量,观察耗时变化幅度。

若 MAXN 下耗时明显低于 15W,说明当前算子受频率/功耗限制;若两者接近但都远高于预期,则更可能是访存或并行度问题。这个简单判断,能帮你在后续章节中快速缩小调优方向。

不要在没有锁定功耗档和频率的情况下比较两次测量结果。Jetson 的动态调频会让同一份代码的耗时波动 20% 以上,容易得出错误结论。