Skip to content

Windows:小块同步写盘快约 1.5 倍(virtio-blk 关掉 ioeventfd,给客体一张 _CST 表) - #116

Open
qiyinxi wants to merge 2 commits into
ModAVD:mainfrom
qiyinxi:perf/whpx-sync-io
Open

qiyinxi wants to merge 2 commits into
ModAVD:mainfrom
qiyinxi:perf/whpx-sync-io

Conversation

@qiyinxi

@qiyinxi qiyinxi commented Nov 10, 2026

Copy link
Copy Markdown
Member

为什么

客体里一次 ext4 fsync 是三个串行的写请求(数据、日志、提交),每个都要等宿主往返一趟。每写一小块就 fsync 的负载就卡在这趟往返上:明日方舟下资源每 7 KB 一次,只有约 8 MB/s(ModAVD/ModAVD#35)。

这趟往返里,真正把数据写进宿主文件只要几微秒,其余都花在等上:

  • WHPX 没有内核里的 eventfd,QEMU 在用户态模拟 ioeventfd,一个请求要在主循环里转三圈、在线程之间交接三次;
  • 客体没有 cpuidle 驱动,等请求完成时直接停机,每次完成都要等 Hyper-V 把停机的 vCPU 叫醒(20–24 µs)。

这个 PR 缩短这两段。完成的条件不变:数据进了宿主文件,请求才算完成。强杀模拟器时能保住的东西和现在一样。

改了什么

  • 开机时在 -qemu 后面多带两个参数(只在 Windows 上):
    • -global virtio-blk-pci.ioeventfd=off:请求由 vCPU 线程直接处理。
    • -acpitable file=..\..\avd\mas_<i>.avd\modavd-cst.aml:一张给每个 CPU 加 _CST 的 SSDT,里面只有一个用 HLT 进入、退出延迟写成 100 µs 的 C1。
      • 客体内核自带的 acpi_idle 驱动和 menu 调度器据此决定:本核有任务在等读写时,先忙等一小段(最多 200 µs)再停机;其余时候照常停机。
      • 表按实例的核数生成,放在实例目录里。QEMU 的 file= 遇到 : 和 , 会切开,文件名又按系统代码页打开,所以用相对模拟器目录的路径传,根目录在哪、带不带中文都一样。
      • 表写不了、实例读不出核数,或者相对路径里有命令行放不下的字符时,不带表照常开机,只记一条警告。
  • 客体自己忙等时,不再起 mas-idlepoll.sh 的忙等守护:开机后读客体的 cpuidle 驱动,是 acpi_idle 就不起。带上表以后那些循环不再加速,却在整段密集写盘期间把每个 vCPU 占满。表没带上时照旧起。
  • MODAVD_SYNC_IO=off:设了这个环境变量再开机,两个参数都不带,行为和改之前一样。
  • README 中英文的「开机后调优」跟着改了。

测试

单测:

  • 表的字节和一个独立写的生成器(Python)逐字节对照:6 核的整张表,另外 5 组核数和延迟对哈希;长度字段、校验和。
  • 相对路径、内容没变不重写、核数变了重写、带逗号或中文的实例目录名不写表、实例目录不存在。
  • 参数拼在 -qemu 部分的最后;读不出核数时只带第一个参数;MODAVD_SYNC_IO=off 时和原来的参数表完全一样。
  • 变异 19 处,全部被测试抓到。「不起守护」的接线没有单测,靠下面的实机确认。

实机(Windows 11,7950X3D,6 核 6 GB 的测试实例,0.39.0 的模拟器,每轮核过客体时钟源是 tsc):

合成负载,用这个分支编出的管理器开机:

仿下载(2 线程,每写 7 KB fsync 一次) 单线程写 4 KiB + fsync 的中位数 跑测试期间 qemu 用的 CPU
MODAVD_SYNC_IO=off 20.5–21.0 MB/s 429 µs 371 s
默认 33.8–34.2 MB/s 344 µs 169 s

明日方舟资源下载(2.7.91,未登录;每轮清掉已下的资源从头下,开始 20 秒后取 150 秒;两种参数交替跑):

各轮 平均 qemu 占的宿主核
MODAVD_SYNC_IO=off 6.94、7.73、7.84 MiB/s 7.50 5.9–6.1
默认 12.07、11.30、11.10 MiB/s 11.49 3.8

其余:

  • 开机时间没变(14–15 秒)。
  • 大块写没有变慢:1 MiB 写 + fsync 300 次,0.74–1.49 s 对 0.74–1.89 s;1 GB 顺序写 258–397 对 181–362 MB/s(各两次开机)。
  • 空闲 40 秒,客体 6 个核合计忙等 0.12 秒。
  • 客体里 current_driver 是 acpi_idle,状态表是 POLL + C1;没有 ACPI 报错;日志有「不起忙等守护」,客体里没有守护进程。
  • 测试期间宿主 CPU 40–85%(同时有别的模拟器在跑)。

试过、没采用的:virtio-blk 多队列。单开反而慢 4 倍(ioeventfd 开着时每个队列一个用户态模拟的通知),配上 ioeventfd=off 以后也没有再快。

没测的

  • 别的游戏的冷启动和帧率。
  • 多开同时下载。
  • 关掉守护以后,单线程的小块同步写比「新参数 + 守护」慢一些(344 对 264 µs),仍比改之前快(429 µs)。
  • 到不了 开机:不用 netsim,整机不再共用一个 netsimd #35 写的 50 MB/s:一次 fsync 还是三趟往返。

Refs ModAVD/ModAVD#35

客体里一次 ext4 fsync 是三个串行的写请求,每个都要等宿主往返一趟。开机时给 QEMU
多带两个参数,往返变短,完成的条件不变(数据进了宿主文件才算完成):

- -global virtio-blk-pci.ioeventfd=off:WHPX 没有内核里的 eventfd,QEMU 在用户态
  模拟,一个请求要在主循环里转三圈、线程之间交接三次;关掉后由 vCPU 线程直接处理。
- -acpitable <每个 CPU 带 _CST 的 SSDT>:客体没有 cpuidle 驱动,空闲就停机,每次
  完成都要等 Hyper-V 把停机的 vCPU 叫醒(20–24 µs)。表里声明一个用 HLT 进入、
  退出延迟 100 µs 的 C1,客体自带的 acpi_idle 和 menu 就会在本核有任务等 I/O 时
  先忙等一小段(最多 200 µs),其余时候照常停机。表按实例的核数生成,放在实例
  目录里,用相对路径传给 QEMU;写不了或路径放不进命令行时不带表照常开机。

只在 Windows 上加。环境变量 MODAVD_SYNC_IO=off 时两个参数都不带。

11-10 在 6 核 6 GB 的测试实例上(0.39.0 的模拟器,带现有的忙等守护):
- 仿下载负载(2 线程,每写 7 KB fsync 一次):20.5–21.0 → 33.3–35.7 MB/s;
- 单线程写 4 KiB + fsync 的中位数:429–436 → 264 µs;
- 1 MiB 写 + fsync、1 GB 顺序写:没有变慢;
- 明日方舟资源下载(各一个 150 秒窗口,相邻):7.3 → 12.3 MB/s;
- 空闲 40 秒里客体忙等合计 0.12 秒。

Refs ModAVD/ModAVD#35
带上 _CST 表以后,客体等读写时自己忙等(acpi_idle + menu),mas-idlepoll.sh 的
忙等循环不再加速,却在整段密集写盘期间把每个 vCPU 占满。开机后先读客体的 cpuidle
驱动,是 acpi_idle 就不起守护;表没带上时(MODAVD_SYNC_IO=off 等)照旧起。

11-10 明日方舟资源下载,6 核实例,各 150 秒窗口,旧参数、新参数交替:
- 旧参数(带守护):6.94 / 7.73 / 7.84 MiB/s,qemu 约 5.9 个宿主核;
- 新参数、带守护:11.75 / 10.36 / 10.91 MiB/s,qemu 约 6.0 个核;
- 新参数、不起守护:12.07 / 11.30 / 11.10 MiB/s,qemu 约 3.8 个核。
仿下载负载不起守护是 33.8 / 34.2 MB/s(起守护 35.7 / 33.3);单线程写 4 KiB + fsync
的中位数 344 µs(起守护 264,旧参数 429–436)。

Refs ModAVD/ModAVD#35
@qiyinxi qiyinxi added enhancement New feature or request platform:windows 与 Windows 平台相关 labels Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request platform:windows 与 Windows 平台相关

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant