mirror of
https://github.com/uutils/coreutils.git
synced 2025-12-23 08:47:37 +00:00
benchmark: create some tree functions
This commit is contained in:
parent
4180c00c73
commit
c4d8b4b5bf
2 changed files with 86 additions and 73 deletions
|
|
@ -4,11 +4,9 @@
|
|||
// file that was distributed with this source code.
|
||||
|
||||
use divan::{Bencher, black_box};
|
||||
use std::fs::{self, File};
|
||||
use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use uu_du::uumain;
|
||||
use uucore::benchmark::run_util_function;
|
||||
use uucore::benchmark::{fs_tree, run_util_function};
|
||||
|
||||
/// Helper to run du with given arguments on a directory
|
||||
fn bench_du_with_args(bencher: Bencher, temp_dir: &TempDir, args: &[&str]) {
|
||||
|
|
@ -21,68 +19,6 @@ fn bench_du_with_args(bencher: Bencher, temp_dir: &TempDir, args: &[&str]) {
|
|||
});
|
||||
}
|
||||
|
||||
/// Create a balanced directory tree for benchmarking
|
||||
fn create_directory_tree(
|
||||
base_dir: &Path,
|
||||
depth: usize,
|
||||
dirs_per_level: usize,
|
||||
files_per_dir: usize,
|
||||
) {
|
||||
if depth == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create files in current directory
|
||||
for file_idx in 0..files_per_dir {
|
||||
let file_path = base_dir.join(format!("f{file_idx}"));
|
||||
File::create(&file_path).unwrap();
|
||||
}
|
||||
|
||||
// Create subdirectories and recurse
|
||||
for dir_idx in 0..dirs_per_level {
|
||||
let dir_path = base_dir.join(format!("d{dir_idx}"));
|
||||
fs::create_dir(&dir_path).unwrap();
|
||||
create_directory_tree(&dir_path, depth - 1, dirs_per_level, files_per_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a wide directory tree (many files/dirs at shallow depth)
|
||||
fn create_wide_tree(base_dir: &Path, total_files: usize, total_dirs: usize) {
|
||||
// Create many files in root
|
||||
for file_idx in 0..total_files {
|
||||
let file_path = base_dir.join(format!("f{file_idx}"));
|
||||
File::create(&file_path).unwrap();
|
||||
}
|
||||
|
||||
// Create many directories with few files each
|
||||
for dir_idx in 0..total_dirs {
|
||||
let dir_path = base_dir.join(format!("d{dir_idx}"));
|
||||
fs::create_dir(&dir_path).unwrap();
|
||||
for file_idx in 0..5 {
|
||||
File::create(dir_path.join(format!("f{file_idx}"))).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a deep directory tree (deep nesting)
|
||||
fn create_deep_tree(base_dir: &Path, depth: usize, files_per_level: usize) {
|
||||
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 {
|
||||
File::create(current_dir.join(format!("f{file_idx}"))).unwrap();
|
||||
}
|
||||
|
||||
// Create next level directory
|
||||
if level < depth - 1 {
|
||||
let next_dir = current_dir.join("d");
|
||||
fs::create_dir(&next_dir).unwrap();
|
||||
current_dir = next_dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Benchmark default du on balanced tree
|
||||
#[divan::bench(args = [(5, 4, 10)])]
|
||||
fn du_balanced_tree(
|
||||
|
|
@ -90,7 +26,7 @@ fn du_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);
|
||||
fs_tree::create_balanced_tree(temp_dir.path(), depth, dirs_per_level, files_per_dir);
|
||||
bench_du_with_args(bencher, &temp_dir, &[]);
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +37,7 @@ fn du_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);
|
||||
fs_tree::create_balanced_tree(temp_dir.path(), depth, dirs_per_level, files_per_dir);
|
||||
bench_du_with_args(bencher, &temp_dir, &["-a"]);
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +48,7 @@ fn du_human_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);
|
||||
fs_tree::create_balanced_tree(temp_dir.path(), depth, dirs_per_level, files_per_dir);
|
||||
bench_du_with_args(bencher, &temp_dir, &["-h"]);
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +56,7 @@ fn du_human_balanced_tree(
|
|||
#[divan::bench(args = [(5000, 500)])]
|
||||
fn du_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);
|
||||
fs_tree::create_wide_tree(temp_dir.path(), total_files, total_dirs);
|
||||
bench_du_with_args(bencher, &temp_dir, &[]);
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +64,7 @@ fn du_wide_tree(bencher: Bencher, (total_files, total_dirs): (usize, usize)) {
|
|||
#[divan::bench(args = [(5000, 500)])]
|
||||
fn du_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);
|
||||
fs_tree::create_wide_tree(temp_dir.path(), total_files, total_dirs);
|
||||
bench_du_with_args(bencher, &temp_dir, &["-a"]);
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +72,7 @@ fn du_all_wide_tree(bencher: Bencher, (total_files, total_dirs): (usize, usize))
|
|||
#[divan::bench(args = [(100, 3)])]
|
||||
fn du_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);
|
||||
fs_tree::create_deep_tree(temp_dir.path(), depth, files_per_level);
|
||||
bench_du_with_args(bencher, &temp_dir, &[]);
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +83,7 @@ fn du_summarize_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);
|
||||
fs_tree::create_balanced_tree(temp_dir.path(), depth, dirs_per_level, files_per_dir);
|
||||
bench_du_with_args(bencher, &temp_dir, &["-s"]);
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +94,7 @@ fn du_max_depth_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);
|
||||
fs_tree::create_balanced_tree(temp_dir.path(), depth, dirs_per_level, files_per_dir);
|
||||
bench_du_with_args(bencher, &temp_dir, &["--max-depth=2"]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -307,3 +307,80 @@ pub mod text_data {
|
|||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
/// Filesystem tree generation utilities for benchmarking
|
||||
pub mod fs_tree {
|
||||
use std::fs::{self, File};
|
||||
use std::path::Path;
|
||||
|
||||
/// Create a balanced directory tree for benchmarking
|
||||
///
|
||||
/// Creates a tree with specified depth, number of directories per level, and files per directory.
|
||||
/// This creates a realistic filesystem structure for testing recursive operations.
|
||||
pub fn create_balanced_tree(
|
||||
base_dir: &Path,
|
||||
depth: usize,
|
||||
dirs_per_level: usize,
|
||||
files_per_dir: usize,
|
||||
) {
|
||||
if depth == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create files in current directory
|
||||
for file_idx in 0..files_per_dir {
|
||||
let file_path = base_dir.join(format!("f{file_idx}"));
|
||||
File::create(&file_path).unwrap();
|
||||
}
|
||||
|
||||
// Create subdirectories and recurse
|
||||
for dir_idx in 0..dirs_per_level {
|
||||
let dir_path = base_dir.join(format!("d{dir_idx}"));
|
||||
fs::create_dir(&dir_path).unwrap();
|
||||
create_balanced_tree(&dir_path, depth - 1, dirs_per_level, files_per_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a wide directory tree (many files/dirs at shallow depth)
|
||||
///
|
||||
/// This creates a flat structure with many files and directories at a shallow depth,
|
||||
/// useful for benchmarking operations that need to traverse many entries quickly.
|
||||
pub fn create_wide_tree(base_dir: &Path, total_files: usize, total_dirs: usize) {
|
||||
// Create many files in root
|
||||
for file_idx in 0..total_files {
|
||||
let file_path = base_dir.join(format!("f{file_idx}"));
|
||||
File::create(&file_path).unwrap();
|
||||
}
|
||||
|
||||
// Create many directories with few files each
|
||||
for dir_idx in 0..total_dirs {
|
||||
let dir_path = base_dir.join(format!("d{dir_idx}"));
|
||||
fs::create_dir(&dir_path).unwrap();
|
||||
for file_idx in 0..5 {
|
||||
File::create(dir_path.join(format!("f{file_idx}"))).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a deep directory tree (deep nesting)
|
||||
///
|
||||
/// This creates a linear chain of deeply nested directories, useful for testing
|
||||
/// recursion depth handling and stack usage.
|
||||
pub fn create_deep_tree(base_dir: &Path, depth: usize, files_per_level: usize) {
|
||||
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 {
|
||||
File::create(current_dir.join(format!("f{file_idx}"))).unwrap();
|
||||
}
|
||||
|
||||
// Create next level directory
|
||||
if level < depth - 1 {
|
||||
let next_dir = current_dir.join("d");
|
||||
fs::create_dir(&next_dir).unwrap();
|
||||
current_dir = next_dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue