硬盘分析工具怎么测才公平?我在 GitHub Actions 上搭了个公开跑分

先说利益关系:我是 SpaceKnife 的作者,SpaceKnife 也在这个榜上,目前总榜第一。测试数据、计时方法和评分规则也都是我写的,作者和参赛者是同一个人,有利益冲突的风险,这一点我承认。(这只是为了声明有关联,该贴为讨论硬盘扫描软件跨平台基准测试的做法,而非任何软件的推荐帖子)

所以我给自己定了两条:

  1. 规则只照着真实硬盘和日常使用的情况来定,不看哪个工具在上面跑得快;
  2. 生成数据的代码、计时脚本、每个工具的版本和命令行、每次运行的日志和原始输出全部公开,欢迎监督,也欢迎开 issue 提建议,有道理就改。

仓库:GitHub - DuskXi/Disk-Scan-Benchmark · GitHub

下面主要聊技术细节,也想听听大家的看法。

为什么要自己搭

在自己电脑上测硬盘分析工具,结果很难复现:盘上的内容、碎片程度、缓存状态、硬件都不一样,换台机器名次就可能变。我想要一个谁都能看着它跑、也能 fork 了自己重跑的榜单,没找到现成的,就用 GitHub Actions 的免费 runner 搭了一个:

  • 平台:Windows / Linux / macOS,x64 和 ARM64
  • 文件系统:NTFS、ReFS、ext4、Btrfs、XFS、ZFS、APFS(Windows 上的 Btrfs 是实验项)
  • 体量:10 万到 900 万个文件,逻辑上 100 GiB 到 3 TiB;另有一档 1400 万文件、塞满 99% 的 4 TB 盘,目前只在 MFT 专栏跑过
  • 16 个扫描器:gdu、dua-cli、dust、ncdu、pdu、diskus、erdtree、SquirrelDisk、WinDirStat、WizTree、SpaceSniffer、Sysinternals du、GNU du、BSD du,以及 SpaceKnife 0.3.5 和 0.3.4

TreeSize Free 没有参加:它的许可证不允许在 Windows Server 上使用,而 GitHub 的 Windows runner 就是 Windows Server。

测试盘:合成的,但尽量像一块用了几年的盘

真实硬盘没法拿来做公开测试:每次内容不同,文件名和路径还涉及隐私。所以用合成文件树。目录树完全由随机种子决定,同一个种子在所有平台、所有运行里一模一样。生成器同时写出标准答案:文件数、目录数、逻辑大小、实际占用、每个区域的明细。

合成数据最大的风险是不像真的。一块新格式化、按顺序一口气写满的卷,目录和文件的记录(NTFS 的 MFT 记录、ext4 的 inode)挤在一起,冷扫时读一块就能顺带拿到一大串有用的记录,比真实盘便宜好几倍。所以生成器默认做「老化」:

  • 每个目录在父目录之后的某个随机时间点创建;
  • 文件拆成 4–64 个一批,分散在目录创建之后的整条时间线上;
  • 大约每 8 个文件旁边建一个临时文件再删掉,留下空洞和可复用的记录;
  • 同一目录里的文件按打乱的顺序创建,避免「名字顺序 = 磁盘顺序」这种真实盘上不存在的巧合。

树分成四个区域,各对应一类真实结构:

  • 依赖目录那样的深链(8–25 层);
  • 浏览器缓存那样的大目录;
  • 视频、虚拟机磁盘那样的大文件;
  • 硬链接、符号链接循环、超长路径这些边界情况。

生成算法的取舍只用一个标准:生成出来的结构和磁盘布局是不是更接近真实盘。每次生成后都会测一组布局指标,和真实盘的同一组数字对比:

  • 同一目录下的记录号有多集中;
  • 按名字相邻的文件在盘上是否也相邻;
  • 文件离目录记录有多远;
  • 目录索引被分成了几段。

某个工具在合成数据上变快或变慢,不作为调整生成器的理由。

冷扫、热扫和访问时间

  • 冷扫:每次冷扫前卸载并重新挂载测试盘(Windows 用 VHDX、Linux 用直接 I/O 的 loop 设备、macOS 用磁盘镜像),Linux 再清页缓存。计时的冷扫是进程第二次启动,第一次启动的杀毒扫描、DLL 加载不算在内。
  • 热扫:冷扫后一般连续扫三次取平均。
  • 计时:只用进程外测的墙钟时间,工具自己报的用时不计分。

访问时间这一条想重点讨论。测试时,访问时间更新是开着的:

  • Linux 默认挂载 relatime;
  • Windows 10 起由系统托管,桌面机上一般是开的;
  • macOS 也默认更新。

扫描读目录时,文件系统要回写目录的访问时间(NTFS 写在 MFT 记录里,ext4 写在 inode 里),冷扫会多出一批写盘。low 体量(100 万文件)实测,开着比关着的冷扫用时(各扫描器的中位数):

日常电脑上它是开着的,用户扫盘前也不会特意去关,所以关掉再测,测出来的冷扫会比用户实际碰到的快。为了让每个工具付同样的代价:

  • 每个工具冷扫前,整棵树的访问时间都调回两天前,越过 relatime 的 24 小时门槛,保证每个工具都要自己触发这批写入;
  • Windows 上每个工具用一份新解出来的测试盘。

需要说明,这条规则对 SpaceKnife 有利。内存盘上的对照里,开着访问时间,gdu、dua、WinDirStat 冷扫多出 5.4–6.3 秒,SpaceKnife 只多约 0.3 秒,它扫描时基本不触发访问时间更新。我认为开着测才符合日常使用,但这也是最可能被质疑的一条,欢迎讨论。

结果核验

