30行代码改了两年,文件打开快39%:Linux 7.4这波优化,你能吃到多少?

源自210位全网作者

09-27 13:20

这几天内核圈有个组合数字反复出现:三十行代码、两年时间、39%。事情本身不复杂——一个只有三十来行改动的补丁,让 Linux 内核打开文件的速度在基准测试里提升了 39%,预计随 Linux 7.4 落地。 真正让它出圈的,是"三十行代码为什么要改两年"这个反差。知乎

这条消息在知乎、B站和 Phoronix 上都刷了一轮。B站上解读这条新闻的视频播放四千多、七十几条评论,最高赞的一条是:“怎么 Linux 一直在优化?把微软都衬托得不知道在干啥了…这保真吗”。 但真正值得回答的,是另一条只有两个赞的留言:“这个反应到真实性能上应该没这么多吧”。哔哩哔哩

这句朴素的话,比"39%"更接近真相。这篇就把这个补丁掰开讲清楚:它到底改了什么、39% 是什么口径、为什么三十行代码要改两年,以及最重要的——你的负载能不能吃到这口提升。

三十行代码改了什么:一次"多此一举"的刷卡

先补一个背景。你的程序打开一个文件,比如 `/home/user/project/main.c`,内核并不是一步拿到文件的。VFS(虚拟文件系统)要把路径逐级拆开:`/` → `home` → `user` → `project` → `main.c`,一级一级解析,每一级对应一个目录项(dentry),最后才定位到文件的 inode。这个过程叫路径遍历,`do_open()` 就是这条链路上的关键函数。

问题出在一次"多此一举"上。按补丁解读文章的说法,打开一个文件的过程中,`__legitimize_path()` 先对 dentry 获取一次引用,接着 `do_dentry_open()` 又获取一次,最后 `terminate_walk()` 再把引用释放。 相当于进门刷了两次门禁卡、出门只退了一张。而每次"刷卡"——引用计数的获取和释放——都是要对共享内存做原子操作的,多核机器上这恰恰是最容易打架的地方。知乎

修法说出来几乎有点好笑:`do_dentry_open()` 直接复用已经拿到的那次引用,不再重复获取,前后改动三十来行。收益是:在一台 20 核虚拟机上跑 will-it-scale 基准,打开文件的操作数每秒提升 39%。知乎哔哩哔哩

39% 是实验室数字,到你机器上大概率打折

把结论放在前面:39% 是微基准数字,不是"你的电脑快了 39%"。

will-it-scale 这类基准的设计目的,就是把内核的某条单一路径推到极限——让所有 CPU 核心疯狂地只做 open() 这一件事,CPU 时间几乎全花在路径解析和引用计数上。在这种环境里,引用计数开销被放到最大,优化它自然立竿见影。这和"百公里油耗 3.8L"是实验室工况一个道理。

真实应用里,open() 只是几十种系统调用中的一种,多数程序打开文件后要读、要写、要算,open 的时间占比被大幅稀释,所以评论区那句"反应到真实性能上应该没这么多吧"的判断是对的。 但你也不能因此说它没用,关键看你的负载长什么样:哔哩哔哩

  • 能吃到比较多的:海量小文件打开型负载。典型场景是编译(一次内核全量编译要打开几万次头文件)、包管理器装依赖、CI 流水线、静态资源服务、爬虫建索引、容器冷启动。它们的共同点是 open() 密度极高,路径解析就是主要开销之一。

  • 基本无感的:打开一次文件读几个小时的负载。数据库大文件扫描、视频转码、GPU 计算这类,open 在总耗时里可以忽略不计,39% 乘以一个千分比,还是千分比。

一个不用升级就能自查的办法:用 `strace -c -f -p ` 挂你自己的服务看一眼,如果 open 族调用在系统调用统计里排前几、每秒几千上万次,这类优化就是在给你省钱;如果 open 占比不到 1%,这个补丁跟你这波没关系。

为什么三十行代码要改两年

