mirror of
https://github.com/uutils/grep.git
synced 2026-06-10 16:15:11 -07:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dde7c23c5 | ||
|
|
2a6a3aba7e |
@@ -0,0 +1,50 @@
|
|||||||
|
name: Benchmarks
|
||||||
|
|
||||||
|
# spell-checker:ignore codspeed dtolnay Swatinem sccache
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main, master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main, master ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # to fetch code (actions/checkout)
|
||||||
|
|
||||||
|
# End the current execution if there is a new changeset in the PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
benchmarks:
|
||||||
|
name: Run benchmarks (CodSpeed)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Install Rust
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
|
- name: Run sccache-cache
|
||||||
|
uses: mozilla-actions/sccache-action@v0.0.10
|
||||||
|
|
||||||
|
- name: Install cargo-codspeed
|
||||||
|
uses: taiki-e/install-action@v2
|
||||||
|
with:
|
||||||
|
tool: cargo-codspeed
|
||||||
|
|
||||||
|
- name: Build benchmarks
|
||||||
|
run: cargo codspeed build -p uu_grep
|
||||||
|
|
||||||
|
- name: Run benchmarks
|
||||||
|
uses: CodSpeedHQ/action@v4
|
||||||
|
env:
|
||||||
|
CODSPEED_LOG: debug
|
||||||
|
with:
|
||||||
|
mode: simulation
|
||||||
|
run: cargo codspeed run -p uu_grep > /dev/null
|
||||||
|
token: ${{ secrets.CODSPEED_TOKEN }}
|
||||||
Generated
+302
-11
File diff suppressed because it is too large
Load Diff
@@ -28,4 +28,11 @@ uucore = "0.8.0"
|
|||||||
walkdir = "2.5"
|
walkdir = "2.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
divan = { package = "codspeed-divan-compat", version = "4.0.5" }
|
||||||
|
tempfile = "3.10.1"
|
||||||
|
uucore = { version = "0.8.0", features = ["benchmark"] }
|
||||||
uutests = "0.8.0"
|
uutests = "0.8.0"
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "grep_bench"
|
||||||
|
harness = false
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ cargo test
|
|||||||
|
|
||||||
* Does not take `LANG`, etc., into account for handling file encodings (non-UTF8 matches are treated as binary)
|
* Does not take `LANG`, etc., into account for handling file encodings (non-UTF8 matches are treated as binary)
|
||||||
* No localization support yet
|
* No localization support yet
|
||||||
|
* Performances need to be improved
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,255 @@
|
|||||||
|
// Benchmarks for the grep utility
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// This file is part of the uutils grep package.
|
||||||
|
// It is licensed under the MIT License.
|
||||||
|
// For the full copyright and license information, please view the LICENSE
|
||||||
|
// file that was distributed with this source code.
|
||||||
|
|
||||||
|
use divan::{Bencher, black_box};
|
||||||
|
use uu_grep::uumain;
|
||||||
|
use uucore::benchmark::{create_test_file, run_util_function};
|
||||||
|
|
||||||
|
/// Build an access-log-like data set with `n` lines.
|
||||||
|
///
|
||||||
|
/// Roughly a quarter of the lines use a non-default HTTP method / status /
|
||||||
|
/// user-agent so that selective patterns match a realistic subset rather than
|
||||||
|
/// every line or no line at all.
|
||||||
|
fn access_log(n: usize) -> Vec<u8> {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
for i in 0..n {
|
||||||
|
let method = if i % 4 == 0 { "POST" } else { "GET" };
|
||||||
|
let status = if i % 7 == 0 { 404 } else { 200 };
|
||||||
|
let agent = if i % 3 == 0 {
|
||||||
|
"Mozilla/5.0 (X11; Linux x86_64) Chrome/120.0"
|
||||||
|
} else {
|
||||||
|
"curl/8.5.0"
|
||||||
|
};
|
||||||
|
let line = format!(
|
||||||
|
"192.168.{}.{} - - [01/Jan/2024:00:00:00 +0000] \"{} /index.html HTTP/1.1\" {} 1234 \"-\" \"{}\"\n",
|
||||||
|
(i / 256) % 256,
|
||||||
|
i % 256,
|
||||||
|
method,
|
||||||
|
status,
|
||||||
|
agent,
|
||||||
|
);
|
||||||
|
data.extend_from_slice(line.as_bytes());
|
||||||
|
}
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark a literal search that matches nothing.
|
||||||
|
///
|
||||||
|
/// This is the purest measure of raw scan throughput: the whole file is read
|
||||||
|
/// and searched but no output is produced.
|
||||||
|
#[divan::bench]
|
||||||
|
fn literal_no_match(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(
|
||||||
|
uumain,
|
||||||
|
&["ZZZ_NONEXISTENT_PATTERN_ZZZ", file_path_str],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark a literal search that matches a subset of lines.
|
||||||
|
#[divan::bench]
|
||||||
|
fn literal_match_some(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(uumain, &["POST", file_path_str]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark a literal search that matches every line (counting only).
|
||||||
|
///
|
||||||
|
/// `-c` keeps the output bounded so the benchmark measures matching rather than
|
||||||
|
/// terminal I/O.
|
||||||
|
#[divan::bench]
|
||||||
|
fn literal_match_all_count(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(uumain, &["-c", "HTTP", file_path_str]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark a fixed-string search (`-F`).
|
||||||
|
#[divan::bench]
|
||||||
|
fn fixed_string(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(
|
||||||
|
uumain,
|
||||||
|
&["-F", "Chrome/120.0", file_path_str],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark a case-insensitive search (`-i`).
|
||||||
|
#[divan::bench]
|
||||||
|
fn case_insensitive(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(uumain, &["-i", "mozilla", file_path_str]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark counting matches (`-c`).
|
||||||
|
#[divan::bench]
|
||||||
|
fn count(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(uumain, &["-c", "POST", file_path_str]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark an inverted match (`-v`).
|
||||||
|
///
|
||||||
|
/// Most lines do not contain "POST", so this selects the majority of lines;
|
||||||
|
/// `-c` bounds the output.
|
||||||
|
#[divan::bench]
|
||||||
|
fn invert_match_count(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(uumain, &["-vc", "POST", file_path_str]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark printing line numbers (`-n`).
|
||||||
|
#[divan::bench]
|
||||||
|
fn line_number(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(1_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(uumain, &["-nc", "POST", file_path_str]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark word-boundary matching (`-w`).
|
||||||
|
#[divan::bench]
|
||||||
|
fn word_match(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(uumain, &["-wc", "GET", file_path_str]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark an extended regular expression with alternation (`-E`).
|
||||||
|
#[divan::bench]
|
||||||
|
fn extended_regex(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(
|
||||||
|
uumain,
|
||||||
|
&["-Ec", "(POST|DELETE|PUT)", file_path_str],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark a basic regular expression with an anchor and character class.
|
||||||
|
#[divan::bench]
|
||||||
|
fn basic_regex(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(
|
||||||
|
uumain,
|
||||||
|
&["-c", "^192\\.168\\.[0-9]*\\.0 ", file_path_str],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark a Perl-compatible regular expression (`-P`).
|
||||||
|
#[divan::bench]
|
||||||
|
fn perl_regex(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(
|
||||||
|
uumain,
|
||||||
|
&["-Pc", "\"\\d{3}\" \\d+", file_path_str],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark `--only-matching` (`-o`) extracting a substring from each line.
|
||||||
|
#[divan::bench]
|
||||||
|
fn only_matching(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(1_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(
|
||||||
|
uumain,
|
||||||
|
&["-Eoc", "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+", file_path_str],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark quiet mode (`-q`), which can stop at the first match.
|
||||||
|
#[divan::bench]
|
||||||
|
fn quiet_first_match(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let file_path = create_test_file(&access_log(2_000_000), temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(uumain, &["-q", "POST", file_path_str]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark searching short numeric lines (many small lines).
|
||||||
|
#[divan::bench]
|
||||||
|
fn short_lines(bencher: Bencher) {
|
||||||
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
for i in 0..10_000_000 {
|
||||||
|
data.extend_from_slice(format!("{i}\n").as_bytes());
|
||||||
|
}
|
||||||
|
let file_path = create_test_file(&data, temp_dir.path());
|
||||||
|
let file_path_str = file_path.to_str().unwrap();
|
||||||
|
|
||||||
|
bencher.bench(|| {
|
||||||
|
black_box(run_util_function(uumain, &["-c", "999", file_path_str]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
divan::main();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user