Files
wlocate/PERFORMANCE.md

92 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 本机验证结果
测量日期:2026-10-07 至 2026-10-08。Windows x64,C: 和 D: 合计约 327 万条文件/目录记录。数字会随本机文件变化、系统负载和缓存状态波动。
## 相对路径片段查询优化(2026-10-08)
`foo\bar` 没有盘符,也没有通配符,因此此前的绝对路径通配符优化没有覆盖它。修复前依然逐项重建完整路径;同样 17 个结果,原生命令行约 3779 ms,旧包装器约 253 ms。现在根据片段的最后一个组件在名称索引中找候选项,验证前面的目录组件,再遍历匹配目录的子树。`foo\bar` 允许 `afoo\barista` 这样的原有子串匹配,也包含匹配目录下的后代;不会把查询错误地改成组件精确匹配。
四次运行排除首次后的三次中位数,索引已在内存,GUI 同等查询每次清除上次结果缓存。命令行总耗时包含进程启动、IPC 和接收完整 stdout;GUI 列只测服务,不含输入防抖、绘制和图标。脚本:`tests/relative_path_benchmark.py`;原始数据:`test-output/relative-path-before.json`、`relative-path-after.json`。
| 查询 | 原生修复前总耗时 | 旧包装器本轮总耗时 | 原生修复后总耗时 | GUI 同等查询服务耗时 | 相同结果数 |
|---|---:|---:|---:|---:|---:|
| `foo\bar` | 3779.2 ms | 249.0 ms | **17.3 ms** | 1.374 ms | 17 |
| `Windows\Logs` | 3437.1 ms | 218.9 ms | **18.9 ms** | 1.490 ms | 364 |
| `Windows\Logs\` | 3382.0 ms | 247.7 ms | **14.7 ms** | 1.340 ms | 363 |
| `Windows\System32\drivers\etc` | 3423.7 ms | 235.9 ms | **17.6 ms** | 0.602 ms | 7 |
四种查询的旧包装器、原生 CLI 和 GUI 同等查询均逐路径比较一致。这里仍比较本机旧包装器,不代表测出了 Everything 搜索引擎本身的耗时或内部实现。
该方案复用已有名称前缀索引、父目录关系和子项链表,不增加常驻索引或重复的完整路径缓存。只有单组件加结尾斜杠(如 `foo\`)需要做名称后缀预筛。支持每个 OR 分支带正向路径片段的查询、附加筛选条件、大小写、Unicode、目录改名/移动和实时新增名称;无法安全缩小范围的查询继续通用匹配。2386 项核心断言及现有 GUI/图标测试通过,其中相对路径优化用逐项完整路径匹配作独立候选筛选对照,并验证 30000 个无关名称不会触发全扫描。实际磁盘集成测试同时比较名称查询、绝对路径通配符和相对路径片段,全部通过。
## 固定目录前缀的路径通配符优化(22:51 更新)
用户报告 `C:\Windows\Logs\*.log` 明显慢于旧版。修复前,路径通配符没有使用目录范围,每次对全盘约 327 万条记录重建完整路径并匹配;GUI 还遍历了全局名称排序。新增按父文件引用号维护的子项链表,先解析固定目录前缀,再遍历对应子树;目录移动/改名、硬链接变化、快照恢复和压缩都会维护或重建此索引。
同一台电脑、内存索引已就绪,6 次运行排除首次后的 5 次中位数。原始结果见 `test-output/path-before.json`、`test-output/path-after.json`;复测脚本 `tests/path_benchmark.py`。
| 查询 `C:\Windows\Logs\*.log` | 修复前 | 修复后 |
|---|---:|---:|
| 旧 `locate.old.exe` 启动至退出 | 152.8 ms | 160.1 ms |
| 原生 `locate.exe` 启动至退出 | 2598.9 ms | 14.7 ms |
| 原生命令行查询的服务内耗时 | 2581.8 ms | 0.486 ms |
| GUI 同等查询:名称排序、全部计数、返回前 256 条,服务内耗时 | 3638.2 ms | 0.571 ms |
三种查询均返回相同的 62 个路径。GUI 同等查询通过 CLI 的 Everything 语法和名称排序选项提交,每次先用不同查询清除上次结果缓存;这里测量服务查询,不包含 GUI 的 100 ms 输入防抖、界面绘制或图标加载。命令行总耗时包含进程启动、IPC 和接收 stdout,不包含终端绘制。比较对象是本机旧包装器,不能由此推断所有查询都快于 Everything 引擎。
保留原有通配符跨子目录、大小写、OR/AND、排除条件、排序和分页语义。只有每个 OR 分支都有正向、带绝对目录前缀的路径通配符时才缩小范围;其他查询沿用通用路径。子项索引增加每行 4 字节及每个父目录一个哈希表项,不保存重复的完整路径。442 项核心断言、30 项 GUI 缓存检查、16 项图标缓存检查通过;实际磁盘集成测试同时验证名称查询与目录范围查询,包括 30 个硬链接、目录改名、文件移动、删除、Unicode 长路径和 500 文件批量创建。
以下为此前测量记录。
## 同结果的命令行比较
命令通过 Python `subprocess` 启动,接收 stdout,测量从启动到退出的总时间;不包含终端逐行绘制。每项运行 9 次,排除首次后报告 8 次中位数。原始数据:`test-output/benchmark.json`。
| 命令 | 原来的 locate.old.exe | 原生 locate.exe | 结果 |
|---|---:|---:|---|
| `python*.exe` | 68.86 ms | 9.10 ms | 同样的 66 个完整路径,集合完全一致 |
| 不存在的文件名通配符 | 68.28 ms | 8.65 ms | 都为 0 条 |
| `-n 10 "python*.exe"` | 不支持该参数,不比较 | 8.40 ms | 10 条 |
| `-n 10 "*.exe"` | 不支持该参数,不比较 | 7.61 ms | 10 条 |
这里比较的是本机旧包装器和新命令行的端到端时间,不能据此声称原生搜索引擎在所有查询上都比 Everything 引擎快。旧版 `*.exe` 输出为 9999 条;原生为 12286 条,这种不同结果规模未用于速度结论。旧版独有的 9 个 Office 更新临时路径,Win32 检查均返回 ERROR_FILE_NOT_FOUND;记录见 `test-output/exe-comparison.json`。
## 原生服务内查询时间
来自 `test-output/performance.json`。每个查询连续运行三次;“首次”表示该查询没有已完成结果缓存,磁盘索引已经在内存。
| 查询 | 服务内时间 | 说明 |
|---|---:|---|
| `-n 10 python*.exe` | 0.30–0.38 ms | 名称前缀索引,找到足够数量就停止 |
| `-bic python` | 26–28 ms | 名称子串计数,10302 条 |
| `-ic python` | 43–52 ms | 完整路径子串计数,84020 条 |
| `-ic -r '^python.*\.exe$'` | 281–309 ms | Unicode PCRE2 JIT 正则,全名称扫描 |
| 全索引按名称排序,第一页 | 首次 1282 ms;缓存约 0.2 ms | 约 320 万条匹配、返回 256 条 |
| 全索引按完整路径排序,第一页 | 首次 3972 ms;缓存约 0.2 ms | 同上 |
| 全索引按大小排序,第一页 | 首次 2325 ms;缓存约 0.4 ms | 同上 |
最明显的剩余性能差距是大范围查询的首次排序和通用正则扫描。查询缓存会在相关索引变化后失效;名称查询不会因为仅修改文件大小/时间而失效。一次采样的服务工作集约 642 MiB、私有内存约 751 MiB;包含名称、父子关系、硬链接、文件元数据和查询缓存,未达到 Everything 的内存效率。
## 实时性、恢复与正确性
- 86 项核心断言通过:UTF-8 进程代码页和窄字符文件 API、查询、Unicode、正则工作量限制、日期边界、硬链接、DOS 别名计数、路径排序、分页、取消、快照校验、压缩与部分卷可用。
- 实际磁盘测试通过:30 个长名称硬链接跨 MFT 扩展记录;目录改名、单链接删除、跨目录移动、所有链接元数据同步、超过 MAX_PATH 的 Unicode 路径。
- 常规文件更新在测试中约 0.12–0.35 秒可见;500 文件突发创建约 0.12 秒可见。大范围排序占用索引读锁时,更新发布可能推迟。
- 服务停止后创建文件,重启后约 2143 ms 可查询,验证快照恢复与 USN 补读。
- 临时 NTFS VHD 插入后测试文件约 131 ms 可查;拔出后约 1787 ms 从已发布卷中移除,其他卷保持可查询。轮询相位会影响这些数字;热插拔检测周期为 2 秒。
- 60 次并发查询、20 个客户端线程,结果一致;单次 20000 条 / 约 2.1 MB 结果传输通过。
- 100 ms 请求超时约 104 ms 返回,随后服务继续正常响应;畸形请求和普通用户重建请求被拒绝。
- 程序内 GUI 测试通过:搜索、OR 分组与类型筛选、虚拟列表翻页、单文件与跨目录多选的系统/第三方 Shell 菜单、真实中文文件重命名。渲染图在 `test-output/ui-final`,已检查布局。
GUI 验证使用程序内集成测试和实际窗口渲染;本次外部桌面自动化接口不可用,未把模拟鼠标逐项点击全部第三方菜单当作已完成的测试。网络盘和非 NTFS 卷不在支持或测试范围。
## 主要实现选择
- 原生 MFT + USN 服务维护索引,CLI/GUI 通过本机管道提交查询,只传回匹配结果。
- 名称去重、排序前缀查找、64 位三元组 Bloom 预筛、连续内存扫描;路径子串查询复用父目录匹配结果。
- 目录采用文件引用号及父行缓存,改名无需重写所有子路径;完整 NTFS 序列号避免文件记录重用串到旧文件。
- PCRE2 JIT、64 KiB 传输缓冲、服务端限量和虚拟列表分页减少不必要的计算与传输。
- 快照带 SHA-256 校验并原子替换;未完成的记录更新保留日志重放位置,避免服务重启后漏掉未解决的变化。
这些优化解决了之前 C# 适配器整批传送目录、客户端重组和筛选的主要开销;性能问题不应简单归因于 C# 这一语言本身。