From 079619ee448b6dcef612c6af80aa581d57c97b1a Mon Sep 17 00:00:00 2001 From: "codspeed-hq[bot]" <117304815+codspeed-hq[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 07:59:22 +0000 Subject: [PATCH] Add CodSpeed performance benchmarks --- .github/workflows/codspeed.yml | 37 +++ Cargo.lock | 543 ++++++++++++++++++++++++++++++++- Cargo.toml | 5 + README.md | 1 + benches/grep_bench.rs | 288 +++++++++++++++++ src/lib.rs | 129 ++++---- 6 files changed, 936 insertions(+), 67 deletions(-) create mode 100644 .github/workflows/codspeed.yml create mode 100644 benches/grep_bench.rs diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml new file mode 100644 index 0000000..59aaa9f --- /dev/null +++ b/.github/workflows/codspeed.yml @@ -0,0 +1,37 @@ +name: CodSpeed + +on: + push: + branches: + - "main" + pull_request: + # `workflow_dispatch` allows CodSpeed to trigger backtest + # performance analysis in order to generate initial data. + workflow_dispatch: + +permissions: + contents: read + id-token: write + +jobs: + codspeed: + name: Run benchmarks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Rust toolchain, cache and cargo-codspeed binary + uses: moonrepo/setup-rust@v0 + with: + channel: stable + cache-target: release + bins: cargo-codspeed + + - name: Build the benchmark target(s) + run: cargo codspeed build + + - name: Run the benchmarks + uses: CodSpeedHQ/action@v4 + with: + mode: simulation + run: cargo codspeed run diff --git a/Cargo.lock b/Cargo.lock index 4d21e03..caaf560 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" version = "1.0.0" @@ -67,12 +73,39 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + [[package]] name = "bitflags" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.62" @@ -106,6 +139,33 @@ dependencies = [ "rand_core", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "4.6.1" @@ -134,12 +194,80 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "codspeed" +version = "4.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57af92d1db7f6871b7e82c79cd87f2501db66f36b0eab924be6ea83dd6b2f3f3" +dependencies = [ + "anyhow", + "cc", + "colored", + "getrandom 0.2.17", + "glob", + "libc", + "nix", + "serde", + "serde_json", + "statrs", +] + +[[package]] +name = "codspeed-criterion-compat" +version = "4.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d31ae2e9ab23c29fa13bdfa06d012524176f5c0f4e25ec262cd829d947ebc5e" +dependencies = [ + "clap", + "codspeed", + "codspeed-criterion-compat-walltime", + "colored", + "regex", +] + +[[package]] +name = "codspeed-criterion-compat-walltime" +version = "4.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8605e40bab5114dcb0f76268e18880082b5798dec10757b5b58d2c3bbc7a1c" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "codspeed", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + [[package]] name = "colorchoice" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.59.0", +] + [[package]] name = "cpufeatures" version = "0.3.0" @@ -149,6 +277,47 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "ctor" version = "0.8.0" @@ -218,6 +387,12 @@ version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + [[package]] name = "equivalent" version = "1.0.2" @@ -297,6 +472,41 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "getrandom" version = "0.4.2" @@ -317,6 +527,17 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -338,6 +559,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "id-arena" version = "2.3.0" @@ -375,12 +602,32 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" @@ -428,6 +675,24 @@ dependencies = [ "jiff-tzdb", ] +[[package]] +name = "js-sys" +version = "0.3.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "leb128fmt" version = "0.1.0" @@ -476,6 +741,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_threads" version = "0.1.7" @@ -519,6 +793,12 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + [[package]] name = "os_display" version = "0.1.4" @@ -528,12 +808,46 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + [[package]] name = "pkg-config" version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -606,7 +920,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20", - "getrandom", + "getrandom 0.4.2", "rand_core", ] @@ -616,6 +930,26 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "regex" version = "1.12.3" @@ -673,6 +1007,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "same-file" version = "1.0.6" @@ -743,6 +1083,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + [[package]] name = "smallvec" version = "1.15.1" @@ -759,6 +1105,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "statrs" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3fe7c28c6512e766b0874335db33c94ad7b8f9054228ae1c2abd47ce7d335e" +dependencies = [ + "approx", + "num-traits", +] + [[package]] name = "strsim" version = "0.11.1" @@ -783,7 +1139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys 0.61.2", @@ -863,6 +1219,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "type-map" version = "0.5.1" @@ -919,6 +1285,7 @@ name = "uu_grep" version = "0.1.0" dependencies = [ "clap", + "codspeed-criterion-compat", "glob", "memchr", "onig", @@ -990,6 +1357,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + [[package]] name = "wasip2" version = "1.0.2+wasi-0.2.9" @@ -1008,6 +1381,51 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +dependencies = [ + "unicode-ident", +] + [[package]] name = "wasm-encoder" version = "0.244.0" @@ -1042,6 +1460,16 @@ dependencies = [ "semver", ] +[[package]] +name = "web-sys" +version = "0.3.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "wild" version = "2.2.1" @@ -1066,13 +1494,22 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.5", ] [[package]] @@ -1084,6 +1521,22 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + [[package]] name = "windows-targets" version = "0.53.5" @@ -1091,58 +1544,106 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_aarch64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + [[package]] name = "windows_i686_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_i686_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "windows_x86_64_msvc" version = "0.53.1" @@ -1253,6 +1754,26 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +[[package]] +name = "zerocopy" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zerofrom" version = "0.1.8" diff --git a/Cargo.toml b/Cargo.toml index 019577a..7170309 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,5 +27,10 @@ onig_sys = { version = "*", default-features = false } uucore = "0.8.0" walkdir = "2.5" +[[bench]] +name = "grep_bench" +harness = false + [dev-dependencies] +criterion = { version = "4.7.0", package = "codspeed-criterion-compat" } uutests = "0.8.0" diff --git a/README.md b/README.md index 8531b38..6f08387 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![dependency status](https://deps.rs/repo/github/uutils/grep/status.svg)](https://deps.rs/repo/github/uutils/grep) [![CodeCov](https://codecov.io/gh/uutils/grep/branch/main/graph/badge.svg)](https://codecov.io/gh/uutils/grep) +[![CodSpeed](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/uutils/grep?utm_source=badge) # Grep, now in Rust diff --git a/benches/grep_bench.rs b/benches/grep_bench.rs new file mode 100644 index 0000000..3232f08 --- /dev/null +++ b/benches/grep_bench.rs @@ -0,0 +1,288 @@ +// This file is part of the uutils grep package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use criterion::{Criterion, black_box, criterion_group, criterion_main}; +use uu_grep::matcher::Matcher; +use uu_grep::{BinaryMode, ColorConfig, Config, DeviceMode, DirectoryMode, GlobSet, RegexMode}; + +fn make_config<'a>( + patterns: &'a [&'a str], + regex_mode: RegexMode, + ignore_case: bool, + invert_match: bool, + word_regexp: bool, +) -> Config<'a> { + Config { + directory_mode: DirectoryMode::Read, + device_mode: DeviceMode::Default, + follow_symlinks: false, + include_globs: GlobSet::new(), + exclude_globs: GlobSet::new(), + exclude_dir_globs: GlobSet::new(), + label: "(standard input)", + #[cfg(windows)] + strip_cr: false, + binary_mode: BinaryMode::Binary, + max_count: None, + before_context: 0, + after_context: 0, + has_context: false, + patterns, + regex_mode, + ignore_case, + invert_match, + word_regexp, + line_regexp: false, + quiet: true, + count: false, + show_filename: false, + files_with_matches: false, + files_without_match: false, + only_matching: false, + byte_offset: false, + line_number: false, + initial_tab: false, + null_separator: false, + null_data: false, + line_buffered: false, + no_messages: true, + group_separator: None, + use_color: false, + color_config: ColorConfig { + matched_selected: "", + matched_context: "", + filename: "", + line_number: "", + byte_offset: "", + separator: "", + selected_line: "", + context_line: "", + reverse_video: false, + no_erase: false, + }, + } +} + +fn bench_compile(c: &mut Criterion) { + let mut group = c.benchmark_group("compile"); + + group.bench_function("fixed_string", |b| { + b.iter(|| { + let patterns: &[&str] = &["hello world"]; + let config = make_config(patterns, RegexMode::Fixed, false, false, false); + let matcher = Matcher::compile(black_box(&config)).unwrap(); + let _ = black_box(&matcher); + }) + }); + + group.bench_function("basic_regex", |b| { + b.iter(|| { + let patterns: &[&str] = &[r"[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}"]; + let config = make_config(patterns, RegexMode::Basic, false, false, false); + let matcher = Matcher::compile(black_box(&config)).unwrap(); + let _ = black_box(&matcher); + }) + }); + + group.bench_function("extended_regex", |b| { + b.iter(|| { + let patterns: &[&str] = &[r"[0-9]{4}-[0-9]{2}-[0-9]{2}"]; + let config = make_config(patterns, RegexMode::Extended, false, false, false); + let matcher = Matcher::compile(black_box(&config)).unwrap(); + let _ = black_box(&matcher); + }) + }); + + group.bench_function("perl_regex", |b| { + b.iter(|| { + let patterns: &[&str] = &[r"\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}"]; + let config = make_config(patterns, RegexMode::Perl, false, false, false); + let matcher = Matcher::compile(black_box(&config)).unwrap(); + let _ = black_box(&matcher); + }) + }); + + group.bench_function("multiple_patterns", |b| { + b.iter(|| { + let patterns: &[&str] = &["error", "warning", "critical", "fatal", "panic"]; + let config = make_config(patterns, RegexMode::Fixed, false, false, false); + let matcher = Matcher::compile(black_box(&config)).unwrap(); + let _ = black_box(&matcher); + }) + }); + + group.finish(); +} + +fn bench_match(c: &mut Criterion) { + let mut group = c.benchmark_group("match"); + + // Fixed string match - hit + { + let patterns: &[&str] = &["ERROR"]; + let config = make_config(patterns, RegexMode::Fixed, false, false, false); + let matcher = Matcher::compile(&config).unwrap(); + let line = b"2024-01-15 10:30:45 ERROR: Connection timeout on server-42"; + + group.bench_function("fixed_string_hit", |b| { + b.iter(|| black_box(matcher.match_line(black_box(line)))) + }); + } + + // Fixed string match - miss + { + let patterns: &[&str] = &["CRITICAL"]; + let config = make_config(patterns, RegexMode::Fixed, false, false, false); + let matcher = Matcher::compile(&config).unwrap(); + let line = b"2024-01-15 10:30:45 INFO: Server started successfully"; + + group.bench_function("fixed_string_miss", |b| { + b.iter(|| black_box(matcher.match_line(black_box(line)))) + }); + } + + // Extended regex match + { + let patterns: &[&str] = &[r"[0-9]{4}-[0-9]{2}-[0-9]{2}"]; + let config = make_config(patterns, RegexMode::Extended, false, false, false); + let matcher = Matcher::compile(&config).unwrap(); + let line = b"2024-01-15 10:30:45 ERROR: Connection timeout"; + + group.bench_function("extended_regex_hit", |b| { + b.iter(|| black_box(matcher.match_line(black_box(line)))) + }); + } + + // Case-insensitive match + { + let patterns: &[&str] = &["error"]; + let config = make_config(patterns, RegexMode::Fixed, true, false, false); + let matcher = Matcher::compile(&config).unwrap(); + let line = b"2024-01-15 10:30:45 ERROR: Connection timeout"; + + group.bench_function("case_insensitive_hit", |b| { + b.iter(|| black_box(matcher.match_line(black_box(line)))) + }); + } + + // Inverted match + { + let patterns: &[&str] = &["ERROR"]; + let config = make_config(patterns, RegexMode::Fixed, false, true, false); + let matcher = Matcher::compile(&config).unwrap(); + let line = b"2024-01-15 10:30:45 INFO: Server started successfully"; + + group.bench_function("inverted_match", |b| { + b.iter(|| black_box(matcher.match_line(black_box(line)))) + }); + } + + // Word boundary match + { + let patterns: &[&str] = &["error"]; + let config = make_config(patterns, RegexMode::Fixed, true, false, true); + let matcher = Matcher::compile(&config).unwrap(); + let line = b"2024-01-15 10:30:45 error: Connection timeout"; + + group.bench_function("word_boundary_hit", |b| { + b.iter(|| black_box(matcher.match_line(black_box(line)))) + }); + } + + // Multiple patterns + { + let patterns: &[&str] = &["error", "warning", "critical", "fatal", "panic"]; + let config = make_config(patterns, RegexMode::Fixed, true, false, false); + let matcher = Matcher::compile(&config).unwrap(); + let line = b"2024-01-15 10:30:45 WARNING: High memory usage detected on node-7"; + + group.bench_function("multi_pattern_hit", |b| { + b.iter(|| black_box(matcher.match_line(black_box(line)))) + }); + } + + // Long line + { + let patterns: &[&str] = &["needle"]; + let config = make_config(patterns, RegexMode::Fixed, false, false, false); + let matcher = Matcher::compile(&config).unwrap(); + let mut long_line = "a".repeat(5000); + long_line.push_str("needle"); + long_line.push_str(&"b".repeat(5000)); + let long_line_bytes = long_line.into_bytes(); + + group.bench_function("long_line_hit", |b| { + b.iter(|| black_box(matcher.match_line(black_box(&long_line_bytes)))) + }); + } + + group.finish(); +} + +fn bench_throughput(c: &mut Criterion) { + let mut group = c.benchmark_group("throughput"); + + // Simulate processing many lines (like searching a log file) + let lines: Vec> = (0..1000) + .map(|i| { + if i % 50 == 0 { + format!( + "2024-01-15 10:30:{:02} ERROR: Connection timeout on server-{}", + i % 60, + i + ) + .into_bytes() + } else { + format!( + "2024-01-15 10:30:{:02} INFO: Request processed in {}ms", + i % 60, + i * 3 + ) + .into_bytes() + } + }) + .collect(); + + { + let patterns: &[&str] = &["ERROR"]; + let config = make_config(patterns, RegexMode::Fixed, false, false, false); + let matcher = Matcher::compile(&config).unwrap(); + + group.bench_function("scan_1000_lines_fixed", |b| { + b.iter(|| { + let mut matches = 0u64; + for line in &lines { + if matcher.match_line(black_box(line)).is_some() { + matches += 1; + } + } + black_box(matches) + }) + }); + } + + { + let patterns: &[&str] = &[r"[0-9]+ *ms"]; + let config = make_config(patterns, RegexMode::Extended, false, false, false); + let matcher = Matcher::compile(&config).unwrap(); + + group.bench_function("scan_1000_lines_regex", |b| { + b.iter(|| { + let mut matches = 0u64; + for line in &lines { + if matcher.match_line(black_box(line)).is_some() { + matches += 1; + } + } + black_box(matches) + }) + }); + } + + group.finish(); +} + +criterion_group!(benches, bench_compile, bench_match, bench_throughput); +criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs index b915ae0..894faa8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,9 +3,12 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -mod context_buffer; -mod line_buffer; -mod matcher; +#[doc(hidden)] +pub mod context_buffer; +#[doc(hidden)] +pub mod line_buffer; +#[doc(hidden)] +pub mod matcher; mod output; mod searcher; @@ -20,7 +23,8 @@ use std::path::Path; use uucore::error::{FromIo, UResult, USimpleError}; #[derive(Clone, Copy, PartialEq, Eq)] -enum RegexMode { +#[doc(hidden)] +pub enum RegexMode { Fixed, Basic, Extended, @@ -28,7 +32,8 @@ enum RegexMode { } #[derive(Clone, Copy, PartialEq, Eq)] -enum BinaryMode { +#[doc(hidden)] +pub enum BinaryMode { Binary, Text, WithoutMatch, @@ -42,79 +47,84 @@ enum ColorMode { } #[derive(Clone, Copy, PartialEq, Eq)] -enum DirectoryMode { +#[doc(hidden)] +pub enum DirectoryMode { Read, Skip, Recurse, } #[derive(Clone, Copy, PartialEq, Eq)] -enum DeviceMode { +#[doc(hidden)] +pub enum DeviceMode { Default, Read, Skip, } -struct ColorConfig<'a> { - matched_selected: &'a str, - matched_context: &'a str, - filename: &'a str, - line_number: &'a str, - byte_offset: &'a str, - separator: &'a str, - selected_line: &'a str, - context_line: &'a str, +#[doc(hidden)] +pub struct ColorConfig<'a> { + pub matched_selected: &'a str, + pub matched_context: &'a str, + pub filename: &'a str, + pub line_number: &'a str, + pub byte_offset: &'a str, + pub separator: &'a str, + pub selected_line: &'a str, + pub context_line: &'a str, - reverse_video: bool, - no_erase: bool, + pub reverse_video: bool, + pub no_erase: bool, } -struct GlobSet { +#[doc(hidden)] +pub struct GlobSet { patterns: Vec, } -struct Config<'a> { +#[doc(hidden)] +pub struct Config<'a> { // Searcher - directory_mode: DirectoryMode, - device_mode: DeviceMode, - follow_symlinks: bool, - include_globs: GlobSet, - exclude_globs: GlobSet, - exclude_dir_globs: GlobSet, - label: &'a str, + pub directory_mode: DirectoryMode, + pub device_mode: DeviceMode, + pub follow_symlinks: bool, + pub include_globs: GlobSet, + pub exclude_globs: GlobSet, + pub exclude_dir_globs: GlobSet, + pub label: &'a str, #[cfg(windows)] - strip_cr: bool, - binary_mode: BinaryMode, - max_count: Option, - before_context: usize, - after_context: usize, - has_context: bool, + pub strip_cr: bool, + pub binary_mode: BinaryMode, + pub max_count: Option, + pub before_context: usize, + pub after_context: usize, + pub has_context: bool, // Matcher - patterns: &'a [&'a str], - regex_mode: RegexMode, - ignore_case: bool, - invert_match: bool, - word_regexp: bool, - line_regexp: bool, + pub patterns: &'a [&'a str], + pub regex_mode: RegexMode, + pub ignore_case: bool, + pub invert_match: bool, + pub word_regexp: bool, + pub line_regexp: bool, // Output - quiet: bool, - count: bool, - show_filename: bool, - files_with_matches: bool, - files_without_match: bool, - only_matching: bool, - byte_offset: bool, - line_number: bool, - initial_tab: bool, - null_separator: bool, - null_data: bool, - line_buffered: bool, - no_messages: bool, - group_separator: Option<&'a str>, - use_color: bool, - color_config: ColorConfig<'a>, + pub quiet: bool, + pub count: bool, + pub show_filename: bool, + pub files_with_matches: bool, + pub files_without_match: bool, + pub only_matching: bool, + pub byte_offset: bool, + pub line_number: bool, + pub initial_tab: bool, + pub null_separator: bool, + pub null_data: bool, + pub line_buffered: bool, + pub no_messages: bool, + pub group_separator: Option<&'a str>, + pub use_color: bool, + pub color_config: ColorConfig<'a>, } #[uucore::main(no_signals)] @@ -855,7 +865,14 @@ fn expand_num_shorthand(args: impl Iterator) -> Vec { } impl GlobSet { - fn with_capacity(capacity: usize) -> Self { + /// Create an empty GlobSet. + pub fn new() -> Self { + Self { + patterns: Vec::new(), + } + } + + pub fn with_capacity(capacity: usize) -> Self { Self { patterns: Vec::with_capacity(capacity), }