基准测试
仓库在 bin/ 和 benchmarks/ 下提供基准测试工具。它会使用真实语料库(WordPress、Laravel)和生成的合成数据集测试每种搜索模式,捕获结构化报告,并支持比较两组报告序列。
该工具属于仓库,而非 Composer软件包:由于 0.2.3、benchmarks/ 和 bin/bench*脚本不会打包发布,因此请从克隆的仓库中运行(git clone https://github.com/inline0/greph && cd greph && composer install)。
README 中公布的性能数据来自 GitHub Actions 的运行结果,绝不采用本地机器的数据。本地运行有助于迭代;CI 运行结果才是权威依据。
语料库
首次运行时,会在 benchmarks/corpora/synthetic/ 下生成合成语料库(synthetic-1k、synthetic-10k、synthetic-100k-single)。真实语料库不包含在内:请在 benchmarks/corpora/wordpress 或 benchmarks/corpora/laravel 处放置仓库副本(CI 工作流会使用 --depth=1 从 WordPress/WordPress 克隆)。缺少目录的语料库会被跳过。
运行基准测试
# Full benchmark suite, every corpus that is present
./bin/bench
# Specific category (the category names used in benchmarks/suites/)
./bin/bench --category text
./bin/bench --category ast
# Compare against external tools when available
./bin/bench --compare rg,grep
./bin/bench --compare sg
# Choose a corpus
./bin/bench --corpus wordpress
./bin/bench --corpus laravel
./bin/bench --corpus synthetic-1k
# Write the run as JSON
./bin/bench --corpus wordpress --output build/run-1.json
# Measured series: 5 runs after 1 warmup run
./bin/bench-series --repeat 5 --warmup 1 --corpus wordpress --output build/head-series.json
# Aggregate separate runs into one series
./bin/bench-aggregate --output build/head-series.json build/run-*.json
bin/bench-compare base-series.json head-series.json 可比较两个序列文件(bench-series 或 bench-aggregate 的输出)并打印 Markdown摘要,便于针对热点路径进行迭代。bin/bench-ci 会通过 gh CLI 在 GitHub Actions 上触发 Benchmark 工作流。
类别
README 会发布八组结果,每组衡量引擎的一个特定层级。每组汇集一个或多个在 benchmarks/suites/ 中定义的工具类别。
扫描模式:文本
使用原生文本搜索匹配字面量、正则表达式及组合模式。发布的基线测试在 WordPress 语料库上运行,包含:
- 字面量
function - 字面量,不区分大小写
- 字面量,全字匹配
- 新建实例的正则表达式
- 正则表达式数组调用
- 正则表达式前缀字面量
- 正则表达式后缀字面量
- 正则表达式精确行字面量
- 正则表达式字面量合并
扫描模式:遍历
仅遍历文件,不执行搜索。单独衡量支持 gitignore 的遍历器开销。
扫描模式:并行文本
使用 1、2 和 4 个任务,对 function 执行固定字符串搜索。对于该模式,只有文件数超过 jobs * 4_000 时工作线程池才会启动(参见 并行工作线程);文件数高于 WordPress 语料库,因此发布的三行数据都在单个进程中运行,无法体现线程池扩展效果(#8)。
扫描模式:AST
使用原生 AST 搜索代表性模式:
new $CLASS()array($$$ITEMS)
索引文本模式
针对与扫描模式相同的模式执行预热后的索引文本搜索。包括字面量、不区分大小写、全字匹配、短词元和正则表达式查询。
索引摘要查询
使用计数、有匹配项的文件和无匹配项的文件等输出,执行预热后的索引文本搜索。由于每个文件的处理成本最低,这些查询最能受益于倒排表存储。
索引 / 缓存 AST
针对与 AST 扫描模式相同的模式,执行预热后的 AST 事实搜索和缓存 AST 搜索。
构建开销
冷启动构建三元组索引、AST 事实索引和 AST 缓存的开销。可用于决定针对特定工作负载维护哪种模式。
解读已发布数据
README 会发布每个基线最新 CI 运行的快照。每个部分均来自特定的 GitHub Actions 运行,并标明语料库、运行器、PHP版本,以及测量运行和预热的次数。如需复现数据,请在本地使用相同组合。
对比列(rg、grep、sg)来自同一任务、同一运行器和同一语料库,不是根据外部基准测试推算得出。
如何添加基准测试
- 在
benchmarks/下添加基准测试定义。 - 如果回归测试套件中尚无对应场景,请添加一个(以便同时验证测量中的行为)。
- 运行
./bin/bench --category <yours>,验证新的基准测试。 - 使用 Benchmark 工作流与
main进行比较。该工作流会在涉及src/、benchmarks/或bin/的拉取请求上运行,并在运行摘要中发布当前提交与基准版本的对比。 - 将包含新基准测试的 CI 运行合入
main后,更新 README 表格。
性能理念
Greph 并不打算在冷扫描速度上超越 ripgrep 或 grep。Ripgrep 使用 Rust 实现,并针对字面量扫描进行了手工调优的 SIMD 优化;在已发布的数据中,冷文本扫描时,rg 和 GNU grep 均快于 Greph。它们的目标各不相同:
- 快到足以让交互使用和代理循环感觉自然。
- 从预热后的索引中响应重复查询:索引正则表达式查询、索引计数查询和文件列表查询都比
rg和grep扫描同一目录树更快。 - 在索引和缓存的 AST 工作负载上胜过
ast-grep,因为 Greph 的热缓存可以避免重新解析目录树。冷 AST 搜索的结果各有不同:new $CLASS()更快,sg、array($$$ITEMS)更慢。 - 让每项性能提升都可测量、可复现。
没有基准测试报告支持的性能声明不会合入。