Skip to content

Commit dbf46c8

Browse files
committed
expand: add a benchmark
1 parent b4f8eac commit dbf46c8

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/expand/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ uucore = { workspace = true }
2424
thiserror = { workspace = true }
2525
fluent = { workspace = true }
2626

27+
[dev-dependencies]
28+
divan = { workspace = true }
29+
tempfile = { workspace = true }
30+
uucore = { workspace = true, features = ["benchmark"] }
31+
2732
[[bin]]
2833
name = "expand"
2934
path = "src/main.rs"
35+
36+
[[bench]]
37+
name = "expand_bench"
38+
harness = false
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// This file is part of the uutils coreutils package.
2+
//
3+
// For the full copyright and license information, please view the LICENSE
4+
// file that was distributed with this source code.
5+
6+
use divan::{Bencher, black_box};
7+
use uu_expand::uumain;
8+
use uucore::benchmark::{create_test_file, run_util_function, text_data};
9+
10+
/// Helper function to run expand benchmark with generated data
11+
fn bench_expand(bencher: Bencher, data: impl AsRef<[u8]>, args: &[&str]) {
12+
let temp_dir = tempfile::tempdir().unwrap();
13+
let file_path = create_test_file(data.as_ref(), temp_dir.path());
14+
let file_path_str = file_path.to_str().unwrap();
15+
16+
let mut all_args = vec![];
17+
all_args.extend_from_slice(args);
18+
all_args.push(file_path_str);
19+
20+
bencher.bench(|| {
21+
black_box(run_util_function(uumain, &all_args));
22+
});
23+
}
24+
25+
/// Benchmark expanding tabs on files with many short lines
26+
#[divan::bench(args = [100_000])]
27+
fn expand_many_lines(bencher: Bencher, num_lines: usize) {
28+
let data = (0..num_lines)
29+
.map(|i| format!("line{}\tvalue{}\tdata{}\n", i, i * 2, i * 3))
30+
.collect::<String>();
31+
bench_expand(bencher, data, &[]);
32+
}
33+
34+
/// Benchmark expanding tabs with custom tab stops
35+
#[divan::bench(args = [50_000])]
36+
fn expand_custom_tabstops(bencher: Bencher, num_lines: usize) {
37+
let data = (0..num_lines)
38+
.map(|i| format!("a\tb\tc\td\te{}\n", i))
39+
.collect::<String>();
40+
bench_expand(bencher, data, &["--tabs=4,8,12"]);
41+
}
42+
43+
/// Benchmark expanding tabs on large file (by size)
44+
#[divan::bench(args = [10])]
45+
fn expand_large_file(bencher: Bencher, size_mb: usize) {
46+
let line = "word1\tword2\tword3\tword4\tword5\n";
47+
let repetitions = (size_mb * 1024 * 1024) / line.len();
48+
let data = line.repeat(repetitions);
49+
bench_expand(bencher, data, &[]);
50+
}
51+
52+
/// Benchmark with initial-only flag (only expand leading tabs)
53+
#[divan::bench(args = [50_000])]
54+
fn expand_initial_only(bencher: Bencher, num_lines: usize) {
55+
let data = (0..num_lines)
56+
.map(|i| format!("\t\tindented{}\tdata\n", i))
57+
.collect::<String>();
58+
bench_expand(bencher, data, &["--initial"]);
59+
}
60+
61+
/// Benchmark with no tabs (worst case - all processing, no expansion)
62+
#[divan::bench(args = [100_000])]
63+
fn expand_no_tabs(bencher: Bencher, num_lines: usize) {
64+
let data = text_data::generate_by_lines(num_lines, 80);
65+
bench_expand(bencher, data, &[]);
66+
}
67+
68+
/// Benchmark with UTF-8 disabled (ASCII mode)
69+
#[divan::bench(args = [50_000])]
70+
fn expand_ascii_mode(bencher: Bencher, num_lines: usize) {
71+
let data = (0..num_lines)
72+
.map(|i| format!("line{}\tvalue{}\n", i, i))
73+
.collect::<String>();
74+
bench_expand(bencher, data, &["--no-utf8"]);
75+
}
76+
77+
fn main() {
78+
divan::main();
79+
}

0 commit comments

Comments
 (0)