Files
note_AI_compiler/iree/09-runtime.md
T
2026-08-20 17:20:09 +08:00

124 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 阶段 7:运行时(VM + iree-runtime)✅
> 2026-08-15。对应规划阶段 7。分两部分:
> **编译侧** `src/iree/compiler/src/iree/compiler/Dialect/VM/`(生成字节码)
> **运行时** `src/iree/runtime/src/iree/`(C 实现)。
## 1. 整体图景
编译的最后一步是把 HAL 模块序列化成 **VM 字节码**(`.vmfb`),运行时加载并解释执行:
```
HAL 模块 → VM 转换(HALToVM)→ vm.module(字节码 IR)→ 序列化 → .vmfb 文件
↓
iree-runtime 加载 → VM 解释器 → 调 hal.* import → HAL driver 执行
```
## 2. VM = 紧凑字节码虚拟机(编译侧)
VM dialect 定义了一套**字节码级的 IR**,核心 op(`IR/VMOps.td`):
| op | 作用 |
|---|---|
| `vm.module` | 顶层字节码模块 |
| `vm.func` | VM 函数 |
| `vm.import` / `vm.export` | 导入外部函数(如 `hal.command_buffer.dispatch`)/ 导出 |
| `vm.call` / `vm.call.variadic` / `vm.call.yieldable` | 调用(含可让出调用,协作式调度) |
| `vm.branch` / `vm.cond_branch` / `vm.branch_table` | 字节码级控制流 |
| `vm.global.load/store.ref` | 全局引用变量 |
| `vm.const.ref.rodata/zero` | 常量 |
| `vm.list.*` / `vm.buffer.*` | 列表 / buffer 操作 |
| `vm.discard.refs` | **引用计数回收**(显式 GC) |
### 字节码格式
用 **FlatBuffers** 定义(`runtime/src/iree/schemas/bytecode_module_def.fbs`),
是紧凑、可直接 mmap 加载的二进制格式。阶段 2 用 `iree-dump-module` 看到的就是反汇编:
```
Required Types: i32, i64, !hal.allocator, !hal.buffer, !hal.buffer_view,
!hal.command_buffer, !hal.device, !hal.executable, !hal.fence, !vm.buffer
Module Dependencies: hal, version >= 6
Imported Functions:
[ 7] hal.command_buffer.dispatch(...) -> ()
[11] hal.device.queue.execute.indirect(...) -> ()
[16] hal.fence.await(i32, i64, tuple<!vm.ref<?>>...) -> (i32)
```
## 3. iree-runtime(C 运行时)
`runtime/src/iree/` 目录:
| 目录 | 作用 |
|---|---|
| `vm/` + `vm/bytecode/` | **VM 解释器**(字节码解码 + 分发执行) |
| `hal/` + `hal/drivers/` | HAL 运行时 + 各设备驱动 |
| `task/` | 多线程任务调度系统(local-task driver 的基础) |
| `base/` | 基础工具(status、allocator、logging) |
| `builtins/` / `modules/` | VM 内置函数 / 内置模块(如 hal 模块) |
| `schemas/` | FlatBuffers schema(字节码 + 各后端可执行体格式) |
| `runtime/` | 顶层 API(`iree_runtime_instance` 等) |
| `io/` | 参数/文件 IO |
### HAL drivers(真正的设备后端)
`hal/drivers/` 下每个目录是一个设备实现:
| driver | 设备 |
|---|---|
| `local_task` | **CPU 多线程**(基于 task 系统)—— 默认 |
| `local_sync` | CPU 同步(调试用) |
| `cuda` / `hip` / `amdgpu` | NVIDIA / AMD GPU |
| `vulkan` | Vulkan |
| `metal` | Apple Metal |
| `webgpu` | WebGPU |
| `null` | 空设备(测试) |
> 当前环境只装了 base 包,运行时只有 local-task/local-sync。CUDA driver 需要额外构建。
## 4. 与 TVM 0.6 对照
| IREE | TVM 0.6 |
|---|---|
| VM 字节码(.vmfb) | graph runtime / relay VM 的序列化 |
| vm.import(hal.*) | 生成的 kernel 调用 |
| HAL driver(local-task/cuda/vulkan) | DeviceAPI(CPU/CUDA/OpenCL/Metal) |
| task 系统 | CPU 线程池 runtime |
| 引用计数 GC | 无(TVM 用 DLTensor 引用计数) |
**核心差异**:IREE 的 VM 是**完整字节码虚拟机**(带控制流、全局变量、yieldable 调用),
而 TVM 的 graph runtime 只是「按拓扑顺序执行节点」。IREE 的 VM 更接近一个真正的 VM。
## 5. 源码阅读路径
```
# 编译侧(字节码生成)
src/iree/compiler/src/iree/compiler/Dialect/VM/
├── IR/VMOps.td # VM op 定义
├── Conversion/HALToVM/ # HAL → VM 转换
└── Target/ # 序列化到字节码
# 运行时(C)
src/iree/runtime/src/iree/
├── vm/ # VM 解释器
├── hal/drivers/local_task/ # CPU 多线程 driver(默认)
├── hal/drivers/cuda/ # CUDA driver
├── task/ # 任务调度
└── schemas/bytecode_module_def.fbs # 字节码格式
```
## 6. 全流程回顾(7 个阶段串起来)
```
输入(StableHLO/TOSA) → [前端] → linalg → [Flow] dispatch 划分 → [Stream] 异步调度
→ [HAL] 设备抽象 + 触发 codegen → [Codegen] linalg→LLVM/SPIR-V → [VM] 字节码 → [runtime] 执行
```
你现在已经把 IREE 从输入到运行时**完整走了一遍**。每个阶段都有对应笔记和源码路径。
## 下一步(阶段 8 实践,可选)
- 写一个自定义 pass(如自定义 fusion 规则),需要源码构建
- 配 CUDA 后端,看 GPU 的 codegen(LLVMGPU → NVVM)
- 深入某一层读源码(建议 Stream 或 Codegen)