diff --git a/bench/main.rs b/bench/main.rs index 2aa6c52..2ce7e15 100644 --- a/bench/main.rs +++ b/bench/main.rs @@ -6,79 +6,79 @@ use anyhow::Result; use serde::Serialize; use serde_json::Value; use std::{ - collections::HashMap, - env, fs, - process::{Command, Stdio}, + collections::HashMap, + env, fs, + process::{Command, Stdio}, }; use utils::root_path; mod utils; fn read_json(filename: &str) -> Result { - let f = fs::File::open(filename)?; - Ok(serde_json::from_reader(f)?) + let f = fs::File::open(filename)?; + Ok(serde_json::from_reader(f)?) } fn write_json(filename: &str, value: &Value) -> Result<()> { - let f = fs::File::create(filename)?; - serde_json::to_writer(f, value)?; - Ok(()) + let f = fs::File::create(filename)?; + serde_json::to_writer(f, value)?; + Ok(()) } /// The list of the examples of the benchmark name, arguments and return code const EXEC_TIME_BENCHMARKS: &[(&str, &str, Option)] = &[ - ( - "electron_hello_world", - "apps/hello_world/out/startup-electron-linux-x64/startup-electron", - None, - ), - ( - "electron_cpu_intensive", - "apps/cpu_intensive/out/cpu-intensive-linux-x64/cpu-intensive", - None, - ), - ( - "electron_3mb_transfer", - "apps/file_transfer/out/file-transfer-linux-x64/file-transfer", - None, - ), + ( + "electron_hello_world", + "apps/hello_world/out/startup-electron-linux-x64/startup-electron", + None, + ), + ( + "electron_cpu_intensive", + "apps/cpu_intensive/out/cpu-intensive-linux-x64/cpu-intensive", + None, + ), + ( + "electron_3mb_transfer", + "apps/file_transfer/out/file-transfer-linux-x64/file-transfer", + None, + ), ]; fn run_strace_benchmarks(new_data: &mut BenchResult) -> Result<()> { - use std::io::Read; + use std::io::Read; - let mut thread_count = HashMap::::new(); - let mut syscall_count = HashMap::::new(); + let mut thread_count = HashMap::::new(); + let mut syscall_count = HashMap::::new(); - for (name, example_exe, _) in EXEC_TIME_BENCHMARKS { - let mut file = tempfile::NamedTempFile::new()?; + for (name, example_exe, _) in EXEC_TIME_BENCHMARKS { + let mut file = tempfile::NamedTempFile::new()?; - Command::new("strace") - .args(&[ - "-c", - "-f", - "-o", - file.path().to_str().unwrap(), - utils::root_path().join(example_exe).to_str().unwrap(), - ]) - .stdout(Stdio::inherit()) - .spawn()? - .wait()?; + Command::new("strace") + .args(&[ + "-c", + "-f", + "-o", + file.path().to_str().unwrap(), + utils::root_path().join(example_exe).to_str().unwrap(), + ]) + .stdout(Stdio::inherit()) + .spawn()? + .wait()?; - let mut output = String::new(); - file.as_file_mut().read_to_string(&mut output)?; + let mut output = String::new(); + file.as_file_mut().read_to_string(&mut output)?; - let strace_result = utils::parse_strace_output(&output); - let clone = strace_result.get("clone").map(|d| d.calls).unwrap_or(0) + 1; - let total = strace_result.get("total").unwrap().calls; - thread_count.insert(name.to_string(), clone); - syscall_count.insert(name.to_string(), total); - } + let strace_result = utils::parse_strace_output(&output); + let clone = strace_result.get("clone").map(|d| d.calls).unwrap_or(0) + 1; + let total = strace_result.get("total").unwrap().calls; + thread_count.insert(name.to_string(), clone); + syscall_count.insert(name.to_string(), total); + } - new_data.thread_count = thread_count; - new_data.syscall_count = syscall_count; + new_data.thread_count = thread_count; + new_data.syscall_count = syscall_count; - Ok(()) + Ok(()) } fn run_max_mem_benchmark() -> Result> { @@ -112,116 +112,117 @@ fn run_max_mem_benchmark() -> Result> { } fn get_binary_sizes() -> Result> { - let mut sizes = HashMap::::new(); - // add size for all EXEC_TIME_BENCHMARKS - for (name, example_exe, _) in EXEC_TIME_BENCHMARKS { - let meta = std::fs::metadata(example_exe).unwrap(); - sizes.insert(name.to_string(), meta.len()); - } + let mut sizes = HashMap::::new(); + // add size for all EXEC_TIME_BENCHMARKS + for (name, example_exe, _) in EXEC_TIME_BENCHMARKS { + let meta = std::fs::metadata(example_exe).unwrap(); + sizes.insert(name.to_string(), meta.len()); + } - Ok(sizes) + Ok(sizes) } const RESULT_KEYS: &[&str] = &["mean", "stddev", "user", "system", "min", "max"]; fn run_exec_time() -> Result>> { - let benchmark_file = root_path().join("hyperfine_results.json"); - let benchmark_file = benchmark_file.to_str().unwrap(); + let benchmark_file = root_path().join("hyperfine_results.json"); + let benchmark_file = benchmark_file.to_str().unwrap(); - let mut command = [ - "hyperfine", - "--export-json", - benchmark_file, - "--warmup", - "3", - ] - .iter() - .map(|s| s.to_string()) - .collect::>(); + let mut command = [ + "hyperfine", + "--export-json", + benchmark_file, + "--warmup", + "3", + ] + .iter() + .map(|s| s.to_string()) + .collect::>(); - for (_, example_exe, _return_code) in EXEC_TIME_BENCHMARKS { - command.push( - utils::root_path() - .join(example_exe) - .to_str() - .unwrap() - .to_string(), - ); - } + for (_, example_exe, _return_code) in EXEC_TIME_BENCHMARKS { + command.push( + utils::root_path() + .join(example_exe) + .to_str() + .unwrap() + .to_string(), + ); + } - utils::run(&command.iter().map(|s| s.as_ref()).collect::>()); + utils::run(&command.iter().map(|s| s.as_ref()).collect::>()); - let mut results = HashMap::>::new(); - let hyperfine_results = read_json(benchmark_file)?; - for ((name, _, _), data) in EXEC_TIME_BENCHMARKS.iter().zip( - hyperfine_results - .as_object() - .unwrap() - .get("results") - .unwrap() - .as_array() - .unwrap(), - ) { - let data = data.as_object().unwrap().clone(); - results.insert( - name.to_string(), - data.into_iter() - .filter(|(key, _)| RESULT_KEYS.contains(&key.as_str())) - .map(|(key, val)| (key, val.as_f64().unwrap())) - .collect(), - ); - } + let mut results = HashMap::>::new(); + let hyperfine_results = read_json(benchmark_file)?; + for ((name, _, _), data) in EXEC_TIME_BENCHMARKS.iter().zip( + hyperfine_results + .as_object() + .unwrap() + .get("results") + .unwrap() + .as_array() + .unwrap(), + ) { + let data = data.as_object().unwrap().clone(); + results.insert( + name.to_string(), + data + .into_iter() + .filter(|(key, _)| RESULT_KEYS.contains(&key.as_str())) + .map(|(key, val)| (key, val.as_f64().unwrap())) + .collect(), + ); + } - Ok(results) + Ok(results) } #[derive(Default, Serialize, Debug)] struct BenchResult { - created_at: String, - sha1: String, - exec_time: HashMap>, - binary_size: HashMap, - max_memory: HashMap, - thread_count: HashMap, - syscall_count: HashMap, + created_at: String, + sha1: String, + exec_time: HashMap>, + binary_size: HashMap, + max_memory: HashMap, + thread_count: HashMap, + syscall_count: HashMap, } fn main() -> Result<()> { - if !env::args().any(|s| s == "--bench") { - return Ok(()); - } + if !env::args().any(|s| s == "--bench") { + return Ok(()); + } - println!("Starting electron benchmark"); + println!("Starting electron benchmark"); - env::set_current_dir(&utils::root_path())?; + env::set_current_dir(&utils::root_path())?; - println!("{:?}", &utils::root_path()); + println!("{:?}", &utils::root_path()); - let mut new_data = BenchResult { - created_at: chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true), - sha1: utils::run_collect(&["git", "rev-parse", "HEAD"]) - .0 - .trim() - .to_string(), - exec_time: run_exec_time()?, - binary_size: get_binary_sizes()?, - ..Default::default() - }; + let mut new_data = BenchResult { + created_at: chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true), + sha1: utils::run_collect(&["git", "rev-parse", "HEAD"]) + .0 + .trim() + .to_string(), + exec_time: run_exec_time()?, + binary_size: get_binary_sizes()?, + ..Default::default() + }; - if cfg!(target_os = "linux") { - run_strace_benchmarks(&mut new_data)?; - new_data.max_memory = run_max_mem_benchmark()?; - } + if cfg!(target_os = "linux") { + run_strace_benchmarks(&mut new_data)?; + new_data.max_memory = run_max_mem_benchmark()?; + } - println!("===== "); - serde_json::to_writer_pretty(std::io::stdout(), &new_data)?; - println!("\n===== "); + println!("===== "); + serde_json::to_writer_pretty(std::io::stdout(), &new_data)?; + println!("\n===== "); - if let Some(filename) = root_path().join("bench.json").to_str() { - write_json(filename, &serde_json::to_value(&new_data)?)?; - } else { - eprintln!("Cannot write bench.json, path is invalid"); - } + if let Some(filename) = root_path().join("bench.json").to_str() { + write_json(filename, &serde_json::to_value(&new_data)?)?; + } else { + eprintln!("Cannot write bench.json, path is invalid"); + } - Ok(()) + Ok(()) } diff --git a/bench/utils.rs b/bench/utils.rs index da63626..6f57be4 100644 --- a/bench/utils.rs +++ b/bench/utils.rs @@ -3,33 +3,38 @@ // SPDX-License-Identifier: MIT use serde::Serialize; -use std::{collections::HashMap, io::BufRead, path::PathBuf, process::{Command, Output, Stdio}}; +use std::{ + collections::HashMap, + io::BufRead, + path::PathBuf, + process::{Command, Output, Stdio}, +}; pub fn root_path() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")) + PathBuf::from(env!("CARGO_MANIFEST_DIR")) } pub fn run_collect(cmd: &[&str]) -> (String, String) { - let mut process_builder = Command::new(cmd[0]); - process_builder - .args(&cmd[1..]) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - let prog = process_builder.spawn().expect("failed to spawn script"); - let Output { - stdout, - stderr, - status, - } = prog.wait_with_output().expect("failed to wait on child"); - let stdout = String::from_utf8(stdout).unwrap(); - let stderr = String::from_utf8(stderr).unwrap(); - if !status.success() { - eprintln!("stdout: <<<{}>>>", stdout); - eprintln!("stderr: <<<{}>>>", stderr); - panic!("Unexpected exit code: {:?}", status.code()); - } - (stdout, stderr) + let mut process_builder = Command::new(cmd[0]); + process_builder + .args(&cmd[1..]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + let prog = process_builder.spawn().expect("failed to spawn script"); + let Output { + stdout, + stderr, + status, + } = prog.wait_with_output().expect("failed to wait on child"); + let stdout = String::from_utf8(stdout).unwrap(); + let stderr = String::from_utf8(stderr).unwrap(); + if !status.success() { + eprintln!("stdout: <<<{}>>>", stdout); + eprintln!("stderr: <<<{}>>>", stderr); + panic!("Unexpected exit code: {:?}", status.code()); + } + (stdout, stderr) } pub fn parse_max_mem(file_path: &str) -> Option { @@ -62,73 +67,73 @@ pub fn parse_max_mem(file_path: &str) -> Option { #[derive(Debug, Clone, Serialize)] pub struct StraceOutput { - pub percent_time: f64, - pub seconds: f64, - pub usecs_per_call: Option, - pub calls: u64, - pub errors: u64, + pub percent_time: f64, + pub seconds: f64, + pub usecs_per_call: Option, + pub calls: u64, + pub errors: u64, } pub fn parse_strace_output(output: &str) -> HashMap { - let mut summary = HashMap::new(); + let mut summary = HashMap::new(); - let mut lines = output - .lines() - .filter(|line| !line.is_empty() && !line.contains("detached ...")); - let count = lines.clone().count(); + let mut lines = output + .lines() + .filter(|line| !line.is_empty() && !line.contains("detached ...")); + let count = lines.clone().count(); - if count < 4 { - return summary; - } + if count < 4 { + return summary; + } - let total_line = lines.next_back().unwrap(); - lines.next_back(); // Drop separator - let data_lines = lines.skip(2); + let total_line = lines.next_back().unwrap(); + lines.next_back(); // Drop separator + let data_lines = lines.skip(2); - for line in data_lines { - let syscall_fields = line.split_whitespace().collect::>(); - let len = syscall_fields.len(); - let syscall_name = syscall_fields.last().unwrap(); + for line in data_lines { + let syscall_fields = line.split_whitespace().collect::>(); + let len = syscall_fields.len(); + let syscall_name = syscall_fields.last().unwrap(); - if (5..=6).contains(&len) { - summary.insert( - syscall_name.to_string(), - StraceOutput { - percent_time: str::parse::(syscall_fields[0]).unwrap(), - seconds: str::parse::(syscall_fields[1]).unwrap(), - usecs_per_call: Some(str::parse::(syscall_fields[2]).unwrap()), - calls: str::parse::(syscall_fields[3]).unwrap(), - errors: if syscall_fields.len() < 6 { - 0 - } else { - str::parse::(syscall_fields[4]).unwrap() - }, - }, - ); - } - } - - let total_fields = total_line.split_whitespace().collect::>(); - summary.insert( - "total".to_string(), + if (5..=6).contains(&len) { + summary.insert( + syscall_name.to_string(), StraceOutput { - percent_time: str::parse::(total_fields[0]).unwrap(), - seconds: str::parse::(total_fields[1]).unwrap(), - usecs_per_call: None, - calls: str::parse::(total_fields[2]).unwrap(), - errors: str::parse::(total_fields[3]).unwrap(), + percent_time: str::parse::(syscall_fields[0]).unwrap(), + seconds: str::parse::(syscall_fields[1]).unwrap(), + usecs_per_call: Some(str::parse::(syscall_fields[2]).unwrap()), + calls: str::parse::(syscall_fields[3]).unwrap(), + errors: if syscall_fields.len() < 6 { + 0 + } else { + str::parse::(syscall_fields[4]).unwrap() + }, }, - ); + ); + } + } - summary + let total_fields = total_line.split_whitespace().collect::>(); + summary.insert( + "total".to_string(), + StraceOutput { + percent_time: str::parse::(total_fields[0]).unwrap(), + seconds: str::parse::(total_fields[1]).unwrap(), + usecs_per_call: None, + calls: str::parse::(total_fields[2]).unwrap(), + errors: str::parse::(total_fields[3]).unwrap(), + }, + ); + + summary } pub fn run(cmd: &[&str]) { - let mut process_builder = Command::new(cmd[0]); - process_builder.args(&cmd[1..]).stdin(Stdio::piped()); - let mut prog = process_builder.spawn().expect("failed to spawn script"); - let status = prog.wait().expect("failed to wait on child"); - if !status.success() { - panic!("Unexpected exit code: {:?}", status.code()); - } + let mut process_builder = Command::new(cmd[0]); + process_builder.args(&cmd[1..]).stdin(Stdio::piped()); + let mut prog = process_builder.spawn().expect("failed to spawn script"); + let status = prog.wait().expect("failed to wait on child"); + if !status.success() { + panic!("Unexpected exit code: {:?}", status.code()); + } } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..cb7457b --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,16 @@ +max_width = 100 +hard_tabs = false +tab_spaces = 2 +newline_style = "Unix" +use_small_heuristics = "Default" +reorder_imports = true +reorder_modules = true +remove_nested_parens = true +edition = "2021" +merge_derives = true +use_try_shorthand = false +use_field_init_shorthand = false +force_explicit_abi = true +# normalize_comments = true +normalize_doc_attributes = true +# wrap_comments = true