ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ripgrep benchsuite 实战:在 i9-12900K 上复现 2022-12-16 命令行搜索工具基准测试并读懂结果

ripgrep benchsuite 实战:在 i9-12900K 上复现 2022-12-16 命令行搜索工具基准测试并读懂结果 ripgrep benchsuite 实战在 i9-12900K 上复现 2022-12-16 命令行搜索工具基准测试并读懂结果【免费下载链接】ripgrepripgrep recursively searches directories for a regex pattern while respecting your gitignore项目地址: https://gitcode.com/GitHub_Trending/ri/ripgrepripgrep 仓库内置了一个名为 benchsuite 的基准测试框架用于在真实语料上系统对比 ripgreprg、GNU grep、ag、git grep、ugrep 等命令行搜索工具的性能与正确性。本文以仓库中 2022-12-16 在 Arch LinuxIntel i9-12900K、128GB 内存上完成的基准运行记录为核心完整还原当时的测试命令、工具版本与硬件环境并结合 benchsuite 脚本 的源码讲清楚测试集如何设计、数据如何采集与汇总帮助你独立复现这套测试、并正确解读 summary 中的每一组数字。一、这次基准运行是什么命令、环境与工具版本本次运行的说明文档 记录了完整的采集方式。基准数据于 2022-12-16 采集通过仓库根目录的benchsuite/benchsuite脚本运行实际执行的命令是$ ./benchsuite \ --dir /dev/shm/benchsuite \ --raw runs/2022-12-16-archlinux-duff/raw.csv \ | tee runs/2022-12-16-archlinux-duff/summary这条命令有三个要点--dir /dev/shm/benchsuite语料目录放在/dev/shmtmpfs 内存盘中避免磁盘 I/O 波动干扰计时--raw .../raw.csv把每一次采样的原始数据所有迭代、所有命令的耗时与命中行数以 CSV 格式落盘即 raw.csv标准输出经tee同时打印并保存为 summary即按基准项分组、展示“均值 ± 标准差”的汇总表。参与对比的工具版本摘自说明文档工具版本备注ripgrep13.0.0 (rev 87c4a2b4b1)编译时未启用 SIMD/AVX-SIMD -AVX (compiled)运行时探测启用SIMD AVX (runtime)GNU grep3.8ag2.2.0jit lzma zlibgit2.39.0以git grep形式参与ugrep3.9.2avx2 pcre2jit zlib bzip2 lzma lz4 zstdripgrep 使用的二进制并非发行版预编译包而是从 commit 7f23cd63 源码编译$ cargo build --release --features pcre2关于pcre2feature当前仓库的 Cargo.toml 中可见其定义pcre2 [grep/pcre2]即通过 crates/grep 启用可选依赖 crates/pcre2一个封装 Rustpcre2crate 的 grep matcher。这意味着基准测试里的 rg 支持 PCRE2 兼容语法与很多发行版打包默认配置保持一致。运行环境为 Arch Linux硬件是 Intel i9-12900K 处理器、128GB 内存。目录名中的 “duff” 是这台机器的代号——仓库里更早一次 2020-10-14 的运行frinkripgrep 12.1.1、grep 3.4、git 2.28见 benchsuite/runs/2020-10-14-archlinux-frink/README.md可以跨机器、跨版本对照阅读。二、benchsuite 脚本的工作机制benchsuite/benchsuite 是一个纯 Python 脚本#!/usr/bin/env python3无第三方依赖它定义了三个核心对象Benchmark一组用于相互比较的命令Command单个被测命令参数直接透传给subprocess.run但 stdin/stdout/stderr 由框架统一接管Result一次基准运行的全部采样负责统计均值与标准差。命令行参数脚本main()中的 argparse 定义benchsuite/benchsuite支持以下常用选项参数作用--dir PATH语料目录也是所有搜索命令的工作目录默认当前目录--download CORPUS下载并准备语料后退出可选all、linux、subtitles-en、subtitles-ru。注意all解压后总计约 13GB且包含完整编译 Linux 内核--raw PATH把所有采样原始数据写成 CSV--warmup-iter N每个命令正式采样前的预热次数默认 1--bench-iter N每个命令正式采样次数默认 3--allow-missing允许某些被测命令缺失时跳过对应项继续运行--disabled a,b逗号分隔的命令名列表直接跳过--list只列出可用基准项名称--force允许覆盖已存在的--raw输出文件bench PAT位置参数正则过滤只运行匹配的基准项collect_benchmarksbenchsuite/benchsuite通过扫描全局命名空间中以bench_开头的函数来动态发现基准项因此新增一个基准只需要新增一个同名函数。缺语料的基准项会打印missing: ...提示并跳过缺命令的基准项则提示可用--allow-missing降级运行。语料准备脚本定义了两大性质完全不同的语料源码注释原文一个是“少量大文件”一个是“大量小文件”两者在性能特征和相关性策略上差异巨大linux 语料浅克隆 Linux 内核源码树git clone --depth 1随后执行make defconfig与make -j$(nproc)完整构建内核download_linux。构建会往仓库里产生大量编译产物这些“垃圾文件”正是搜索工具默认应该跳过的对象。vmlinux二进制文件存在与否被用作语料就绪的标志。subtitles 语料从 OPUS-OpenSubtitles 下载英、俄双语单语文本并解压英文语料还会截取前 5500 万行生成en.sample.txt使英文基准的规模与俄语语料接近download_subtitles_en。采样与统计Benchmark.run()对每个命令先执行warmup_count次预热本次运行为 1 次再执行count次正式采样本次运行为 3 次benchsuite/benchsuite。每次采样记录两个量duration命令墙钟耗时秒含小数毫秒line_count搜索结果输出的行数通过统计 stdout 中\n计数得到。行数的作用不只是统计——它是正确性交叉验证同一基准下各工具的行数应当一致除非命令的语义本身不同例如 ASCII 与 Unicode 的\w定义不同。Result.distribution_for用statistics.mean和statistics.stdev计算每组采样的均值与标准差即 summary 中0.084 /- 0.002这类数字的来源。raw.csv 的格式--raw输出的 CSV 固定包含 8 个字段benchsuite/benchsuitebenchmark,warmup_iter,iter,name,command,duration,lines,env本次运行的 raw.csv 共 400 行1 行表头 399 条采样例如linux_literal_default,1,3,rg,rg PM_RESUME,0.08678817749023438,39, linux_literal_default,1,3,rg,rg PM_RESUME,0.08307123184204102,39, linux_literal_default,1,3,rg,rg PM_RESUME,0.08347964286804199,39, linux_literal_default,1,3,ag,ag PM_RESUME,0.2955434322357178,39,其中env字段记录该命令附加的环境变量如LC_ALLC这让每条数据都能被完整复现。三、基准用例设计从“故意不公平”到“尽量公平”所有 linux 系列基准都在构建好的内核源码树上执行subtitles 系列针对单个大文本文件。下面按脚本源码逐个说明函数定义见 benchsuite/benchsuite。linux 系列语料Linux 内核源码树基准名模式设计意图linux_literal_defaultPM_RESUME故意不公平各工具都用默认参数。rg/ag/git grep 默认会做智能过滤跳过隐藏/二进制文件、遵循 .gitignore而 grep/ugrep 默认不做所以后者必然搜更多文件。注释明确说它“pedagogically useful”——用来说明默认行为的差异linux_literalPM_RESUME尽量公平所有工具使用“各工具都有的最小参数集”如-n输出行号统一不做忽略大小写linux_literal_caseiPM_RESUME-i忽略大小写的字面量搜索linux_re_literal_suffix[A-Z]_RESUME字面量嵌在正则里考察正则引擎处理“前缀正则 后缀字面量”的能力linux_wordPM_RESUME-w全词匹配word boundarylinux_unicode_greek\p{Greek}Unicode 属性类匹配仅 rg 与 ugrep 参与linux_unicode_greek_casei\p{Greek}-i忽略大小写的 Unicode 属性类。源码注释直言“Only ripgrep gets this right (and its still fast)”linux_unicode_word\wAh考察\w的 Unicode 感知。注释指出只有 ripgrep 和设置了LC_ALLen_US.UTF-8的 git grep 才是真的按 Unicode 处理其余用 ASCII 语义linux_no_literal\w{5}\s\w{5}\s\w{5}\s\w{5}\s\w{5}不含任何字面量的正则击败所有“字面量快捷优化”memmem 预过滤等注释承认“applicability is somewhat suspicious”linux_alternates/linux_alternates_caseiERR_SYS\|PME_TURN_OFF\|LINK_REQ_RST\|CFG_BME_EVT短字面量 alternation无公共前缀字节考察多字面量优化各工具在同一基准中的典型调用方式以linux_literal为例rg -n PM_RESUME # rg rg -n --mmap PM_RESUME # rg (mmap) ag -s PM_RESUME # ag (mmap)ag 默认内存映射 git grep -I -n PM_RESUME # git grepLC_ALLC ugrep -r --ignore-files --no-hidden -I -n PM_RESUME ./ # ugrep可以看到脚本为每个工具精心选择了“等价能力”的参数git grep加-I跳过二进制、ugrep加--ignore-files --no-hidden -I、ag加-s静默、rg 单独列出--mmap变体以便对照 mmap 与 read 两种读取策略。对 grep/git grep 还显式设置LC_ALL脚本顶部注释解释grep 的 locale 设置对性能影响巨大GREP_ASCII {LC_ALL: C}与GREP_UNICODE {LC_ALL: en_US.UTF-8}所以同一工具常以 ASCII/Unicode 两种环境成对出现。subtitles 系列语料OpenSubtitles 大文本英文en.sample.txt与俄语ru.txt西里尔文各 7 个基准模式围绕“Sherlock Holmes / Шерлок Холмс”展开基准名模式考察点*_literalSherlock Holmes/Шерлок Холмс纯字面量含rg与rg (no mmap)对照*_literal_casei同上 -i忽略大小写*_literal_word字面量 词边界对俄语基准脚本手工拼接(?-u:^|\W)...(?-u:$|\W)来模拟 ASCII 词边界因为\b无法在禁用 Unicode 的模式里使用*_alternate5 个人名的 alternation多字面量选择*_alternate_casei同上 -i多字面量 忽略大小写*_surrounding_words\w\sHolmes\s\w含内部字面量的复杂正则*_no_literal\w{5}\s\w{5}...7 组无字面量正则。注释特别说明带 Unicode 支持的 grep 在 2 分钟时仍无完成迹象被作者手动终止故该基准只跑 ASCII 变体俄语基准还有两处值得注意的“公平性补丁”源码注释ugrep 会错误地把全合法的 UTF-8 俄语语料识别为二进制文件因此给 ugrep 加-a强制按文本处理——注释坦承这“technically gives it an edge”ag (lines) (ASCII)之类的变体则反映 ag 只按 ASCII 解释\w对西里尔文本匹配 0 行的事实会被 line count 如实记录。四、summary 汇总格式与星号含义主循环把每个基准的结果打印成如下格式benchsuite/benchsuitebenchmark name (pattern: pattern) ---------------------------------- name padded mean /- stdev (lines: n)*[fastest]两个*含义不同名字后的*该命令产出了全场最快的单次采样fastest_sample行末的*该命令的均值最低fastest_cmd按分布判定。同一基准内各命令的(lines: N)应当一致出现分歧往往意味着结果语义或正确性不同见下文实例。五、2022-12-16 运行结果解读以下数据全部来自 summary单位秒。内核语料上的字面量搜索linux_literal_default默认参数、故意不公平命令均值 ± 标准差linesrg0.084 ± 0.002 *39ugrep0.105 ± 0.00239git grep0.225 ± 0.00739ag0.295 ± 0.00139grep0.996 ± 0.00339公平参数版linux_literal中 rg 与自身 mmap 变体的对照命令均值 ± 标准差rg0.085 ± 0.001rg (mmap)0.322 ± 0.002ag (mmap)0.290 ± 0.002git grep0.211 ± 0.009ugrep0.189 ± 0.005一个直观结论在此机器与语料上rg默认read 路径显著快于显式--mmap而 ag 因默认即 mmap其速度与 rg 的 mmap 变体相近。Unicode 相关基准最能体现引擎差异。linux_unicode_word模式\wAh中git grepUnicode 环境耗时 3.980s±0.241而 rg 仅 0.085slinux_no_literal中差距更悬殊命令均值 ± 标准差linesrg (ASCII)0.200 ± 0.001720ugrep (ASCII)0.236 ± 0.003722rg0.266 ± 0.006721ugrep3.403 ± 0.008723git grep (ASCII)2.144 ± 0.014720git grep7.346 ± 0.017721ag (ASCII)0.832 ± 0.0071134注意ag (ASCII)的 lines 为 1134与其他工具约 720 不一致——ASCII 语义的\w与 Unicode 语义匹配的是不同集合line count 把这种语义差异直接暴露了出来。大文件语料上的表现基准模式rg最慢者subtitles_en_literalSherlock Holmes0.123ag (lines) 1.868subtitles_ru_literalШерлок Холмс0.133ag (lines) 1.973subtitles_en_surrounding_words\w\sHolmes\s\w0.200ugrep 43.220subtitles_ru_no_literal7 组\w{5}2.236ugrep 28.811subtitles_en_surrounding_words中 ugrep 耗时 43.220s±0.047rg 仅 0.200s±0.001是该次运行中最极端的单项差距俄语同型基准中 ugrep 亦为 42.919s。而subtitles_ru_alternate_casei则展示了另一面ag (ASCII) 以 2.727s 拿下全场最快rg 为 3.673s但 rg 的 lines 为 735、ag 为 691——Unicode 忽略大小写使 rg 多匹配了部分西里尔词形说明“最快”与“匹配最完整”未必是同一个命令这正是 line count 校验存在的意义。类似地linux_unicode_greek_casei中 ugrep 的 lines105与 rg245不一致对照脚本中“Only ripgrep gets this right”的注释可以推断 ugrep 在该用例上未能正确完成 Unicode 忽略大小写匹配。六、如何复现这套基准完整复现步骤在 ripgrep 仓库根目录下安装 Python 3、git、GNU grep、ag、ugrep以及待测的 rg建议按本次运行的方式从源码构建cargo build --release --features pcre2下载并准备语料约 13GB且需要编译整个 Linux 内核耗时较长./benchsuite --dir /dev/shm/benchsuite --download all该命令是幂等的也可以只准备部分语料如--download linux。运行全部基准并落盘原始数据./benchsuite \ --dir /dev/shm/benchsuite \ --raw runs/date-machine/raw.csv \ | tee runs/date-machine/summary常用变体./benchsuite --list # 列出全部基准项 ./benchsuite unicode # 只运行名称匹配 unicode 的基准 ./benchsuite --disabled grep,ag # 跳过指定命令 ./benchsuite --warmup-iter 1 --bench-iter 5 # 提高采样精度两点实践提示其一把--dir指向 tmpfs如本次运行的/dev/shm/benchsuite可显著降低 I/O 噪声前提是内存装得下语料其二--raw已存在时会拒绝覆盖--force可解除避免误覆盖历史数据。若想对照历史结果仓库中还保存了 2016、2018、2020 年的多组运行如 benchsuite/runs/2016-12-24-archlinux-cheetah/summary但注意 CPU 代际不同跨机器只宜看量级不宜看绝对值。七、如何正确看待这些数字最后给出阅读这份以及仓库中任何一次benchsuite 运行记录时的适用前提与限制单机结果所有数据只在“i9-12900K 128GB Arch Linux tmpfs”这一组合下成立工具版本rg 13.0.0、grep 3.8、ag 2.2.0、git 2.39.0、ugrep 3.9.2也是数据的一部分换机器或换版本都可能改变排序语料依赖linux 语料是“大量小文件 编译垃圾”subtitles 语料是“少量大文件”两类语料考察的策略完全不同文件遍历/过滤 vs 单文件内存搜索不能由一类结果外推另一类正确性优先于速度同一基准中 lines 不一致说明语义或匹配正确性存在差异ASCII/Unicode 词边界、二进制识别、Unicode case-folding此时“快”没有意义公平性是有代价的linux_literal_default是故意不公平的对照实验而“公平”版本也只能对齐各工具能力的交集脚本注释多次承认这种对齐的局限如给 ugrep 加-a的补偿。理解以上边界后这份 2022-12-16 的运行记录就不仅是一组静态数字而是一套可复现、可验证、可继续扩展新增bench_*函数即可加入基准项的搜索工具评测方法论的完整实例。【免费下载链接】ripgrepripgrep recursively searches directories for a regex pattern while respecting your gitignore项目地址: https://gitcode.com/GitHub_Trending/ri/ripgrep创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表