Day 3·1 mmap直挂权重为什么只要1.2秒

简介: 本文实测RK3588板端冷启动仅1.0–1.2秒,核心在于mmap直挂VQF权重文件:不全量读取,仅映射+校验头部,权重页由内核按需缺页加载,配合预量化布局,较safetensors全量读快33倍。(239字)

真机实测通过:本文实验已在 RK3588 板端实测完成(2026-09;方法学与原始记录见仓库 docs 与《实验脚本》目录)

一句话导读:mmap 直挂的权重加载设计:解释冷启动快不是读得快而是建立映射、权重页由内核按需缺页载入,拆 vqf.c 里 vqf_load 头指针即映射首地址的三步,落点在 VQF 与 safetensors 两条加载路线的计时对照。

Day 1 我们说"冷启动 2 秒",Day 2 我们钉死了文件布局(_Static_assert)。今天把这两件事接起来:几 GB 的权重是怎么在一秒多里"进"到进程的? 答案不是"读得快",而是根本没读——mmap 直挂。

1. 知识点:mmap 为什么快,快在哪里

先想一个问题:一个 2.3 GB 的权重文件,冷启动只用了约 1.2 秒加载。eMMC 顺序读大约 300–500 MB/s,2.3 GB 全量读一遍至少要 5–8 秒——光是 I/O 就不够。所以引擎一定没有"全量读"。

mmap(内存映射)的做法是:把文件映射进进程地址空间,内核给你一段"看起来像内存"的区段。映射本身只建立页表关系,不搬数据;真正把磁盘页读进内存,发生在你第一次访问那个页的时候(缺页中断,由内核按需加载)。

对推理引擎来说,这带来两个质变:

  1. 加载 = 建立映射 + 校验元数据,不是搬运权重——时间只花在头部那几百字节和目录上;
  2. 权重页按需进入:推理从第一层开始读,内核就只提前取那一部分;而且同一文件被多次运行共享页缓存,第二次启动更快。

对比"读文件"路线:malloc 一块内存 → fread 全量搬 → 解析 → 量化——每个字节都要先经 CPU 拷一遍,还要自建缓存。mmap 让内核替你当"搬运工 + 缓存管理员"。

(一个关键细节:mmap 之后 malloc 出来的 memcpy 不需要了,但布局必须逐字节正确——因为磁盘字节就是进程字节,没有"读进来再纠正"的机会。这就是 Day 2 三道 _Static_assert 存在的理由。)

2. 对应代码:vqf_load 的三行"快"

打开 src/model/vqf.c 的 vqf_load(第 549 行起),加载核心就几步:

