mirror of
https://github.com/uutils/coreutils.git
synced 2025-12-23 08:47:37 +00:00
bench: remove some duplication
This commit is contained in:
parent
b5ad68eaad
commit
bfaf5f7aef
2 changed files with 59 additions and 135 deletions
|
|
@ -4,12 +4,10 @@
|
|||
// file that was distributed with this source code.
|
||||
|
||||
use divan::{Bencher, black_box};
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::fs;
|
||||
use tempfile::TempDir;
|
||||
use uu_ls::uumain;
|
||||
use uucore::benchmark::run_util_function;
|
||||
use uucore::benchmark::{fs_tree, run_util_function};
|
||||
|
||||
/// Helper to run ls with given arguments on a directory
|
||||
fn bench_ls_with_args(bencher: Bencher, temp_dir: &TempDir, args: &[&str]) {
|
||||
|
|
@ -23,127 +21,6 @@ fn bench_ls_with_args(bencher: Bencher, temp_dir: &TempDir, args: &[&str]) {
|
|||
});
|
||||
}
|
||||
|
||||
/// Create a deterministic directory tree for benchmarking ls -R performance
|
||||
fn create_directory_tree(
|
||||
base_dir: &Path,
|
||||
depth: usize,
|
||||
dirs_per_level: usize,
|
||||
files_per_dir: usize,
|
||||
) -> std::io::Result<()> {
|
||||
if depth == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Create files in current directory
|
||||
for file_idx in 0..files_per_dir {
|
||||
let file_path = base_dir.join(format!("file_{file_idx:04}.txt"));
|
||||
let mut file = File::create(&file_path)?;
|
||||
writeln!(file, "This is file {file_idx} at depth {depth}")?;
|
||||
}
|
||||
|
||||
// Create subdirectories and recurse
|
||||
for dir_idx in 0..dirs_per_level {
|
||||
let dir_path = base_dir.join(format!("subdir_{dir_idx:04}"));
|
||||
fs::create_dir(&dir_path)?;
|
||||
create_directory_tree(&dir_path, depth - 1, dirs_per_level, files_per_dir)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a wide directory tree (many files/dirs at shallow depth)
|
||||
fn create_wide_tree(base_dir: &Path, total_files: usize, total_dirs: usize) -> std::io::Result<()> {
|
||||
// Create many files in root
|
||||
for file_idx in 0..total_files {
|
||||
let file_path = base_dir.join(format!("wide_file_{file_idx:06}.txt"));
|
||||
let mut file = File::create(&file_path)?;
|
||||
writeln!(file, "Wide tree file {file_idx}")?;
|
||||
}
|
||||
|
||||
// Create many directories with few files each
|
||||
let files_per_subdir = 5;
|
||||
for dir_idx in 0..total_dirs {
|
||||
let dir_path = base_dir.join(format!("wide_dir_{dir_idx:06}"));
|
||||
fs::create_dir(&dir_path)?;
|
||||
|
||||
for file_idx in 0..files_per_subdir {
|
||||
let file_path = dir_path.join(format!("file_{file_idx}.txt"));
|
||||
let mut file = File::create(&file_path)?;
|
||||
writeln!(file, "File {file_idx} in wide dir {dir_idx}")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a deep directory tree (few files/dirs but deep nesting)
|
||||
fn create_deep_tree(base_dir: &Path, depth: usize, files_per_level: usize) -> std::io::Result<()> {
|
||||
let mut current_dir = base_dir.to_path_buf();
|
||||
|
||||
for level in 0..depth {
|
||||
// Create files at this level
|
||||
for file_idx in 0..files_per_level {
|
||||
let file_path = current_dir.join(format!("deep_file_{level}_{file_idx}.txt"));
|
||||
let mut file = File::create(&file_path)?;
|
||||
writeln!(file, "File {file_idx} at depth level {level}")?;
|
||||
}
|
||||
|
||||
// Create next level directory
|
||||
if level < depth - 1 {
|
||||
let next_dir = current_dir.join(format!("level_{:04}", level + 1));
|
||||
fs::create_dir(&next_dir)?;
|
||||
current_dir = next_dir;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a tree with mixed file types and permissions for comprehensive testing
|
||||
fn create_mixed_tree(base_dir: &Path) -> std::io::Result<()> {
|
||||
let extensions = ["txt", "log", "dat", "tmp", "bak", "cfg"];
|
||||
let sizes = [0, 100, 1024, 10240];
|
||||
|
||||
for (i, ext) in extensions.iter().enumerate() {
|
||||
for (j, &size) in sizes.iter().enumerate() {
|
||||
let file_path = base_dir.join(format!("mixed_file_{i}_{j}.{ext}"));
|
||||
let mut file = File::create(&file_path)?;
|
||||
|
||||
if size > 0 {
|
||||
let content = "x".repeat(size);
|
||||
file.write_all(content.as_bytes())?;
|
||||
}
|
||||
|
||||
// Set permissions only on Unix platforms
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let perms = fs::Permissions::from_mode(match (i + j) % 4 {
|
||||
0 => 0o644,
|
||||
1 => 0o755,
|
||||
2 => 0o600,
|
||||
_ => 0o444,
|
||||
});
|
||||
fs::set_permissions(&file_path, perms)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create some subdirectories
|
||||
for i in 0..5 {
|
||||
let dir_path = base_dir.join(format!("mixed_subdir_{i}"));
|
||||
fs::create_dir(&dir_path)?;
|
||||
|
||||
for j in 0..3 {
|
||||
let file_path = dir_path.join(format!("sub_file_{j}.txt"));
|
||||
let mut file = File::create(&file_path)?;
|
||||
writeln!(file, "File {j} in subdir {i}")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Benchmark ls -R on balanced directory tree
|
||||
#[divan::bench(args = [(6, 4, 15)])]
|
||||
fn ls_recursive_balanced_tree(
|
||||
|
|
@ -151,7 +28,7 @@ fn ls_recursive_balanced_tree(
|
|||
(depth, dirs_per_level, files_per_dir): (usize, usize, usize),
|
||||
) {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
create_directory_tree(temp_dir.path(), depth, dirs_per_level, files_per_dir).unwrap();
|
||||
fs_tree::create_balanced_tree(temp_dir.path(), depth, dirs_per_level, files_per_dir);
|
||||
bench_ls_with_args(bencher, &temp_dir, &[]);
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +39,7 @@ fn ls_recursive_long_all_balanced_tree(
|
|||
(depth, dirs_per_level, files_per_dir): (usize, usize, usize),
|
||||
) {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
create_directory_tree(temp_dir.path(), depth, dirs_per_level, files_per_dir).unwrap();
|
||||
fs_tree::create_balanced_tree(temp_dir.path(), depth, dirs_per_level, files_per_dir);
|
||||
bench_ls_with_args(bencher, &temp_dir, &["-a", "-l"]);
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +47,7 @@ fn ls_recursive_long_all_balanced_tree(
|
|||
#[divan::bench(args = [(10000, 1000)])]
|
||||
fn ls_recursive_wide_tree(bencher: Bencher, (total_files, total_dirs): (usize, usize)) {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
create_wide_tree(temp_dir.path(), total_files, total_dirs).unwrap();
|
||||
fs_tree::create_wide_tree(temp_dir.path(), total_files, total_dirs);
|
||||
bench_ls_with_args(bencher, &temp_dir, &[]);
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +55,7 @@ fn ls_recursive_wide_tree(bencher: Bencher, (total_files, total_dirs): (usize, u
|
|||
#[divan::bench(args = [(15000, 1500)])]
|
||||
fn ls_recursive_long_all_wide_tree(bencher: Bencher, (total_files, total_dirs): (usize, usize)) {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
create_wide_tree(temp_dir.path(), total_files, total_dirs).unwrap();
|
||||
fs_tree::create_wide_tree(temp_dir.path(), total_files, total_dirs);
|
||||
bench_ls_with_args(bencher, &temp_dir, &["-a", "-l"]);
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +63,7 @@ fn ls_recursive_long_all_wide_tree(bencher: Bencher, (total_files, total_dirs):
|
|||
#[divan::bench(args = [(200, 2)])]
|
||||
fn ls_recursive_deep_tree(bencher: Bencher, (depth, files_per_level): (usize, usize)) {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
create_deep_tree(temp_dir.path(), depth, files_per_level).unwrap();
|
||||
fs_tree::create_deep_tree(temp_dir.path(), depth, files_per_level);
|
||||
bench_ls_with_args(bencher, &temp_dir, &[]);
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +71,7 @@ fn ls_recursive_deep_tree(bencher: Bencher, (depth, files_per_level): (usize, us
|
|||
#[divan::bench(args = [(100, 4)])]
|
||||
fn ls_recursive_long_all_deep_tree(bencher: Bencher, (depth, files_per_level): (usize, usize)) {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
create_deep_tree(temp_dir.path(), depth, files_per_level).unwrap();
|
||||
fs_tree::create_deep_tree(temp_dir.path(), depth, files_per_level);
|
||||
bench_ls_with_args(bencher, &temp_dir, &["-a", "-l"]);
|
||||
}
|
||||
|
||||
|
|
@ -202,12 +79,12 @@ fn ls_recursive_long_all_deep_tree(bencher: Bencher, (depth, files_per_level): (
|
|||
#[divan::bench]
|
||||
fn ls_recursive_mixed_tree(bencher: Bencher) {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
create_mixed_tree(temp_dir.path()).unwrap();
|
||||
fs_tree::create_mixed_tree(temp_dir.path());
|
||||
|
||||
for i in 0..10 {
|
||||
let subdir = temp_dir.path().join(format!("mixed_branch_{i}"));
|
||||
fs::create_dir(&subdir).unwrap();
|
||||
create_mixed_tree(&subdir).unwrap();
|
||||
fs_tree::create_mixed_tree(&subdir);
|
||||
}
|
||||
|
||||
bench_ls_with_args(bencher, &temp_dir, &[]);
|
||||
|
|
@ -217,12 +94,12 @@ fn ls_recursive_mixed_tree(bencher: Bencher) {
|
|||
#[divan::bench]
|
||||
fn ls_recursive_long_all_mixed_tree(bencher: Bencher) {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
create_mixed_tree(temp_dir.path()).unwrap();
|
||||
fs_tree::create_mixed_tree(temp_dir.path());
|
||||
|
||||
for i in 0..10 {
|
||||
let subdir = temp_dir.path().join(format!("mixed_branch_{i}"));
|
||||
fs::create_dir(&subdir).unwrap();
|
||||
create_mixed_tree(&subdir).unwrap();
|
||||
fs_tree::create_mixed_tree(&subdir);
|
||||
}
|
||||
|
||||
bench_ls_with_args(bencher, &temp_dir, &["-a", "-l"]);
|
||||
|
|
|
|||
|
|
@ -311,6 +311,7 @@ pub mod text_data {
|
|||
/// Filesystem tree generation utilities for benchmarking
|
||||
pub mod fs_tree {
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
/// Create a balanced directory tree for benchmarking
|
||||
|
|
@ -383,4 +384,50 @@ pub mod fs_tree {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a tree with mixed file types and permissions for comprehensive testing
|
||||
///
|
||||
/// Creates files with different extensions, sizes, and permissions (on Unix).
|
||||
/// Useful for testing file type detection, permission handling, and formatting.
|
||||
pub fn create_mixed_tree(base_dir: &Path) {
|
||||
let extensions = ["txt", "log", "dat", "tmp", "bak", "cfg"];
|
||||
let sizes = [0, 100, 1024, 10240];
|
||||
|
||||
for (i, ext) in extensions.iter().enumerate() {
|
||||
for (j, &size) in sizes.iter().enumerate() {
|
||||
let file_path = base_dir.join(format!("mixed_file_{i}_{j}.{ext}"));
|
||||
let mut file = File::create(&file_path).unwrap();
|
||||
|
||||
if size > 0 {
|
||||
let content = "x".repeat(size);
|
||||
file.write_all(content.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
// Set permissions only on Unix platforms
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let perms = fs::Permissions::from_mode(match (i + j) % 4 {
|
||||
0 => 0o644,
|
||||
1 => 0o755,
|
||||
2 => 0o600,
|
||||
_ => 0o444,
|
||||
});
|
||||
fs::set_permissions(&file_path, perms).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create some subdirectories
|
||||
for i in 0..5 {
|
||||
let dir_path = base_dir.join(format!("mixed_subdir_{i}"));
|
||||
fs::create_dir(&dir_path).unwrap();
|
||||
|
||||
for j in 0..3 {
|
||||
let file_path = dir_path.join(format!("sub_file_{j}.txt"));
|
||||
let mut file = File::create(&file_path).unwrap();
|
||||
writeln!(file, "File {j} in subdir {i}").unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue