Skip to content

Commit 0587c69

Browse files
committed
df: add benchmarks
1 parent 0004574 commit 0587c69

File tree

4 files changed

+72
-0
lines changed

4 files changed

+72
-0
lines changed

.github/workflows/benchmarks.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ jobs:
2828
- { package: uu_cp }
2929
- { package: uu_cut }
3030
- { package: uu_dd }
31+
- { package: uu_df }
3132
- { package: uu_du }
3233
- { package: uu_expand }
3334
- { package: uu_fold }

Cargo.lock

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

src/uu/df/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@ thiserror = { workspace = true }
2525
fluent = { workspace = true }
2626

2727
[dev-dependencies]
28+
divan = { workspace = true }
2829
tempfile = { workspace = true }
30+
uucore = { workspace = true, features = ["benchmark"] }
2931

3032
[[bin]]
3133
name = "df"
3234
path = "src/main.rs"
35+
36+
[[bench]]
37+
name = "df_bench"
38+
harness = false

src/uu/df/benches/df_bench.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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 std::env;
8+
use std::fs;
9+
use std::path::PathBuf;
10+
use tempfile::TempDir;
11+
use uu_df::uumain;
12+
use uucore::benchmark::run_util_function;
13+
14+
/// Create a deeply nested directory structure and return the path to the deepest level.
15+
/// Creates directories in chunks to avoid PATH_MAX limits.
16+
fn create_deep_directory(base_dir: &std::path::Path, depth: usize) -> PathBuf {
17+
let mut current = base_dir.to_path_buf();
18+
env::set_current_dir(&current).unwrap();
19+
20+
for _ in 0..depth {
21+
current = current.join("d");
22+
fs::create_dir("d").unwrap();
23+
env::set_current_dir("d").unwrap();
24+
}
25+
current
26+
}
27+
28+
/// Benchmark df running from a deeply nested directory (20000 levels).
29+
/// This tests the fix for issue #10117 where df was O(n²) slow in deep directories
30+
/// due to calling is_symlink() on relative device names like "tmpfs".
31+
#[divan::bench(sample_count = 300, sample_size = 1)]
32+
fn df_deep_directory(bencher: Bencher) {
33+
const DEPTH: usize = 20000;
34+
35+
// Save original directory
36+
let original_dir = env::current_dir().unwrap();
37+
38+
let temp_dir = TempDir::new().unwrap();
39+
// create_deep_directory changes cwd to the deepest level
40+
let _deep_path = create_deep_directory(temp_dir.path(), DEPTH);
41+
42+
// We're now in the deep directory, run the benchmark
43+
bencher.bench(|| {
44+
black_box(run_util_function(uumain, &[] as &[&str]));
45+
});
46+
47+
// Restore original directory
48+
env::set_current_dir(original_dir).unwrap();
49+
}
50+
51+
/// Benchmark df with explicit path argument (baseline, not affected by cwd depth)
52+
#[divan::bench(sample_count = 300, sample_size = 1)]
53+
fn df_with_path(bencher: Bencher) {
54+
let temp_dir = TempDir::new().unwrap();
55+
let temp_path_str = temp_dir.path().to_str().unwrap();
56+
57+
bencher.bench(|| {
58+
black_box(run_util_function(uumain, &[temp_path_str]));
59+
});
60+
}
61+
62+
fn main() {
63+
divan::main();
64+
}

0 commit comments

Comments
 (0)