PPysolate SpineREAD THE CODE · UNDERSTAND THE SYSTEM
章节目录
LEARNING NOTES / 04

可选:Prepared full-copy

只讲干净基线与私有副本,不是真 COW。

面试准备以 PLM 为主。这里用一个短的全量复制实现交代“干净基线 → 私有 Guest”,不做 Linux COW,不做性能测量,也不把真实共享页留作必须完成的任务。第一次学习可以先跳过本章。

运行

go run ./cmd/demo -prepared-copy
# {"item": "book", "total": 42}
go run ./cmd/demo -source examples/order.py -prepared-copy -plm
# {"item": "book", "total": 47}
go run ./cmd/demo -source examples/order.py -prepared-copy -prefix
# {"item": "book", "total": 47}

-prepared-copy 只选择 Guest 的创建方式;PLM、prefix、工具注册、结果交付、Future 和取消仍是原有路径。默认不加这个参数时仍采用 fresh 初始化。

只读 prepared.go

prepared.go 只有两个核心函数:

  • NewPrepared:先像 New 一样建立 runtime/编译代码;创建一个参考 Guest,运行 _initialize 和 CPython init;把此时的整份线性内存复制到 Runner 私有的 image,关闭参考 Guest。不运行用户代码,也不开放自定义 warmup 脚本。
  • newGuest:为每轮创建独立 Wasm 实例和 I/O,调用 _initialize。fresh 模式继续调用 CPython init;prepared 模式将内存增长到基线长度,然后用 Memory.Write(0, image) 全量复制,跳过再次调用 CPython init
NewPrepared: 参考 Guest → init 完成 → 复制为 Go image → 关闭参考 Guest
每轮运行:    新 Guest → _initialize → 全量复制 image → 普通 / PLM / prefix

为什么在 _initialize 之后复制?实例化的 data segments 和运行库初始化会写内存。先复制再初始化,可能覆盖已准备的状态。

Runner.image 从参考内存复制得到,不借用已关闭 Guest 的切片;实例的 Memory.Write 又复制一份,所以实例之间和基线之间没有可写别名。Runner.Close 释放对 image 的引用。关闭必须发生在本 Runner 的所有 Run 返回之后,与原有约定相同。

full-copy 与 COW 的区别

  • 当前 full-copy:每个实例付出整份内存复制和私有存储,借此说明基线恢复及写入隔离。
  • 真正 COW:可共享尚未修改的物理页,写入时才分离。当前没有 memfdMAP_PRIVATE 或页共享。
  • 两者都可以让程序看到私有状态,但不能据此声称内存成本或启动性能相同。本项目没有测这些指标。

Go 的 runState、Host 工具、Future 和 prefix producer 不放进 image。基线是在任何用户源码、inputs、工具调用和 prefix 接收之前捕获的;复制一个已经带请求数据的运行中 Guest 不是这里支持的操作。

范围:不是通用 Wasm checkpoint

只支持本仓库固定 Guest 在干净 init 返回后的内存基线,不捕获任意执行栈、Wasm globals/tables 或 Host 文件描述符等外部状态。新实例自己的 _initialize 和静态初始化仍然执行。

当前 artifact 的这个静止初始化边界已通过真实执行验证。若以后增加会改变这些边界的 Guest 初始化、外部资源或可变非内存状态,要重新判断能否这样复制;不为未发生的需求预建通用 snapshot 框架。

本轮没有改 Guest 源码或打包方式,沿用阶段 3 的真实 Wasm;实现和验证在本机 macOS 完成,不需要 Linux 工具或本地 WSL。

测试在回答什么

prepared_test.go 检查基线真实存在、捕获没有调用 Host 工具,并有 7 个真实 Guest 子测试:

  1. 普通 Host 工具返回值正确。
  2. 一轮修改 builtins,下一轮看不到。
  3. 两个同时存活的实例:写一个实例的内存不改变另一个,也不改变 image。
  4. PLM 的独立工具仍能用启动信号握手证明重叠。
  5. prefix 的工具仍在源码 EOF 前启动。
  6. Python 错误不改变后续实例的基线。
  7. 中止无限循环后,下一轮仍正常。

这是功能和生命周期检查,不是复制速度/内存 benchmark。