Skip to content

Commit 24adbf7

Browse files
committed
Add --quiet and --write-results-to. Change program path and arguments to be OsString
1 parent 2c8ed48 commit 24adbf7

File tree

3 files changed

+120
-34
lines changed

3 files changed

+120
-34
lines changed

benchmarking-tool/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
pub mod tools;
22
pub mod utilities;
33

4-
pub struct CommandRequest {
5-
pub program: String,
6-
pub arguments: Vec<String>,
4+
use std::borrow::Cow;
5+
use std::ffi::OsStr;
6+
7+
pub struct CommandRequest<'a> {
8+
pub program: Cow<'a, OsStr>,
9+
pub arguments: Vec<Cow<'a, OsStr>>,
710
}
811

912
/// TODO iterations, etc for time etc

benchmarking-tool/src/main.rs

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
use benchmarking_tool::{CommandRequest, Entry, ToolOptions, ToolOutput, tools, utilities};
21
use std::collections::HashMap;
3-
use utilities::{Direction, Sorting};
2+
use std::ffi::OsString;
3+
use std::io::Write;
4+
5+
use benchmarking_tool::{CommandRequest, Entry, ToolOptions, ToolOutput, tools, utilities};
6+
use utilities::{Direction, PairedWriter, Sorting};
47

58
fn main() {
69
let mut args = std::env::args().skip(1);
@@ -9,15 +12,26 @@ fn main() {
912

1013
let input = BenchmarkInput::from_arguments(args);
1114

15+
let writer = PairedWriter::new_from_option(
16+
input.write_to_stdout.then(|| std::io::stdout()),
17+
input.write_results_to.map(|path| {
18+
let path = std::path::Path::new(&path);
19+
if let Some(parent) = path.parent() {
20+
std::fs::create_dir_all(parent).unwrap();
21+
}
22+
std::fs::File::create(path).unwrap()
23+
}),
24+
);
25+
1226
match tool {
1327
"--info" | "help" => {
1428
println!("benchmarking-tool");
1529
println!("run 'qbdi', 'sde', 'perf-events' or 'time'");
1630
}
1731
"qbdi" => {
1832
let request = CommandRequest {
19-
program: input.program,
20-
arguments: input.arguments,
33+
program: input.program.into(),
34+
arguments: input.arguments.into_iter().map(Into::into).collect(),
2135
};
2236
let options = ToolOptions {
2337
keep: input.keep,
@@ -26,24 +40,26 @@ fn main() {
2640
let result = tools::qbdi::run_qbdi(request, options).unwrap();
2741
match result {
2842
ToolOutput::SymbolInstructionCounts { symbols, total } => print_results(
43+
&mut writer.expect("--quiet must have --write-results-to"),
2944
symbols,
3045
total as usize,
3146
input.format,
3247
input.sort,
3348
input.limit,
3449
input.breakdown,
35-
),
50+
)
51+
.unwrap(),
3652
_ => todo!(),
3753
}
3854
}
3955
"time" => {
4056
todo!()
4157
}
42-
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
58+
#[cfg(any(target_arch = "x86", target_arch = "x86_64", debug_assertions))]
4359
"sde" => {
4460
let request = CommandRequest {
45-
program: input.program,
46-
arguments: input.arguments,
61+
program: input.program.into(),
62+
arguments: input.arguments.into_iter().map(Into::into).collect(),
4763
};
4864
let options = ToolOptions {
4965
keep: input.keep,
@@ -52,13 +68,15 @@ fn main() {
5268
let result = tools::sde::run_sde(request, options).unwrap();
5369
match result {
5470
ToolOutput::SymbolInstructionCounts { symbols, total } => print_results(
71+
&mut writer.expect("--quiet must have --write-results-to"),
5572
symbols,
5673
total as usize,
5774
input.format,
5875
input.sort,
5976
input.limit,
6077
input.breakdown,
61-
),
78+
)
79+
.unwrap(),
6280
_ => todo!(),
6381
}
6482
}
@@ -88,8 +106,8 @@ pub struct BenchmarkInput {
88106
/// plain, JSON, markdown, csv
89107
pub format: OutputFormat,
90108
// ...
91-
pub program: String,
92-
pub arguments: Vec<String>,
109+
pub program: OsString,
110+
pub arguments: Vec<OsString>,
93111
// ...
94112
pub generic_arguments: HashMap<String, Vec<String>>,
95113

@@ -98,8 +116,11 @@ pub struct BenchmarkInput {
98116
pub keep: Option<String>,
99117
/// skip Rust internals
100118
pub skip_internals: bool,
101-
/// include all inst
119+
/// include all instruction kinds
102120
pub breakdown: bool,
121+
// things
122+
pub write_results_to: Option<String>,
123+
pub write_to_stdout: bool,
103124
}
104125

105126
impl BenchmarkInput {
@@ -109,14 +130,17 @@ impl BenchmarkInput {
109130
sort: None,
110131
format: OutputFormat::default(),
111132
// ...
112-
program: String::new(),
133+
program: OsString::new(),
113134
arguments: Vec::new(),
114135
// ...
115136
generic_arguments: HashMap::new(),
116137
// ...
117138
keep: None,
118139
skip_internals: true,
119140
breakdown: false,
141+
// ...
142+
write_results_to: None,
143+
write_to_stdout: true,
120144
};
121145

122146
let mut left_over: Option<String> = None;
@@ -161,42 +185,55 @@ impl BenchmarkInput {
161185
"--keep" => {
162186
this.keep = args.next();
163187
}
188+
"--write-results-to" => {
189+
this.write_results_to = args.next();
190+
}
164191
"--all" => {
165192
this.skip_internals = false;
166193
}
167194
"--breakdown" => {
168195
this.breakdown = true;
169196
}
197+
"--quiet" => {
198+
this.write_to_stdout = false;
199+
}
170200
"--arg" => {
201+
// `--arg name=6,7`
171202
let next = args.next().unwrap();
172203
let (name, values) = next.split_once('=').unwrap();
173-
this.generic_arguments.insert(
174-
name.to_owned(),
175-
values.split(',').map(str::to_owned).collect(),
176-
);
204+
// TODO CSV parse?
205+
let values = values.trim().split(',').map(str::to_owned).collect();
206+
this.generic_arguments.insert(name.to_owned(), values);
177207
}
178-
// WIP
208+
// -- *program* *arg1* *arg2* ...
209+
"--" => {
210+
let arg = args.next().unwrap();
211+
this.program = OsString::from(arg);
212+
break;
213+
}
214+
// WIP. First unknown argument is the program
179215
_command => {
180-
this.program = arg;
216+
this.program = OsString::from(arg);
181217
break;
182218
}
183219
}
184220
}
185221

186-
this.arguments = args.collect();
222+
this.arguments = args.map(OsString::from).collect();
187223

188224
this
189225
}
190226
}
191227

192228
pub fn print_results(
229+
to: &mut impl Write,
193230
mut rows: Vec<Entry>,
194231
total_count: usize,
195232
output_format: OutputFormat,
196233
sorting: Option<utilities::Sorting>,
197234
limit: usize,
198235
breakdown: bool,
199-
) {
236+
) -> std::io::Result<()> {
200237
use std::borrow::Cow;
201238
use utilities::count_with_seperator;
202239

@@ -218,7 +255,7 @@ pub fn print_results(
218255
rows.sort_unstable_by(|lhs, rhs| sort.direction.compare(&lhs.total, &rhs.total));
219256
}
220257
field => {
221-
eprintln!("unknown field {field:?}");
258+
writeln!(to, "error: unknown field {field:?}")?;
222259
}
223260
}
224261
}
@@ -256,10 +293,11 @@ pub fn print_results(
256293
// println!();
257294
// }
258295

259-
println!(
296+
writeln!(
297+
to,
260298
"Run {total} instructions",
261299
total = count_with_seperator(total_count as usize)
262-
);
300+
)?;
263301
for row in rows {
264302
let symbol_name: Cow<'_, str> = if row.symbol_name.len() > MAX_WIDTH {
265303
Cow::Owned(format!(
@@ -272,21 +310,25 @@ pub fn print_results(
272310
let fill = &WHITESPACE[..max_name_width - symbol_name.len()];
273311

274312
// TODO wip
275-
print!("{symbol_name}{fill}");
276-
print!(
313+
write!(to, "{symbol_name}{fill}")?;
314+
write!(
315+
to,
277316
" total: {count}",
278317
count = count_with_seperator(row.total as usize)
279-
);
318+
)?;
280319
if breakdown {
281320
for (name, count) in &row.entries {
282-
print!(
321+
write!(
322+
to,
283323
" {name}: {count}",
284324
count = count_with_seperator(*count as usize)
285-
);
325+
)?;
286326
}
287327
}
288-
println!();
328+
writeln!(to)?;
289329
}
330+
331+
Ok(())
290332
}
291333
OutputFormat::JSON => {
292334
let mut buf = String::from("[");
@@ -308,7 +350,7 @@ pub fn print_results(
308350
}
309351
}
310352
buf.push(']');
311-
println!("{buf}");
353+
write!(to, "{buf}")
312354
}
313355
format => {
314356
todo!("output format '{format:?}'");

benchmarking-tool/src/utilities.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,44 @@ fn to_denary(value: usize, seperator: &str) -> String {
4242
}
4343
buf
4444
}
45+
46+
pub struct PairedWriter<W1, W2>(Option<W1>, Option<W2>);
47+
48+
impl<W1, W2> PairedWriter<W1, W2> {
49+
pub fn new_from_option(first: Option<W1>, second: Option<W2>) -> Option<Self> {
50+
if first.is_some() || second.is_some() {
51+
Some(Self(first, second))
52+
} else {
53+
None
54+
}
55+
}
56+
}
57+
58+
impl<W1, W2> std::io::Write for PairedWriter<W1, W2>
59+
where
60+
W1: std::io::Write,
61+
W2: std::io::Write,
62+
{
63+
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
64+
if let Some(first) = self.0.as_mut() {
65+
let result = std::io::Write::write(first, buf)?;
66+
if let Some(second) = self.1.as_mut() {
67+
std::io::Write::write(second, buf)
68+
} else {
69+
Ok(result)
70+
}
71+
} else {
72+
std::io::Write::write(self.1.as_mut().unwrap(), buf)
73+
}
74+
}
75+
76+
fn flush(&mut self) -> std::io::Result<()> {
77+
if let Some(first) = self.0.as_mut() {
78+
std::io::Write::flush(first)?;
79+
}
80+
if let Some(second) = self.1.as_mut() {
81+
std::io::Write::flush(second)?;
82+
}
83+
Ok(())
84+
}
85+
}

0 commit comments

Comments
 (0)