本期检索说明
先读取 content/collections/deep-radar 截至 2026-09-11 的全部原文链接,并按 URL、标题与问题语义去重。最近 24 小时内,Tokio 的 I/O driver 分片草案同时公开了实现、Criterion、线上负载矩阵和失败边界;Linux kbuild 的 23 补丁系列原始发布于 9 月 8 日,9 月 11 日经 LWN 深入分析后进入本期视野,补丁线程又包含多台机器的独立复测,因此纳入最近 7 天窗口。
本周期内 Java/JVM、Kotlin 与 Zig 没有发现同时满足“实测数据、源码或汇编证据、原理剖析”三项标准且未被历史报告收录的新材料。OpenJDK RISC-V C2 与 Kotlin/Native memory dump 的新改动都有工程价值,但没有公开 benchmark,故不以推测补位。本期只收录 2 篇。
| 主题 | 原始发布日期 | 一手来源与交叉验证 | 截稿状态 | 推荐强度 |
|---|---|---|---|---|
| Tokio 多 epoll I/O driver 分片 | 2026-09-12 07:16(中原标准时间) | Tokio PR #8450 / 2 个提交 / Criterion / 3 组服务负载 / strace / 回归测试 | Open,未合入 | 必读 |
| Linux kbuild 关键路径并行化 | 2026-09-08 | LKML 23 补丁 / 3 台作者测试机 / EPYC 独立复测 / LWN 分析 | RFC v1,未合入 | 必读 |
01 · Tokio:一个 runtime 不必让所有 I/O 都排队经过同一个 epoll
原文与日期: so-ant,2026-09-12 07:16(中原标准时间);tokio-rs/tokio PR #8450。截稿时包含 2 个提交,仍开放且尚无正式 reviewer,不应把结果写成 Tokio 已采用的默认行为。
为什么值得读: 多线程 runtime 即使有很多 worker,单个 epoll 实例仍留下三类共享瓶颈:同一时刻只有一个线程阻塞在 epoll_wait;读取 /proc/<pid>/fdinfo/<epfd> 会持有 epoll mutex 遍历全部 socket,从而阻塞 epoll_ctl;多个 CPU 上的 receive softirq 又会在 ep_poll_callback 争用同一个 ep->lock。这个 PR 没有只给“多开几个 epoll”的结论,而是完整处理了 worker 分组、socket 归属、定时器唤醒、饱和批次、driver 交接和故障组兜底。
核心技术结论: Builder::io_shards(n) 为多线程 runtime 建立 n 个 mio Poll,worker 被分成连续的 n 组,新 socket round-robin 分配,ScheduledIo 记录所属 shard。默认仍为 1,syscall 与现行 Tokio 相同;环境变量默认值会保证每个 shard 至少约 8 个 worker,小于 16 个 worker 的 runtime 不自动分片。
难点不是拆表,而是保证每个 shard 持续有人 poll。worker 阻塞前先零等待轮询自己的 shard,再帮助“超过半个 sweep interval 未被 poll”或“上次事件缓冲已满”的 shard;若 driver 已被占用,worker 进入该 shard 独立的 standby 队列,持有者离开时只唤醒同组接班人。默认每 10 ms 强制一次 sweep,繁忙 runtime 还有 10 倍 interval 的 maintenance backstop。代价同样明确:所有 shard 共享一个 timer wheel,所以每个 deadline 仍会唤醒全部 driver;signal、child reaping 与 io_uring completion 也暂时只留在 shard 0。
Runtime
├─ worker group 0 ─ epoll shard 0 ─ socket 0, 4, 8 ...
├─ worker group 1 ─ epoll shard 1 ─ socket 1, 5, 9 ...
├─ worker group 2 ─ epoll shard 2 ─ socket 2, 6, 10 ...
└─ worker group 3 ─ epoll shard 3 ─ socket 3, 7, 11 ...
shared: timer wheel
shard 0 only: signal / child process / io_uring completion最有价值的实验、源码与 benchmark 细节: 32 worker/32 core 上注册再释放 6,400 个 UDP socket,8 shards 把 Criterion 中位耗时从 18.3 ms 降到 8.7 ms,下降约 52.5%。保留 20,000 个空闲 socket、同时循环读取各 epoll fdinfo 时,从 376 ms 降到 39.6 ms,约为原来的 10.5%。150,000 长连接、每 2 秒读取一次 fdinfo 的服务中,新连接首帧 p99 从 135–139 ms 降到 25 ms。180 worker、64 TCP 连接时 8 shards 的吞吐提升 20%,但约 32 worker 以下没有收益。
作者还保留了负向结果。15–16 worker 的正常 400 req/s 服务从 9.4 core 增到 9.6 core,而 TTFB 仍为 14.5 ms;1.7 倍过载时 p50 只从 1.06–1.11 s 变为 1.01–1.04 s。非阻塞 sweep 原本只取 busy batch,10,000 conn/s 风暴下会让首字节恶化到 80–105 ms;改成“两次连续饱和后用一次 full batch”才恢复到 25 ms。若只检测一次饱和,2 shards 在 1.7 倍负载下 p50 反而从 1.0 s 恶化到 4.0 s。这组反例说明 drain aggressiveness 不能只按队列是否满来判断,还必须防止普通请求过载吞掉公平性。
测试同样揭示尚未闭合的边界:4 worker 真正拆成 4 shards 后,依赖“空闲 runtime 恰好只 park 一次”的 metrics 断言失败;楔住 3/4 worker 的 yield_now 测试也会间歇失败,因为 yield 只帮助自己的 shard 与 10 倍 interval backstop。Loom 测试虽绿,但 Loom 构建不包含 I/O driver,所以没有覆盖 shard handoff 与 sweep。timer 单点唤醒原型能把 8 shards、1 ms interval 的空闲 context switch 从 13.6k/s 降到 1.7k/s,不过还不在本 PR 中。
适合的工程师背景: 熟悉 Tokio/mio、epoll、软中断与高连接数代理,正在排查注册锁争用、host agent 读取 fdinfo 或多核 I/O 扩展性的 Rust 工程师。
预计阅读收益: 约 70–100 分钟;能得到一套“把单驱动器拆成多 shard”时的工程检查表:所有权、poller 交接、过期检测、事件批次、公平性、共享 timer 与失败组兜底,并学会用正常负载、过载、连接风暴和观察代理四种环境分别验证。
02 · Linux kbuild:并行编译之后,真正的瓶颈藏在单线程收尾
原文与日期: Lorenzo Stoakes(ARM),2026-09-08;LKML 23 补丁系列与完整讨论。交叉验证来自 2026-09-11 的 LWN 分析 与 Phoronix 摘要。系列共修改 47 个文件,新增 2,884 行、删除 682 行;截稿时仍是 v1,不能把 benchmark 当成已进入主线的保证。
为什么值得读: make -j 只解决了可并行的编译单元,最终链接、kallsyms、modpost 与 objtool 仍会形成长串单线程关键路径。作者没有换编译器或减少配置,而是逐段 profile 构建图:删掉无意义排序和 relocation、将 shell/nm 管线变成直接 ELF 解析、缓存重复状态、批量化细碎进程、用线程池并行 srcversion 与 objtool,再让 Rust frontend/crate 构建与 C 工作重叠。这些方法同样适用于大型 C/C++ monorepo 与任何“前半段并行、尾部突然塌成单核”的构建系统。
核心技术结论: 23 个补丁分成六条互相叠加的路径。kallsyms 按 token 建索引、输出二进制数据,并用 C 版 mksysmap 直接读取 ELF symbol table;kbuild 不再为无关输出排序 nm,trial link 只在需要时携带 vmlinux relocation,并用新的 C depcheck 缓存 object/composite 状态与比较依赖时间戳;compiler/linker capability 只在顶层 probe 一次。
modpost 把 module source 从逐字节 hash 改为逐文件,缓存 section relocation mismatch,直接生成 .mod.S,再把数万个很小的 module finalisation 进程合批,并行计算 srcversion。objtool 避免把数百万 DWARF relocation 塞进 hash,缓存 dead-end,把 instruction decode 与 branch target resolution 分给多个线程。Rust 侧并行 frontend、修正生成 header 依赖,并让 crate 与其余 C 编译并行;最后在系统提供时用 pigz 替代串行 gzip。
原构建尾部:ld -r vmlinux.o → modpost → objtool → kallsyms/link → module finalise
单线程关键路径,其他 CPU 大量空闲
系列之后: 缓存/直接 ELF 解析 + modpost/objtool 线程池 + module 批处理
Rust frontend 与 C 编译重叠 + pigz最有价值的实验、源码与 benchmark 细节: 作者在 64 核/128 线程 Threadripper 9980X、双路 256 核/512 线程 EPYC 9754 和 8 核 M2 上取多次运行的最好值。allmodconfig 全量构建中,Threadripper GCC 从 345.3 s 降到 275.2 s(-20%),EPYC GCC 从 188.6 s 降到 121.1 s(-36%);Clang 分别改善 23% 与 29%。增量构建更能体现关键路径收益:Threadripper GCC 46.4→15.3 s(-67%),EPYC GCC 82.0→24.3 s(-70%)。no-op 构建则从 12.97→1.18 s 与 25.92→1.52 s,分别下降 91% 与 94%。
较小的 defconfig 也没有被大机数据掩盖:M2 GCC 全量只改善 9%,但增量从 18.6→9.9 s(-47%),no-op 从 5.59→1.69 s(-70%)。Threadripper 上 ld -r vmlinux.o、modpost、objtool 组成的中段关键路径从 23 s 降到 7 s,剩余 6 s 几乎全由 objtool 占据,直接指出下一处优化上限。讨论中 Florian Fainelli 又在 AMD EPYC 9454P、arm64 defconfig、make -j97 上独立复测,约改善 13%,说明收益并非只存在于作者的两台 x86 大机。
正确性验证覆盖 arm64、arm、riscv、powerpc64、s390 与 loongarch 的 allmodconfig;多个架构的新旧 System.map 相同。x86、arm64、arm、riscv、loongarch、powerpc64、s390、m68k 与 parisc64 内核均在 QEMU 启动,重定位后的 text symbol 能在 /proc/kallsyms 找到,module 可装卸。负向边界也应保留:测量取多次最好值而非分布;Linus 对方向表示积极,但 Rust 并行补丁还不成熟,objtool 变更需要其维护者单独审查;作者明确披露 LLM 参与定位与生成,代码经过人工重写和验证,并在每个提交保留 Assisted-by。
适合的工程师背景: 维护 Linux/kbuild、objtool、modpost、Rust-for-Linux,或负责大型原生项目构建性能与 CI 周转时间的工程师。
预计阅读收益: 约 90–130 分钟;可以学到如何从构建 DAG 识别串行关键路径,把“少做工作、缓存、合批、直接解析、并行化、跨语言重叠”分层落地,并用全量、增量、no-op 和多架构启动分别约束性能与正确性。
中国大陆 ToC 硬件价格观察
数据口径
窗口为 2026-08-14 至 2026-09-12,单位人民币。六类硬件继续固定同一 SKU。9 月 12 日复核时,六个既有公开比价入口仍不能同时给出同型号、同渠道、带当日日期的可核验新报价;搜索结果中的海外价格、不同型号与没有日期的商城列表均未采纳。因此本期不新增数据点,也不把旧值复制为今日行情。图表以 9 月 12 日为窗口终点,折线只连接 JSON 中真实采样日,空白尾段代表缺少证据而非横盘。
| 类别 | 固定样本与最后可复核价 | 30 日窗口内真实走势 | 建议 |
|---|---|---|---|
| CPU | Ryzen 7 9800X3D,最后可核验 9/9 ¥2,449 | 8/21 ¥2,609 → 9/9 ¥2,449,-6.13%;末次采样下降 ¥140 | 可关注入手;窗口新低已形成,但下单前须重新核对盒装/散片与保修 |
| GPU | MSI RTX 5070 VENTUS 3X 12G,最后可核验 9/10 ¥4,464.34 | 8/29–9/10 五个真实点均为 ¥4,464.34 | 继续观望;样本横盘,且 7 月中国区渠道调价提高了上行风险 |
| 主板 | ASUS TUF B850M-PLUS WIFI7,最后可核验 9/8 ¥1,299 | 8/31 ¥1,449 → 9/2–9/8 ¥1,299,-10.35% 后横盘 | 刚需可入;付款前复核 WIFI7 版本、店铺与售后 |
| DRAM | Kingston FURY Beast DDR5-6000 32GB,最后可核验 9/9 ¥3,900 | 9/2 ¥3,900,9/5 ¥3,860,随后回到 ¥3,900 | 刚需小量买;没有形成连续下降趋势,不据缺失日期预测回落 |
| HDD | IronWolf Pro 8TB ST8000NE001,最后可核验 9/10 ¥1,849 | 9/1–9/10 五个真实点均为 ¥1,849 | 按容量刚需购买;固定样本横盘,优先比较五年保修与数据恢复服务 |
| SSD | ZHITAI Ti600 2TB,最后可核验 9/10 页面最低 ¥749 | 9/2 ¥1,919 → 9/5–9/10 ¥749;同页不同渠道价差显著 | 谨慎核验后入手;先确认容量、颗粒、保修与商家,不能把聚合最低价视为全市场跌幅 |
价格来源: 9800X3D、MSI RTX 5070 VENTUS 3X、ASUS TUF B850M-PLUS WIFI7、Kingston FURY DDR5-6000 32GB、IronWolf Pro 8TB、ZHITAI Ti600 2TB。GPU 供给判断继续参考 2026-07-27 的中国区 RTX 50 系列渠道调价记录。
判断依据
CPU 与主板已有明确的台阶下降,刚需可以围绕最后有效价设置到手价阈值;GPU 与 HDD 的固定样本没有下降证据,DRAM 只出现一次短暂低点。SSD 的聚合低价与其他渠道差异过大,购买建议必须附带规格和商家核验。由于连续两天没有新采样,本文不把空白尾段解释为价格稳定,也不基于不可见库存预测继续下跌。
其它你可能关心的
- OpenJDK RISC-V C2:融合 ConvI2L 与 32 位取负、除法和余数
- Kotlin/Native:memory dump 可省略 payload、gzip 压缩并用子进程写出
- Linux 页分配器:避免带小阶 fallback 的高阶
__GFP_NORETRY进入同步 compaction
本期结论
两篇材料都说明“已经并行”不等于共享瓶颈消失。Tokio 的 worker 很多,但所有 readiness、注册和观测仍可在一个 epoll 上串行化;kbuild 的编译单元很多,但链接、modpost 与 objtool 仍决定尾部关键路径。可迁移的方法是先用外部干扰与时间线找到真正的串行点,再组合分片、缓存、合批与有限并行,并用反例约束公平性、空闲成本和正确性,而不是只展示最快的一组数字。