join: add benchmarks (#10005)

This commit is contained in:
WaterWhisperer
2026-01-03 20:22:18 +08:00
committed by GitHub
parent ea64612efb
commit e4d35b03bf
4 changed files with 127 additions and 0 deletions
+1
View File
@@ -31,6 +31,7 @@ jobs:
- { package: uu_du }
- { package: uu_expand }
- { package: uu_fold }
- { package: uu_join }
- { package: uu_ls }
- { package: uu_mv }
- { package: uu_nl }
Generated
+2
View File
@@ -3462,8 +3462,10 @@ name = "uu_join"
version = "0.5.0"
dependencies = [
"clap",
"codspeed-divan-compat",
"fluent",
"memchr",
"tempfile",
"thiserror 2.0.17",
"uucore",
]
+9
View File
@@ -27,3 +27,12 @@ fluent = { workspace = true }
[[bin]]
name = "join"
path = "src/main.rs"
[dev-dependencies]
divan = { workspace = true }
tempfile = { workspace = true }
uucore = { workspace = true, features = ["benchmark"] }
[[bench]]
name = "join_bench"
harness = false
+115
View File
@@ -0,0 +1,115 @@
// This file is part of the uutils coreutils package.
//
// 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 std::{fs::File, io::Write};
use tempfile::TempDir;
use uu_join::uumain;
use uucore::benchmark::run_util_function;
/// Create two sorted files with matching keys for join benchmarking
fn create_join_files(temp_dir: &TempDir, num_lines: usize) -> (String, String) {
let file1_path = temp_dir.path().join("file1.txt");
let file2_path = temp_dir.path().join("file2.txt");
let mut file1 = File::create(&file1_path).unwrap();
let mut file2 = File::create(&file2_path).unwrap();
for i in 0..num_lines {
writeln!(file1, "{i:08} field1_{i} field2_{i}").unwrap();
writeln!(file2, "{i:08} data1_{i} data2_{i}").unwrap();
}
(
file1_path.to_str().unwrap().to_string(),
file2_path.to_str().unwrap().to_string(),
)
}
/// Create two files with partial overlap for join benchmarking
fn create_partial_overlap_files(
temp_dir: &TempDir,
num_lines: usize,
overlap_ratio: f64,
) -> (String, String) {
let file1_path = temp_dir.path().join("file1.txt");
let file2_path = temp_dir.path().join("file2.txt");
let mut file1 = File::create(&file1_path).unwrap();
let mut file2 = File::create(&file2_path).unwrap();
let overlap_count = (num_lines as f64 * overlap_ratio) as usize;
// File 1: keys 0 to num_lines-1
for i in 0..num_lines {
writeln!(file1, "{i:08} f1_data_{i}").unwrap();
}
// File 2: keys (num_lines - overlap_count) to (2*num_lines - overlap_count - 1)
let start = num_lines - overlap_count;
for i in 0..num_lines {
writeln!(file2, "{:08} f2_data_{}", start + i, i).unwrap();
}
(
file1_path.to_str().unwrap().to_string(),
file2_path.to_str().unwrap().to_string(),
)
}
/// Benchmark basic join with fully matching keys
#[divan::bench]
fn join_full_match(bencher: Bencher) {
let num_lines = 10000;
let temp_dir = TempDir::new().unwrap();
let (file1, file2) = create_join_files(&temp_dir, num_lines);
bencher.bench(|| {
black_box(run_util_function(uumain, &[&file1, &file2]));
});
}
/// Benchmark join with partial overlap (50%)
#[divan::bench]
fn join_partial_overlap(bencher: Bencher) {
let num_lines = 10000;
let temp_dir = TempDir::new().unwrap();
let (file1, file2) = create_partial_overlap_files(&temp_dir, num_lines, 0.5);
bencher.bench(|| {
black_box(run_util_function(uumain, &[&file1, &file2]));
});
}
/// Benchmark join with custom field separator
#[divan::bench]
fn join_custom_separator(bencher: Bencher) {
let num_lines = 10000;
let temp_dir = TempDir::new().unwrap();
let file1_path = temp_dir.path().join("file1.txt");
let file2_path = temp_dir.path().join("file2.txt");
let mut file1 = File::create(&file1_path).unwrap();
let mut file2 = File::create(&file2_path).unwrap();
for i in 0..num_lines {
writeln!(file1, "{i:08}\tfield1_{i}\tfield2_{i}").unwrap();
writeln!(file2, "{i:08}\tdata1_{i}\tdata2_{i}").unwrap();
}
let file1_str = file1_path.to_str().unwrap();
let file2_str = file2_path.to_str().unwrap();
bencher.bench(|| {
black_box(run_util_function(
uumain,
&["-t", "\t", file1_str, file2_str],
));
});
}
fn main() {
divan::main();
}