只用工具自己输出的数字,从不拿标准答案补位:

  • 总大小不低于标准答案的 75%;
  • 报了文件数的,不低于 90%;
  • 报了顶层目录的,每个区域都要报出大小,且不低于 75%。

少报说明漏扫,成绩作废。多报(跟进了链接、重复计数)只标警告,因为多扫只会更慢,占不到便宜。每个命令行工具的原始输出都和结果一起保存;只报总数的工具标「只核对大小」,没有任何输出的图形界面工具标「未核验」。

NTFS MFT:单独一个专栏

直接读 NTFS 的 $MFT 会比目录遍历快得多,但比的不是同一件事。所以普通榜要求走目录遍历,读 MFT 的模式单独排。

为了发现普通榜里偷读 MFT 的情况,同一份数据在 NTFS 和没有 MFT 的 ReFS 上各跑一次,两个迹象同时出现才判:

  1. ReFS 对它明显比对别的工具慢(ReFS / NTFS 耗时比超过所有扫描器中位数的 2 倍);
  2. 它在 NTFS 上冷扫和热扫几乎一样快(冷 ÷ 热 ≤ 1.3):读 MFT 每次都要读完整张表,冷热没区别。

只中第 1 条的,只是「在 ReFS 上偏慢」,比如每个文件都单独查询一次的工具,会标出来但不处罚。

MFT 专栏目前的冷扫秒数:

# 扫描器 综合 100 万 500 万 900 万 1400 万
1 SpaceKnife 0.3.4 100.0 3.57 15.6 27.6 31.2
2 WizTree 37.0 6.74 35.4 62.9 80.1
3 WinDirStat 35.5 7.75 40.0 74.4 80.5

SpaceKnife 0.3.5 还没有 MFT 成绩。SpaceKnife 的 MFT 扫描一旦退回普通遍历,成绩直接作废。

计分

  • 平台内相对分:该平台最快用时 ÷ 自己的用时 × 100,硬件快慢在这一步就约掉了。冷扫、热扫各算一次。
  • 均衡指数:同时看用时和资源,跑得快但把 CPU 和磁盘压得更满的,不会因此占便宜。
    • CPU 时间 = 进程树的 CPU 时间 ÷ 逻辑核数;
    • IO 时间 = 读盘次数 ÷ 该平台测得的随机读上限;
    • B = √(墙钟 × (CPU 时间 + IO 时间)),均衡指数 = 项数 ÷ B。
  • 跨平台:每一项在工具能跑的平台上取几何平均。综合分是冷扫、热扫、均衡三项的几何平均。
  • 跨体量:总榜只算 100 万文件及以上的体量。10 万、40 万两档几秒就扫完,计时以进程启动为主,只作参考。

缺平台的处理:不扣分也不加分,只在它能跑的平台上算平均,等于把缺的平台按它自己的平均分补上。只有 Windows 版的工具不会因为没有 Linux、macOS 版吃亏,平台多的也不能靠多跑几个平台刷分。代价是平台少的工具被检验得没那么全面,所以榜上另列有效平台数。

当前总榜(截至 11 月 10 日)

「平台」是 low 体量的有效 / 参加数。榜单会随新的运行刷新,最新的以仓库 README 为准。

已知局限

CI 的盘是限速云盘。

  • 同时发 32 个随机 4 KiB 读,每秒只有约 4 千到 2.4 万次。
  • Windows x64 上单次读的延迟约 0.1 ms,但每秒读次数很快封顶在 9 千到 1 万次,同时发 1 个读和发 64 个几乎一样快。
  • 所以 CI 上的冷扫更像慢盘场景:并发很深的工具只是在盘上多排队。

换成内存盘,排名会变。 同一棵 100 万文件的树(总大小缩到 4 GiB),冷扫秒数,两轮取第一轮。10 月 26 日测,当时诊断工作流还没有打开访问时间更新:

  • 物理盘上和 VHDX 一样,都是 WinDirStat 最快,另外三个挤在 1 秒以内,说明偏差来自云盘的 IOPS 上限,不是 VHDX。
  • 内存盘上读盘不再是瓶颈,比的是 CPU,WinDirStat 从第一变成最后。
  • 真实的 NVMe 介于两者之间。

其他局限

  • 只有 4 个逻辑核:能随核数扩展的工具,在多核桌面机上会更快。
  • macOS 的冷扫不够冷:磁盘镜像的缓存清不干净,冷扫接近热扫。
  • 部分图形界面工具只能用导出模式无界面运行,比如 WinDirStat 会写出每一项的 CSV,这部分时间也算在成绩里。

想看自己盘上的情况,可以用仓库里的本地套件,在自己的盘上跑同样版本的工具,成绩能提交到社区榜。目前社区榜上只有我自己电脑上的 3 块盘:1 块 NTFS 系统盘、2 块 ReFS 数据盘。

想听听大家的意见

  1. 访问时间开着测,你们觉得合理吗?如果你的系统是关着的,也想知道是什么情况。
  2. 合成数据还有哪些真实盘上常见、但没覆盖到的结构?比如云盘占位文件、OneDrive 这类按需下载的文件、压缩或加密的文件。
  3. CI 上只有限速云盘,有没有更好的办法测出本地 NVMe 上的表现?
  4. 还想看哪些工具加入?需要能在命令行或无界面下运行、能读出结果,许可证也要允许在 Windows Server 上用。

觉得规则、参数或测试数据对哪个工具不公平,欢迎回帖,或者到 GitHub 开 issue。

方法说明:Disk-Scan-Benchmark/docs/METHODOLOGY.md at main · DuskXi/Disk-Scan-Benchmark · GitHub
本地套件:Disk-Scan-Benchmark/docs/LOCAL_SUITE.md at main · DuskXi/Disk-Scan-Benchmark · GitHub