跳转到正文

基准测试

仓库在 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)来自同一任务、同一运行器和同一语料库,不是根据外部基准测试推算得出。

如何添加基准测试

  1. 在 benchmarks/ 下添加基准测试定义。
  2. 如果回归测试套件中尚无对应场景,请添加一个(以便同时验证测量中的行为)。
  3. 运行 ./bin/bench --category <yours>,验证新的基准测试。
  4. 使用 Benchmark 工作流与 main进行比较。该工作流会在涉及 src/、benchmarks/ 或 bin/ 的拉取请求上运行,并在运行摘要中发布当前提交与基准版本的对比。
  5. 将包含新基准测试的 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) 更慢。
  • 让每项性能提升都可测量、可复现。

没有基准测试报告支持的性能声明不会合入。