Prepared runtime 与 private-COW
一句话
Pysolate 的 Experimental/default-off private-COW lane 可以把一个从未服务过请求的 WASM linear-memory baseline 封存在 Linux memfd 中,再用 MAP_PRIVATE 为每个 consumer 建立私有 mapping;这样共享未修改页面,同时仍为每次执行建立和清理独立 module instance。
先看一个例子
一间机房要给每位学生提供相同的预装环境。每次从零安装依赖很慢,让所有人共用同一台正在被修改的电脑又会相互污染。
一种折中方式是保存一份只读的“刚安装完”磁盘映像。每位学生从它启动自己的实例:没修改的部分可以共享,写入后只产生自己的副本。课程结束后删除这个实例,原始映像不变。
Private-COW 对 WASM linear memory 做了类似处理。这个类比只覆盖内存页;Pysolate 没有因此获得完整 Python 解释器快照。
真实机制
普通 prepared runtime 先 instantiate module,运行 _initialize 和 runtime_init,保存一个尚未服务请求的 preparedInstance。takePrepared 取走后 slot 立即清空,所以它是 single-use slot,不是循环 reset 的解释器池。
Linux private-COW 将复用粒度移到 linear-memory page:
- Host 从 canonical prepared module 读取 baseline bytes。
newCOWImageWithMaximum建立 memfd,写入 baseline,按声明的 maximum 调整大小,并加F_SEAL_*,使 backing image 不能再写或伸缩。- 每个 consumer 用
mmap(..., MAP_PRIVATE)建立自己的读写 mapping。 - 未修改页面可以由内核共享;consumer 首次写某页时,内核为它创建私有 copy。
- Runtime 为该 mapping 重新 instantiate module,检查 memory shape,运行必要初始化,并在 serve 前用
MADV_DONTNEED丢弃准备期间的私有脏页,重新看到 sealed baseline。 - 这份 instance 只服务一次 Run,随后关闭 module、temporary 和 COW lease,并 unmap 私有 memory。
compiled module + sealed immutable baseline
├─ MAP_PRIVATE → consumer A → private writes → close
└─ MAP_PRIVATE → consumer B → private writes → close
两个 consumer 共享的是 sealed memfd/page-cache lineage,不是同一个可变 module。Request、response、stdout/stderr、workspace、Broker context 和 Host handles 仍按本次 Run 建立。Baseline bytes 写入 memfd 本身也涉及 copy,因此不能笼统称为 zero-copy。
当前 Prepared Family v1 在这个 substrate 上增加了一个显式 multi-consumer owner。两条 lane 复用同一份 bounded NumPy input:Linux exact-artifact private-COW lane 还共享 sealed image/page lineage;portable private-copy lane 则逐 Guest prepare。每个 member 仍建立 fresh single-use runner,不共享 Plan、Broker、Invocation 或 workspace。
MemoryCOW 依赖 PreparedRuntime,只在 Linux、单一 exported memory、声明 maximum 等受支持形状下成立。非 Linux stub 直接报告 unavailable。部分 mechanism-selection 或 semantic session 可以在承诺 capacity 前选择 ordinary fresh path;显式 capacity 和普通 Run 的 COW 初始化/clone 失败会 fail closed,不会静默伪装成一次 fresh 命中。
为什么重要
技术上: 多个 fresh consumer 可以共享 sealed linear-memory baseline,减少部分重复页面分配与 runtime_init 路径成本,同时隔离各自的 mutation。每个 consumer 仍要 instantiate 新 module,并执行必要的 _initialize。Engine 用 active lease 阻止 image 在 consumer 仍运行时被关闭。
产品和业务上: 当 Guest 初始化昂贵、并发 fan-out 较多且 Linux worker 支持时,private-COW 可能改善内存密度和启动成本。是否值得启用仍取决于 clone、page fault、初始化和 cleanup 的真实经济性。
不能推出什么
- Private-COW 不保存 Python frame、完整 heap、module globals/tables、WASI handle、Broker state 或 native extension state。
- 它不是 workflow continuation、checkpoint/restore 或跨平台能力。
MAP_PRIVATE是既有 Linux substrate;论文主张依赖的是 Host-owned authority 与 fresh-consumer lifecycle,不把 COW 本身包装成新创新。- Prepared Family v1 已把 bounded NumPy input/private consumer 做成显式 opt-in API,但仍不是通用 object ABI、scheduler 或性能默认项。
术语卡
- Prepared runtime:初始化完成但尚未服务请求的 runtime instance 或 baseline。
- Linear memory:WASM module 使用的连续字节地址空间。
- memfd:Linux 中由文件描述符持有的匿名内存文件。
MAP_PRIVATE:写入时产生私有页面、不修改 backing image 的映射方式。- Private-COW:多个 consumer 共享只读基线、修改时各自复制页面的机制。
继续阅读
- 前置:Reuse 不是一个通用 Cache
- 后续:Prepared Family 到底共享什么、WASM 与 native 两条执行 lane
- 说明文档:
implementation/08c-private-cow-and-prepared-runtime.md、implementation/05-reuse-taxonomy.md - 源码 owner:
runtime/engine/wazero/cow_memory_linux.go、runtime/engine/wazero/cow_runtime_linux.go、runtime/engine/wazero/engine.go、runtime/engine/wazero/prepared_family.go