int vqf_load(STModelWeights *w, const char *path) {
   
    st_mmap_t m;
    /* ... */
    if (st_mmap_open(&m, 0, path) != 0) {
             /* (1) mmap 整文件 */
        fprintf(stderr, "[VQF] mmap failed: %s\n", path);
        return -1;
    }
    if (m.len < sizeof(VQFHeader) + sizeof(VQFTensor)) {
    ... }
    const VQFHeader *h = (const VQFHeader *)m.data;  /* (2) 头 = 映射首地址 */
    if (h->magic != VQF_MAGIC)   {
    st_mmap_close(&m); return -1; }
    if (h->version != VQF_VERSION) {
   
        fprintf(stderr, "[VQF] version %u unsupported (need %u)\n", ...);
        st_mmap_close(&m); return -1;
    }
    /* ... 校验 flags / 布局一致性 ... */

注意 (2):头指针就是 m.data,没有 memcpy、没有反序列化。后续所有权重指针都通过 vqf_mount(base, off)(第 545 行)在映射上取址——权重"驻留"在文件里,进程只是拿到了一组指针。

文件第 641–646 行的注释把这个取舍说得很透:

/* 默认跳过整文件校验:转换时已 self-check 通过,位级一致由构造保证;
 * mmap 页由内核按需加载,整文件校验会把 4GB 从 eMMC 全量读一遍
 * (~20s),直接抵消 mmap 的加载收益。设 VLLM_VQF_CHECK=1 才校验 */

这段注释本身就是论点:全量读一遍要 ~20 秒(4GB 量级),这正是"读文件路线"的成本量级。

3. 改动后果:同机同模型,两条路线实测对照

在板端(RK3588 / Orange Pi 5 Plus,模型目录里同时躺着 model.safetensors 4.25 GB 与预量化好的 model.vqf 2.33 GB),我们给引擎两条加载路线各掐了一次表:启动服务 → /health 返回 200。引擎每次自动加载会打印 [SERVE] auto-load: loading model ...,就绪打印 [SERVE] model ready: ...。

路线一:VQF + mmap 直挂

./vllm_kestrel --serve --port 18091 --model /mnt/emmc/Modl/Qwen3-VL-2B-Instruct \
               --load-format vqf --auto-load &
# 轮询 http://127.0.0.1:18091/health 直到 200

板端实测(2026-09,页缓存已热):

[1] elapsed=1.00s  health=200   [SERVE] model ready: ... (wmode=0, vision=1)
[2] elapsed=1.21s  health=200   [SERVE] model ready: ... (wmode=0, vision=1)

路线二:safetensors 全量读路线(同一模型、同一进程语义,只换 --load-format safetensors):

[st] elapsed=36.65s  health=200   [SERVE] model ready: ... (wmode=0, vision=1)

约 33 倍差距(36.65s vs ~1.1s)。诚实地说清这个对照包含了两个因素:

  1. VQF 是预量化格式,加载只需取指针;safetensors 路线要在加载期全量读入、重新量化成引擎布局(CPU 密集);
  2. 文件大小也不同(2.33 GB vs 4.25 GB)。

但这两点正是设计本身:VQF 把"量化"这个最贵的活从每次启动挪到一次性转换期,再用 mmap 把"搬运"交给内核。

仓库基准报告里冷启动口径是 2.01s(spawn→HTTP ready,重复 3 次中位),加载段 1175ms;本机页缓存热时我们测到 1.0–1.2s 即可就绪——冷/热缓存差就是 mmap 按需加载的直接证据(基准报告还给了对照:safetensors 路线的记忆基线 22–37s,与我们的 36.65s 落在同一区间)。

若你想亲手复现"把 mmap 换成全量读":不需要改代码——引擎的 --load-format safetensors 就是这条路线(运行时全量读 + 量化)。想隔离"纯 I/O"成本,把 VLLM_VQF_CHECK=1 打开再加载一次,引擎会按注释所说把 2.3GB 全量扫一遍校验,你会看到加载时间从 ~1s 涨到十几秒。

4. 学员调试任务

  • A 档(板端动手):
    1. 找到你板上的 .vqf(或 .safetensors),记录文件大小;
    2. 复现两条路线计时(脚本要点:后台起引擎 → 轮询 /health 到 200 → kill),各跑一次,记录 elapsed;
    3. 连续跑两次 VQF 路线,观察第二次是否更快(页缓存命中),这正是 mmap 的按需加载在说话。
  • B 档(纯读源码):读 vqf.c 的 vqf_load 全文,画一张"文件 → 页表 → 进程地址空间"的图,标出哪几步是 CPU 干的、哪几步是内核干的。

预期输出:你能解释"mmap 不是读得快,是没读",以及"为什么 VQF 预量化 + mmap 直挂能把 36 秒压到 1 秒"。

收尾

  • 本篇源码点名:vqf.c(vqf_load 第 549 行起;VLLM_VQF_CHECK 注释第 641–646 行)、st_mmap_open(vllm_platform.h)。
  • 开源仓库:Kestrel-LLM (Gitee)(源码可得双许可:学习 / 学术研究免费)

关键词:mmap、权重加载、VQF、按需加载、RK3588

下篇预告:映射进来的是一串字节,而字节的"顺序"由谁说了算?下一篇 3-2 讲字节序纪律——我们把真实文件的 version 字段改了个字节序,引擎立刻翻脸。

上一篇:Day 2·3 设备画像实战:识别RK3588而不是靠猜CPU型号

下一篇:Day 3·2 字节序踩坑实录:大端序与小端序的数值灾难

相关文章
|
12天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
7926 15
|
10天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
1737 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
11天前
|
人工智能 并行计算 PyTorch
秋叶 ComfyUI 2026 整合包 v3.2 完整部署教程:Python 3.13 + Torch 2.13 全栈升级
秋叶aaaki ComfyUI 2026年8月整合包v3.2正式发布!全面升级Python 3.13.11、PyTorch 2.13.0+cu130及ComfyUI v0.30.2,原生支持MiniMax H3、Wan 2.2、Qwen-Image-2.1等2026主流音视频/图像模型,解压即用,无需环境配置。
1734 11
|
9天前
|
人工智能 编解码 并行计算
MiniMax-H3 一键整合包技术文档:8G 显存运行 AI 漫剧制作 —— 角色替换 / 动作迁移 / 文图生视频部署与调参指南
MiniMax H3 是 MiniMax 开源的全模态视频生成模型,支持文/图/音/视多条件输入,输出最高2K、15秒带双声道音频视频。本文档详述其Int8量化版在8GB显存下的本地一键部署、三段式工作流(EDIT/REPLACE/CONTINUE)、参数调优及常见问题排查。(239字)
|
24天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
3789 10
|
19天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
1990 1