Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 5 additions & 21 deletions src/uu/cp/benches/cp_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,11 @@
// file that was distributed with this source code.

use divan::{Bencher, black_box};
use std::fs::{self, File};
use std::io::Write;
use std::fs;
use std::path::Path;
use tempfile::TempDir;
use uu_cp::uumain;
use uucore::benchmark::{fs_tree, run_util_function};

fn remove_path(path: &Path) {
if !path.exists() {
return;
}

if path.is_dir() {
fs::remove_dir_all(path).unwrap();
} else {
fs::remove_file(path).unwrap();
}
}
use uucore::benchmark::{binary_data, fs_tree, fs_utils, run_util_function};

fn bench_cp_directory<F>(bencher: Bencher, args: &[&str], setup_source: F)
where
Expand All @@ -38,7 +25,7 @@ where
let dest_str = dest.to_str().unwrap();

bencher.bench(|| {
remove_path(&dest);
fs_utils::remove_path(&dest);

let mut full_args = Vec::with_capacity(args.len() + 2);
full_args.extend_from_slice(args);
Expand Down Expand Up @@ -99,16 +86,13 @@ fn cp_large_file(bencher: Bencher, size_mb: usize) {
let source = temp_dir.path().join("source.bin");
let dest = temp_dir.path().join("dest.bin");

let buffer = vec![b'x'; size_mb * 1024 * 1024];
let mut file = File::create(&source).unwrap();
file.write_all(&buffer).unwrap();
file.sync_all().unwrap();
binary_data::create_file(&source, size_mb, b'x');

let source_str = source.to_str().unwrap();
let dest_str = dest.to_str().unwrap();

bencher.bench(|| {
remove_path(&dest);
fs_utils::remove_path(&dest);

black_box(run_util_function(uumain, &[source_str, dest_str]));
});
Expand Down
99 changes: 46 additions & 53 deletions src/uu/dd/benches/dd_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,25 @@
// 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 tempfile::TempDir;
use uu_dd::uumain;
use uucore::benchmark::run_util_function;

fn create_test_file(path: &Path, size_mb: usize) {
let buffer = vec![b'x'; size_mb * 1024 * 1024];
let mut file = File::create(path).unwrap();
file.write_all(&buffer).unwrap();
file.sync_all().unwrap();
}

fn remove_file(path: &Path) {
if path.exists() {
fs::remove_file(path).unwrap();
}
}
use uucore::benchmark::{binary_data, fs_utils, run_util_function};

/// Benchmark basic dd copy with default settings
#[divan::bench(args = [32])]
fn dd_copy_default(bencher: Bencher, size_mb: usize) {
#[divan::bench]
fn dd_copy_default(bencher: Bencher) {
let size_mb = 32;
let temp_dir = TempDir::new().unwrap();
let input = temp_dir.path().join("input.bin");
let output = temp_dir.path().join("output.bin");

create_test_file(&input, size_mb);
binary_data::create_file(&input, size_mb, b'x');

let input_str = input.to_str().unwrap();
let output_str = output.to_str().unwrap();

bencher.bench(|| {
remove_file(&output);
fs_utils::remove_path(&output);
black_box(run_util_function(
uumain,
&[
Expand All @@ -50,19 +35,20 @@ fn dd_copy_default(bencher: Bencher, size_mb: usize) {
}

/// Benchmark dd copy with 4KB block size (common page size)
#[divan::bench(args = [24])]
fn dd_copy_4k_blocks(bencher: Bencher, size_mb: usize) {
#[divan::bench]
fn dd_copy_4k_blocks(bencher: Bencher) {
let size_mb = 24;
let temp_dir = TempDir::new().unwrap();
let input = temp_dir.path().join("input.bin");
let output = temp_dir.path().join("output.bin");

create_test_file(&input, size_mb);
binary_data::create_file(&input, size_mb, b'x');

let input_str = input.to_str().unwrap();
let output_str = output.to_str().unwrap();

bencher.bench(|| {
remove_file(&output);
fs_utils::remove_path(&output);
black_box(run_util_function(
uumain,
&[
Expand All @@ -76,19 +62,20 @@ fn dd_copy_4k_blocks(bencher: Bencher, size_mb: usize) {
}

/// Benchmark dd copy with 64KB block size
#[divan::bench(args = [64])]
fn dd_copy_64k_blocks(bencher: Bencher, size_mb: usize) {
#[divan::bench]
fn dd_copy_64k_blocks(bencher: Bencher) {
let size_mb = 64;
let temp_dir = TempDir::new().unwrap();
let input = temp_dir.path().join("input.bin");
let output = temp_dir.path().join("output.bin");

create_test_file(&input, size_mb);
binary_data::create_file(&input, size_mb, b'x');

let input_str = input.to_str().unwrap();
let output_str = output.to_str().unwrap();

bencher.bench(|| {
remove_file(&output);
fs_utils::remove_path(&output);
black_box(run_util_function(
uumain,
&[
Expand All @@ -102,19 +89,20 @@ fn dd_copy_64k_blocks(bencher: Bencher, size_mb: usize) {
}

/// Benchmark dd copy with 1MB block size
#[divan::bench(args = [128])]
fn dd_copy_1m_blocks(bencher: Bencher, size_mb: usize) {
#[divan::bench]
fn dd_copy_1m_blocks(bencher: Bencher) {
let size_mb = 128;
let temp_dir = TempDir::new().unwrap();
let input = temp_dir.path().join("input.bin");
let output = temp_dir.path().join("output.bin");

create_test_file(&input, size_mb);
binary_data::create_file(&input, size_mb, b'x');

let input_str = input.to_str().unwrap();
let output_str = output.to_str().unwrap();

bencher.bench(|| {
remove_file(&output);
fs_utils::remove_path(&output);
black_box(run_util_function(
uumain,
&[
Expand All @@ -128,19 +116,20 @@ fn dd_copy_1m_blocks(bencher: Bencher, size_mb: usize) {
}

/// Benchmark dd copy with separate input and output block sizes
#[divan::bench(args = [48])]
fn dd_copy_separate_blocks(bencher: Bencher, size_mb: usize) {
#[divan::bench]
fn dd_copy_separate_blocks(bencher: Bencher) {
let size_mb = 48;
let temp_dir = TempDir::new().unwrap();
let input = temp_dir.path().join("input.bin");
let output = temp_dir.path().join("output.bin");

create_test_file(&input, size_mb);
binary_data::create_file(&input, size_mb, b'x');

let input_str = input.to_str().unwrap();
let output_str = output.to_str().unwrap();

bencher.bench(|| {
remove_file(&output);
fs_utils::remove_path(&output);
black_box(run_util_function(
uumain,
&[
Expand All @@ -155,19 +144,20 @@ fn dd_copy_separate_blocks(bencher: Bencher, size_mb: usize) {
}

/// Benchmark dd with count limit (partial copy)
#[divan::bench(args = [32])]
fn dd_copy_partial(bencher: Bencher, size_mb: usize) {
#[divan::bench]
fn dd_copy_partial(bencher: Bencher) {
let size_mb = 32;
let temp_dir = TempDir::new().unwrap();
let input = temp_dir.path().join("input.bin");
let output = temp_dir.path().join("output.bin");

create_test_file(&input, size_mb);
binary_data::create_file(&input, size_mb, b'x');

let input_str = input.to_str().unwrap();
let output_str = output.to_str().unwrap();

bencher.bench(|| {
remove_file(&output);
fs_utils::remove_path(&output);
black_box(run_util_function(
uumain,
&[
Expand All @@ -182,19 +172,20 @@ fn dd_copy_partial(bencher: Bencher, size_mb: usize) {
}

/// Benchmark dd with skip (seeking in input)
#[divan::bench(args = [48])]
fn dd_copy_with_skip(bencher: Bencher, size_mb: usize) {
#[divan::bench]
fn dd_copy_with_skip(bencher: Bencher) {
let size_mb = 48;
let temp_dir = TempDir::new().unwrap();
let input = temp_dir.path().join("input.bin");
let output = temp_dir.path().join("output.bin");

create_test_file(&input, size_mb);
binary_data::create_file(&input, size_mb, b'x');

let input_str = input.to_str().unwrap();
let output_str = output.to_str().unwrap();

bencher.bench(|| {
remove_file(&output);
fs_utils::remove_path(&output);
black_box(run_util_function(
uumain,
&[
Expand All @@ -209,19 +200,20 @@ fn dd_copy_with_skip(bencher: Bencher, size_mb: usize) {
}

/// Benchmark dd with seek (seeking in output)
#[divan::bench(args = [48])]
fn dd_copy_with_seek(bencher: Bencher, size_mb: usize) {
#[divan::bench]
fn dd_copy_with_seek(bencher: Bencher) {
let size_mb = 48;
let temp_dir = TempDir::new().unwrap();
let input = temp_dir.path().join("input.bin");
let output = temp_dir.path().join("output.bin");

create_test_file(&input, size_mb);
binary_data::create_file(&input, size_mb, b'x');

let input_str = input.to_str().unwrap();
let output_str = output.to_str().unwrap();

bencher.bench(|| {
remove_file(&output);
fs_utils::remove_path(&output);
black_box(run_util_function(
uumain,
&[
Expand All @@ -236,19 +228,20 @@ fn dd_copy_with_seek(bencher: Bencher, size_mb: usize) {
}

/// Benchmark dd with different block sizes for comparison
#[divan::bench(args = [32])]
fn dd_copy_8k_blocks(bencher: Bencher, size_mb: usize) {
#[divan::bench]
fn dd_copy_8k_blocks(bencher: Bencher) {
let size_mb = 32;
let temp_dir = TempDir::new().unwrap();
let input = temp_dir.path().join("input.bin");
let output = temp_dir.path().join("output.bin");

create_test_file(&input, size_mb);
binary_data::create_file(&input, size_mb, b'x');

let input_str = input.to_str().unwrap();
let output_str = output.to_str().unwrap();

bencher.bench(|| {
remove_file(&output);
fs_utils::remove_path(&output);
black_box(run_util_function(
uumain,
&[
Expand Down
40 changes: 40 additions & 0 deletions src/uucore/src/lib/features/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,46 @@ pub mod text_data {
}
}

/// Binary data generation utilities for benchmarking
pub mod binary_data {
use std::fs::File;
use std::io::Write;
use std::path::Path;

/// Create a binary file filled with a repeated pattern
///
/// Creates a file of the specified size (in MB) filled with the given byte pattern.
/// This is useful for benchmarking utilities that work with large binary files like dd, cp, etc.
pub fn create_file(path: &Path, size_mb: usize, pattern: u8) {
let buffer = vec![pattern; size_mb * 1024 * 1024];
let mut file = File::create(path).unwrap();
file.write_all(&buffer).unwrap();
file.sync_all().unwrap();
}
}

/// Filesystem utilities for benchmarking
pub mod fs_utils {
use std::fs;
use std::path::Path;

/// Remove a file or directory if it exists
///
/// This is a convenience function for cleaning up between benchmark iterations.
/// It handles both files and directories, and is a no-op if the path doesn't exist.
pub fn remove_path(path: &Path) {
if !path.exists() {
return;
}

if path.is_dir() {
fs::remove_dir_all(path).unwrap();
} else {
fs::remove_file(path).unwrap();
}
}
}

/// Filesystem tree generation utilities for benchmarking
pub mod fs_tree {
use std::fs::{self, File};
Expand Down
Loading