3. 运行时系统概述
AI 编译器负责把高层模型图转换为可在目标硬件上执行的指令序列,但编译产物真正跑起来,还需要一个“现场管理者”——运行时系统(Runtime System)。它位于编译产物与操作系统、硬件之间,负责资源分配、内存管理、算子调度、数据搬运和错误处理。理解运行时系统,是理解 AI 编译器“从图到执行”闭环的关键一步。
3.1 运行时系统的定义
运行时系统是伴随编译产物一起部署、在程序执行期间提供支撑服务的软件层。它不同于编译期做静态优化的编译器前端/后端,而是动态地响应执行请求。对于 AI 场景,运行时系统通常包含:设备抽象层、内存池、内核调度器、流/队列管理、算子库绑定以及性能计数器等。
3.2 核心功能
主流 AI 运行时系统的核心功能可以归纳为以下五类:
- 设备与上下文管理:枚举 GPU/NPU/CPU,创建 context、stream、event,管理设备句柄与生命周期。
- 内存管理:通过内存池(memory pool)复用显存,减少 cudaMalloc 等昂贵调用;支持张量生命周期分析与原地复用。
- 算子调度与执行:按依赖关系下发 kernel,处理同步/异步、流间依赖与事件等待。
- 数据搬运:管理 H2D、D2H、D2D 拷贝,处理 pinned memory 与零拷贝路径。
- 性能与容错:采集时间线、显存占用、kernel 耗时;捕获异常并支持重试或降级。
下面这张图展示了运行时系统在“模型—编译器—运行时—OS/硬件”链路中的位置与内部结构:
3.3 与操作系统和硬件的关系
运行时系统并不直接“裸奔”在硬件上,它依赖操作系统提供的驱动与资源抽象,同时又要屏蔽硬件差异。具体关系如下:
| 层次 | 职责 | 与运行时的交互 |
|---|---|---|
| AI 编译器 | 图优化、算子融合、代码生成 | 向运行时输出可执行计划与内核句柄 |
| 运行时系统 | 资源分配、调度、内存复用、数据搬运 | 调用 OS 驱动接口,管理设备上下文 |
| 操作系统 | 驱动加载、内存映射、线程调度、中断 | 提供 ioctl、mmap、DMA、事件通知 |
| 硬件 | 计算单元、显存、互联总线 | 执行 kernel,完成数据读写与同步 |
一个典型调用链如下:
// 伪代码:运行时下发一个卷积算子
rt_stream_t stream = rt_stream_create(device);
rt_tensor_t* input = rt_tensor_alloc(pool, shape, dtype);
rt_tensor_t* weight = rt_tensor_alloc(pool, shape, dtype);
rt_tensor_t* output = rt_tensor_alloc(pool, out_shape, dtype);
rt_memcpy_h2d(input, host_ptr, bytes, stream);
rt_memcpy_h2d(weight, host_ptr, bytes, stream);
rt_kernel_t* k = rt_kernel_lookup("conv2d_fwd");
rt_kernel_launch(k, grid, block, stream, input, weight, output);
rt_stream_sync(stream);
rt_memcpy_d2h(host_out, output, bytes, stream);
可以看到,运行时系统承担了“翻译官”和“调度员”的双重角色:对上接收编译器的执行计划,对下把计划翻译成驱动能理解的命令,并管理好内存与同步。
3.4 主流 AI 运行时对比
不同厂商和框架的运行时系统设计目标不同,下面从几个维度进行对比:
| 运行时 | 所属生态 | 核心特点 | 典型场景 |
|---|---|---|---|
| CUDA Runtime | NVIDIA | API 简洁,隐式上下文管理,生态成熟 | GPU 训练与推理 |
| CUDA Driver API | NVIDIA | 显式上下文与模块加载,控制粒度细 | 需要精细控制的推理引擎 |
| ROCm/HIP Runtime | AMD | 类 CUDA 接口,跨平台可移植 | AMD GPU 训练推理 |
| CANN Runtime | 华为昇腾 | 面向 NPU 的流与内存管理,图执行模式 | 昇腾推理与训练 |
| TVM Runtime | 开源 | 轻量、可嵌入,支持多种后端 | 端侧与异构部署 |
| ONNX Runtime | 微软/开源 | 图执行器 + 多 EP 插件,跨平台 | 通用推理服务 |
3.5 常见误区与复盘
在实际开发中,初学者容易把运行时系统当成“透明层”,忽略它的开销与约束。常见误区包括:
- 频繁申请释放显存:每次推理都 cudaMalloc/cudaFree,导致性能抖动。应使用内存池并复用张量。
- 忽略流同步:异步 kernel 未正确同步就读取结果,得到脏数据。应使用 event 或 stream sync。
- 混淆编译期与运行期:把本可在编译期确定的形状、布局拖到运行期处理,增加调度开销。
- 忽视设备上下文切换:多卡场景频繁切换 context,导致额外延迟。
复盘一个真实场景:某推理服务在 GPU 上单次延迟 8ms,其中 kernel 计算仅 2ms,其余 6ms 花在 H2D 拷贝与 stream 同步上。通过启用 pinned memory、合并小拷贝、使用双缓冲流,延迟降到 3.5ms。这说明运行时系统的内存与流管理,往往比算子本身更影响端到端性能。
综上,运行时系统是 AI 编译器落地执行的“最后一公里”。它向上承接编译器的执行计划,向下驱动操作系统与硬件,核心在于资源管理、调度与数据搬运。理解它的定义、功能、层次关系与主流实现差异,是后续深入学习内存池、流调度与多设备并行的基础。