|
1 | | -#![allow(unused)] |
2 | | -// This file is part of the uutils diffutils package. |
3 | | -// |
4 | | -// For the full copyright and license information, please view the LICENSE-* |
5 | | -// files that was distributed with this source code. |
6 | | - |
7 | | -//! Benches for all utils in diffutils. |
8 | | -//! |
9 | | -//! There is a file generator included to create files of different sizes for comparison. \ |
10 | | -//! Set the TEMP_DIR const to keep the files. df_to_ files have small changes in them, search for '#'. \ |
11 | | -//! File generation up to 1 GB is really fast, Benchmarking above 100 MB takes very long. |
12 | | -
|
13 | | -/// Generate test files with these sizes in KB. |
14 | | -const FILE_SIZES_IN_KILO_BYTES: [u64; 4] = [100, 1 * MB, 10 * MB, 25 * MB]; |
15 | | -const NUM_DIFF: u64 = 4; |
16 | | -// Empty String to use TempDir (files will be removed after test) or specify dir to keep generated files |
17 | | -const TEMP_DIR: &str = ""; |
18 | | -// just for FILE_SIZE_KILO_BYTES |
19 | | -const MB: u64 = 1_000; |
20 | | - |
21 | | -use std::sync::OnceLock; |
22 | | - |
23 | | -use divan::Bencher; |
24 | | -use tempfile::TempDir; |
25 | | -use uu_cmp::{params_cmp::Params, uu_app}; |
26 | | -// use uu_cmp::parse_params; |
27 | | -// use uu_cmp::uumain; |
28 | | -use uudiff::benchmark::{ |
29 | | - bench_binary, |
30 | | - prepare_bench::{BenchContext, generate_test_files_bytes}, |
31 | | - str_to_args, |
32 | | -}; |
33 | | - |
34 | | -// bench the time it takes to parse the command line arguments |
35 | | -#[divan::bench] |
36 | | -fn cmp_parser(bencher: Bencher) { |
37 | | - let cmd = "cmd file_1.txt file_2.txt -bl -n10M --ignore-initial=100KiB:1MiB"; |
38 | | - let args = str_to_args(&cmd).into_iter().peekable(); |
39 | | - bencher.with_inputs(|| args.clone()).bench_values( |
40 | | - // |params: std::iter::Peekable<std::vec::IntoIter<std::ffi::OsString>>| parse_params(params), |
41 | | - |params: std::iter::Peekable<std::vec::IntoIter<std::ffi::OsString>>| { |
42 | | - let matches = uudiff::clap_localization::handle_clap_result(uu_app(), params).unwrap(); |
43 | | - let params: Params = matches.try_into().unwrap(); |
44 | | - }, |
45 | | - ); |
46 | | - // ); |
47 | | -} |
48 | | - |
49 | | -// // // test the impact on the benchmark if not converting the cmd to Vec<OsString> (doubles for parse) |
50 | | -// #[divan::bench] |
51 | | -// fn cmp_parser_no_prepare() { |
52 | | -// let cmd = "cmd file_1.txt file_2.txt -bl n10M --ignore-initial=100KiB:1MiB"; |
53 | | -// let args = str_to_args(&cmd).into_iter().peekable(); |
54 | | -// let _ = parse_params(args); |
55 | | -// } |
56 | | - |
57 | | -// bench equal, full file read |
58 | | -#[divan::bench(args = FILE_SIZES_IN_KILO_BYTES)] |
59 | | -fn cmp_compare_files_equal(bencher: Bencher, kb: u64) { |
60 | | - let fp = get_context().get_files_equal_kb(kb).unwrap(); |
61 | | - let cmd = format!("cmp {} {}", fp.from, fp.to); |
62 | | - let args = str_to_args(&cmd).into_iter(); |
63 | | - |
64 | | - bencher |
65 | | - // .with_inputs(|| prepare::cmp_params_identical_testfiles(lines)) |
66 | | - .with_inputs(|| args.clone()) |
67 | | - .bench_refs(|params| uu_cmp::uumain(params.peekable())); |
68 | | -} |
69 | | - |
70 | | -// bench different; cmp exits on first difference |
71 | | -#[divan::bench(args = FILE_SIZES_IN_KILO_BYTES)] |
72 | | -fn cmp_compare_files_different(bencher: Bencher, kb: u64) { |
73 | | - let fp = get_context().get_files_different_kb(kb).unwrap(); |
74 | | - let cmd = format!("cmp -s {} {}", fp.from, fp.to); |
75 | | - let args = str_to_args(&cmd).into_iter(); |
76 | | - |
77 | | - bencher |
78 | | - // .with_inputs(|| prepare::cmp_params_identical_testfiles(lines)) |
79 | | - .with_inputs(|| args.clone()) |
80 | | - .bench_refs(|params| uu_cmp::uumain(params.peekable())); |
81 | | -} |
82 | | - |
83 | | -// TODO use coreutils bench logic |
84 | | -// bench original GNU cmp |
85 | | -#[cfg(feature = "feat_run_binary_bench")] |
86 | | -#[divan::bench(args = FILE_SIZES_IN_KILO_BYTES)] |
87 | | -fn cmd_cmp_gnu_equal(bencher: Bencher, kb: u64) { |
88 | | - let fp = get_context().get_files_equal_kb(kb).unwrap(); |
89 | | - let args_str = format!("{} {}", fp.from, fp.to); |
90 | | - bencher |
91 | | - // .with_inputs(|| prepare::cmp_params_identical_testfiles(lines)) |
92 | | - .with_inputs(|| args_str.clone()) |
93 | | - .bench_refs(|cmd_args| bench_binary::bench_binary("cmp", cmd_args)); |
94 | | -} |
95 | | - |
96 | | -// bench the compiled release version |
97 | | -#[cfg(feature = "feat_run_binary_bench")] |
98 | | -#[divan::bench(args = FILE_SIZES_IN_KILO_BYTES)] |
99 | | -fn cmd_cmp_release_equal(bencher: Bencher, kb: u64) { |
100 | | - // search for src, then shorten path |
101 | | - let dir = std::env::current_dir().unwrap(); |
102 | | - let path = dir.to_string_lossy(); |
103 | | - let path = path.trim_end_matches("src/uu/cmp"); |
104 | | - let prg = path.to_string() + "target/release/cmp"; |
105 | | - |
106 | | - let fp = get_context().get_files_equal_kb(kb).unwrap(); |
107 | | - let args_str = format!("{} {}", fp.from, fp.to); |
108 | | - |
109 | | - bencher |
110 | | - // .with_inputs(|| prepare::cmp_params_identical_testfiles(lines)) |
111 | | - .with_inputs(|| args_str.clone()) |
112 | | - .bench_refs(|cmd_args| bench_binary::bench_binary(&prg, cmd_args)); |
113 | | -} |
114 | | - |
115 | | -// Since each bench function is separate in Divan it is more difficult to dynamically create test data. |
116 | | -// This keeps the TempDir alive until the program exits and generates the files only once. |
117 | | -static SHARED_CONTEXT: OnceLock<BenchContext> = OnceLock::new(); |
118 | | -/// Creates the test files once and provides them to all tests. |
119 | | -pub fn get_context() -> &'static BenchContext { |
120 | | - SHARED_CONTEXT.get_or_init(|| { |
121 | | - let mut ctx = BenchContext::default(); |
122 | | - if TEMP_DIR.is_empty() { |
123 | | - let tmp_dir = TempDir::new().expect("Failed to create temp dir"); |
124 | | - ctx.tmp_dir = Some(tmp_dir); |
125 | | - } else { |
126 | | - // uses current directory, the generated files are kept |
127 | | - let path = std::path::Path::new(TEMP_DIR); |
128 | | - if !path.exists() { |
129 | | - std::fs::create_dir_all(path).expect("Path {path} could not be created"); |
130 | | - } |
131 | | - ctx.dir = TEMP_DIR.to_string(); |
132 | | - }; |
133 | | - |
134 | | - // generate test bytes |
135 | | - for kb in FILE_SIZES_IN_KILO_BYTES { |
136 | | - let f = generate_test_files_bytes(ctx.get_path(), kb * 1000, 0, "eq") |
137 | | - .expect("generate_test_files failed"); |
138 | | - ctx.files_equal.push(f); |
139 | | - let f = generate_test_files_bytes(ctx.get_path(), kb * 1000, NUM_DIFF, "df") |
140 | | - .expect("generate_test_files failed"); |
141 | | - ctx.files_different.push(f); |
142 | | - } |
143 | | - |
144 | | - ctx |
145 | | - }) |
146 | | -} |
147 | | - |
148 | | -fn main() { |
149 | | - // Run registered benchmarks. |
150 | | - divan::main(); |
151 | | -} |
| 1 | +#![allow(unused)] |
| 2 | +// This file is part of the uutils diffutils package. |
| 3 | +// |
| 4 | +// For the full copyright and license information, please view the LICENSE-* |
| 5 | +// files that was distributed with this source code. |
| 6 | + |
| 7 | +//! Benches for all utils in diffutils. |
| 8 | +//! |
| 9 | +//! There is a file generator included to create files of different sizes for comparison. \ |
| 10 | +//! Set the TEMP_DIR const to keep the files. df_to_ files have small changes in them, search for '#'. \ |
| 11 | +//! File generation up to 1 GB is really fast, Benchmarking above 100 MB takes very long. |
| 12 | +
|
| 13 | +/// Generate test files with these sizes in KB. |
| 14 | +const FILE_SIZES_IN_KILO_BYTES: [u64; 5] = [100, 1 * MB, 10 * MB, 25 * MB, 100 * MB]; |
| 15 | +const NUM_DIFF: u64 = 4; |
| 16 | +// Empty String to use TempDir (files will be removed after test) or specify dir to keep generated files |
| 17 | +const TEMP_DIR: &str = ""; |
| 18 | +// just for FILE_SIZE_KILO_BYTES |
| 19 | +const MB: u64 = 1_000; |
| 20 | + |
| 21 | +use std::{ |
| 22 | + path::{Path, PathBuf}, |
| 23 | + sync::OnceLock, |
| 24 | +}; |
| 25 | + |
| 26 | +use divan::Bencher; |
| 27 | +use tempfile::TempDir; |
| 28 | +use uu_cmp::{params_cmp::Params, uu_app}; |
| 29 | +use uudiff::benchmark::{ |
| 30 | + bench_binary, |
| 31 | + prepare_bench::{BenchContext, generate_test_files_bytes}, |
| 32 | + str_to_args, |
| 33 | +}; |
| 34 | + |
| 35 | +// bench the time it takes to parse the command line arguments |
| 36 | +#[divan::bench] |
| 37 | +fn cmp_parser(bencher: Bencher) { |
| 38 | + let cmd = "cmd file_1.txt file_2.txt -bl -n10M --ignore-initial=100KiB:1MiB"; |
| 39 | + let args = str_to_args(&cmd).into_iter().peekable(); |
| 40 | + bencher.with_inputs(|| args.clone()).bench_values( |
| 41 | + // |params: std::iter::Peekable<std::vec::IntoIter<std::ffi::OsString>>| parse_params(params), |
| 42 | + |params: std::iter::Peekable<std::vec::IntoIter<std::ffi::OsString>>| { |
| 43 | + let matches = uudiff::clap_localization::handle_clap_result(uu_app(), params).unwrap(); |
| 44 | + let params: Params = matches.try_into().unwrap(); |
| 45 | + }, |
| 46 | + ); |
| 47 | + // ); |
| 48 | +} |
| 49 | + |
| 50 | +// // // test the impact on the benchmark if not converting the cmd to Vec<OsString> (doubles for parse) |
| 51 | +// #[divan::bench] |
| 52 | +// fn cmp_parser_no_prepare() { |
| 53 | +// let cmd = "cmd file_1.txt file_2.txt -bl n10M --ignore-initial=100KiB:1MiB"; |
| 54 | +// let args = str_to_args(&cmd).into_iter().peekable(); |
| 55 | +// let _ = parse_params(args); |
| 56 | +// } |
| 57 | + |
| 58 | +// bench equal, full file read |
| 59 | +#[divan::bench(args = FILE_SIZES_IN_KILO_BYTES)] |
| 60 | +fn cmp_compare_files_equal(bencher: Bencher, kb: u64) { |
| 61 | + let fp = get_context().get_files_equal_kb(kb).unwrap(); |
| 62 | + let cmd = format!("cmp {} {}", fp.from, fp.to); |
| 63 | + let args = str_to_args(&cmd).into_iter(); |
| 64 | + let matches = |
| 65 | + uudiff::clap_localization::handle_clap_result_with_exit_code(uu_app(), args, 2).unwrap(); |
| 66 | + let params: Params = matches.try_into().unwrap(); |
| 67 | + |
| 68 | + bencher |
| 69 | + // .with_inputs(|| prepare::cmp_params_identical_testfiles(lines)) |
| 70 | + .with_inputs(|| params.clone()) |
| 71 | + .bench_refs(|params| uu_cmp::cmp_compare(params)); |
| 72 | +} |
| 73 | + |
| 74 | +// bench different; cmp exits on first difference |
| 75 | +#[divan::bench(args = FILE_SIZES_IN_KILO_BYTES)] |
| 76 | +fn cmp_compare_files_different(bencher: Bencher, kb: u64) { |
| 77 | + let fp = get_context().get_files_different_kb(kb).unwrap(); |
| 78 | + let cmd = format!("cmp -s {} {}", fp.from, fp.to); |
| 79 | + let args = str_to_args(&cmd).into_iter(); |
| 80 | + |
| 81 | + bencher |
| 82 | + // .with_inputs(|| prepare::cmp_params_identical_testfiles(lines)) |
| 83 | + .with_inputs(|| args.clone()) |
| 84 | + .bench_refs(|params| uu_cmp::uumain(params.peekable())); |
| 85 | +} |
| 86 | + |
| 87 | +// TODO use coreutils bench logic |
| 88 | +// bench original GNU cmp |
| 89 | +#[cfg(feature = "feat_run_binary_bench")] |
| 90 | +#[divan::bench(args = FILE_SIZES_IN_KILO_BYTES)] |
| 91 | +fn cmd_cmp_gnu_equal(bencher: Bencher, kb: u64) { |
| 92 | + let fp = get_context().get_files_equal_kb(kb).unwrap(); |
| 93 | + let args_str = format!("{} {}", fp.from, fp.to); |
| 94 | + bencher |
| 95 | + // .with_inputs(|| prepare::cmp_params_identical_testfiles(lines)) |
| 96 | + .with_inputs(|| args_str.clone()) |
| 97 | + .bench_refs(|cmd_args| bench_binary::bench_binary(&PathBuf::from("cmp"), cmd_args)); |
| 98 | +} |
| 99 | + |
| 100 | +// bench the compiled release version |
| 101 | +#[cfg(feature = "feat_run_binary_bench")] |
| 102 | +#[divan::bench(args = FILE_SIZES_IN_KILO_BYTES)] |
| 103 | +fn cmd_cmp_release_equal(bencher: Bencher, kb: u64) { |
| 104 | + let mut dir = std::env::current_dir().unwrap(); |
| 105 | + let suffix = Path::new("src").join("uu").join("cmp"); |
| 106 | + if dir.ends_with(suffix) { |
| 107 | + dir.pop(); |
| 108 | + dir.pop(); |
| 109 | + dir.pop(); |
| 110 | + } |
| 111 | + let prg = dir.join("target").join("release").join("cmp"); |
| 112 | + |
| 113 | + let fp = get_context().get_files_equal_kb(kb).unwrap(); |
| 114 | + let args_str = format!("{} {}", fp.from, fp.to); |
| 115 | + |
| 116 | + bencher |
| 117 | + // .with_inputs(|| prepare::cmp_params_identical_testfiles(lines)) |
| 118 | + .with_inputs(|| args_str.clone()) |
| 119 | + .bench_refs(|cmd_args| bench_binary::bench_binary(&prg, cmd_args)); |
| 120 | +} |
| 121 | + |
| 122 | +// Since each bench function is separate in Divan it is more difficult to dynamically create test data. |
| 123 | +// This keeps the TempDir alive until the program exits and generates the files only once. |
| 124 | +static SHARED_CONTEXT: OnceLock<BenchContext> = OnceLock::new(); |
| 125 | +/// Creates the test files once and provides them to all tests. |
| 126 | +pub fn get_context() -> &'static BenchContext { |
| 127 | + SHARED_CONTEXT.get_or_init(|| { |
| 128 | + let mut ctx = BenchContext::default(); |
| 129 | + if TEMP_DIR.is_empty() { |
| 130 | + let tmp_dir = TempDir::new().expect("Failed to create temp dir"); |
| 131 | + ctx.tmp_dir = Some(tmp_dir); |
| 132 | + } else { |
| 133 | + // uses current directory, the generated files are kept |
| 134 | + let path = std::path::Path::new(TEMP_DIR); |
| 135 | + if !path.exists() { |
| 136 | + std::fs::create_dir_all(path).expect("Path {path} could not be created"); |
| 137 | + } |
| 138 | + ctx.dir = TEMP_DIR.to_string(); |
| 139 | + }; |
| 140 | + |
| 141 | + // generate test bytes |
| 142 | + for kb in FILE_SIZES_IN_KILO_BYTES { |
| 143 | + let f = generate_test_files_bytes(ctx.get_path(), kb * 1000, 0, "eq") |
| 144 | + .expect("generate_test_files failed"); |
| 145 | + ctx.files_equal.push(f); |
| 146 | + let f = generate_test_files_bytes(ctx.get_path(), kb * 1000, NUM_DIFF, "df") |
| 147 | + .expect("generate_test_files failed"); |
| 148 | + ctx.files_different.push(f); |
| 149 | + } |
| 150 | + |
| 151 | + ctx |
| 152 | + }) |
| 153 | +} |
| 154 | + |
| 155 | +fn main() { |
| 156 | + // Run registered benchmarks. |
| 157 | + divan::main(); |
| 158 | +} |
0 commit comments