这是整件事最有意思的部分。补丁作者 Guzik 解释过原因,概括起来是:这是 Linux 内核、路径遍历在无数场景被用到、语义上必须保持正确、还得做基准测试。 展开说一层。引用计数是内核里"最便宜也最贵"的机制:写一行 `refcount_inc()` 便宜,错一个方向就是 use-after-free 或者引用泄漏——前者是安全漏洞,后者是慢性内存泄漏,都可能在几个月后才炸。而路径遍历是所有文件操作的必经之路,全系统没有几条代码路径比它跑得更频繁。在这块代码上动引用计数,等于在早高峰的地铁站里换地板砖。知乎

B站评论区一位从业者说得实在:“路径遍历那东西大家其实都不想碰……”。 这句话解释了另一个问题——为什么这种"看上去简单"的低垂果实到现在才摘:不是没人看得懂,而是这块代码的风险收益比太差,没人愿意为了 39% 的微基准收益去赌一个引用计数 bug。直到这次有人愿意把两年的 review、五次修订和全套基准测试做扎实,它才进得了主线。哔哩哔哩

所以这三十行代码的两年,改的不是代码,是证明。这也是内核开发和一个普通业务项目最不一样的地方:代码量从来不等于工作量,证明"改了之后全世界都没事"才是工作量大头。下次再看到"XX 行代码优化内核 XX%"的新闻,先看它花了多久、改了几版,你对它的信任度校准会更准。

顺手看一眼 7.4 还有什么

这次围绕 7.4 的报道里还有几条值得记下的:

  • Rust 的存在感继续变强。同一轮 Linux 周报里提到,Rust 已经进入 Android 的 Binder 驱动,Ubuntu 的核心工具集也在 Rust 化。 不过要留意分寸:内核社区的主流口径始终是"不主张用 Rust 重写内核,只支持新代码用 Rust 写"。 Android 侧则已经有数百万台手机跑着 Rust 内核代码。 评论区问"Linux 什么时候用 Rust 重写"的朋友,短期内不用期待。哔哩哔哩知乎知乎专栏

  • 文件操作与编译速度的整体提升。do_open 补丁之外,7.4 在文件操作和编译速度上还有别的性能改动,方向一致。

  • Btrfs 修复了一批回归。用 Btrfs 的 NAS 用户可以关注发行版的更新说明。

不同的人,接下来该做什么

  • 滚动发行版用户(Arch/Fedora):最快吃到的群体。等 7.4 正式发布进了仓库跟着升就行,不建议拿 rc 内核上生产机。

  • 服务器/云主机:别只看新闻标题做决定。先用 strace 数一下自己服务的 open 密度;编译农场、对象存储网关、CI 集群这类高密度 open 的服务,值得在 7.4 稳定一两个月后做一次内核版本 A/B,看真实吞吐变化。

  • 嵌入式 Linux:大多数项目还锁在 6.1/6.6 LTS 上,这个补丁短期内不会 backport 到 LTS。按原计划走,不要为一个微基准数字切换内核版本——那是高风险动作。

  • 应用层开发者:说句可能让你更舒服的话——与其等内核,不如先减少自己程序的 open 次数:复用文件描述符、缓存已解析的路径、避免循环里重复打开同一个文件。应用层这种改动带来的收益往往是一个数量级的,比内核替你省的零头多得多。

值得继续盯的三个信号

  1. 7.4 正式发布后的全系统实测:Phoronix 惯例会跑全量基准,到时候看 open 密集型场景(编译、打包)能兑现几成。

  2. 编译时间的真实数据:内核编译本身就是最好的 open 密集型测试,社区大概率会有人贴 7.3 vs 7.4 的编译时间对比。

  3. 会不会 backport:一旦这个补丁被回移到稳定分支,LTS 用户的时间表就得重算,嵌入式团队尤其要留意。

最后留个话头:你机器上最"吃 open()"的服务是什么?评论区说说,等 7.4 落地,正好一起验证这 39% 能兑现几成。

内容由AI生成
0
扫一下,分享更方便,购买更轻松
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

最新文章 热门文章