mirror of
https://github.com/tauri-apps/benchmark_electron.git
synced 2026-01-31 00:35:24 +01:00
fix: Apply same rustfmt as tauri repo
This commit is contained in:
273
bench/main.rs
273
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<Value> {
|
||||
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<i32>)] = &[
|
||||
(
|
||||
"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::<String, u64>::new();
|
||||
let mut syscall_count = HashMap::<String, u64>::new();
|
||||
let mut thread_count = HashMap::<String, u64>::new();
|
||||
let mut syscall_count = HashMap::<String, u64>::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<HashMap<String, u64>> {
|
||||
@@ -112,116 +112,117 @@ fn run_max_mem_benchmark() -> Result<HashMap<String, u64>> {
|
||||
}
|
||||
|
||||
fn get_binary_sizes() -> Result<HashMap<String, u64>> {
|
||||
let mut sizes = HashMap::<String, u64>::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::<String, u64>::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<HashMap<String, HashMap<String, f64>>> {
|
||||
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::<Vec<_>>();
|
||||
let mut command = [
|
||||
"hyperfine",
|
||||
"--export-json",
|
||||
benchmark_file,
|
||||
"--warmup",
|
||||
"3",
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
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::<Vec<_>>());
|
||||
utils::run(&command.iter().map(|s| s.as_ref()).collect::<Vec<_>>());
|
||||
|
||||
let mut results = HashMap::<String, HashMap<String, f64>>::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::<String, HashMap<String, f64>>::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<String, HashMap<String, f64>>,
|
||||
binary_size: HashMap<String, u64>,
|
||||
max_memory: HashMap<String, u64>,
|
||||
thread_count: HashMap<String, u64>,
|
||||
syscall_count: HashMap<String, u64>,
|
||||
created_at: String,
|
||||
sha1: String,
|
||||
exec_time: HashMap<String, HashMap<String, f64>>,
|
||||
binary_size: HashMap<String, u64>,
|
||||
max_memory: HashMap<String, u64>,
|
||||
thread_count: HashMap<String, u64>,
|
||||
syscall_count: HashMap<String, u64>,
|
||||
}
|
||||
|
||||
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!("===== <BENCHMARK RESULTS>");
|
||||
serde_json::to_writer_pretty(std::io::stdout(), &new_data)?;
|
||||
println!("\n===== </BENCHMARK RESULTS>");
|
||||
println!("===== <BENCHMARK RESULTS>");
|
||||
serde_json::to_writer_pretty(std::io::stdout(), &new_data)?;
|
||||
println!("\n===== </BENCHMARK RESULTS>");
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
159
bench/utils.rs
159
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<u64> {
|
||||
@@ -62,73 +67,73 @@ pub fn parse_max_mem(file_path: &str) -> Option<u64> {
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct StraceOutput {
|
||||
pub percent_time: f64,
|
||||
pub seconds: f64,
|
||||
pub usecs_per_call: Option<u64>,
|
||||
pub calls: u64,
|
||||
pub errors: u64,
|
||||
pub percent_time: f64,
|
||||
pub seconds: f64,
|
||||
pub usecs_per_call: Option<u64>,
|
||||
pub calls: u64,
|
||||
pub errors: u64,
|
||||
}
|
||||
|
||||
pub fn parse_strace_output(output: &str) -> HashMap<String, StraceOutput> {
|
||||
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::<Vec<_>>();
|
||||
let len = syscall_fields.len();
|
||||
let syscall_name = syscall_fields.last().unwrap();
|
||||
for line in data_lines {
|
||||
let syscall_fields = line.split_whitespace().collect::<Vec<_>>();
|
||||
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::<f64>(syscall_fields[0]).unwrap(),
|
||||
seconds: str::parse::<f64>(syscall_fields[1]).unwrap(),
|
||||
usecs_per_call: Some(str::parse::<u64>(syscall_fields[2]).unwrap()),
|
||||
calls: str::parse::<u64>(syscall_fields[3]).unwrap(),
|
||||
errors: if syscall_fields.len() < 6 {
|
||||
0
|
||||
} else {
|
||||
str::parse::<u64>(syscall_fields[4]).unwrap()
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let total_fields = total_line.split_whitespace().collect::<Vec<_>>();
|
||||
summary.insert(
|
||||
"total".to_string(),
|
||||
if (5..=6).contains(&len) {
|
||||
summary.insert(
|
||||
syscall_name.to_string(),
|
||||
StraceOutput {
|
||||
percent_time: str::parse::<f64>(total_fields[0]).unwrap(),
|
||||
seconds: str::parse::<f64>(total_fields[1]).unwrap(),
|
||||
usecs_per_call: None,
|
||||
calls: str::parse::<u64>(total_fields[2]).unwrap(),
|
||||
errors: str::parse::<u64>(total_fields[3]).unwrap(),
|
||||
percent_time: str::parse::<f64>(syscall_fields[0]).unwrap(),
|
||||
seconds: str::parse::<f64>(syscall_fields[1]).unwrap(),
|
||||
usecs_per_call: Some(str::parse::<u64>(syscall_fields[2]).unwrap()),
|
||||
calls: str::parse::<u64>(syscall_fields[3]).unwrap(),
|
||||
errors: if syscall_fields.len() < 6 {
|
||||
0
|
||||
} else {
|
||||
str::parse::<u64>(syscall_fields[4]).unwrap()
|
||||
},
|
||||
},
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
summary
|
||||
let total_fields = total_line.split_whitespace().collect::<Vec<_>>();
|
||||
summary.insert(
|
||||
"total".to_string(),
|
||||
StraceOutput {
|
||||
percent_time: str::parse::<f64>(total_fields[0]).unwrap(),
|
||||
seconds: str::parse::<f64>(total_fields[1]).unwrap(),
|
||||
usecs_per_call: None,
|
||||
calls: str::parse::<u64>(total_fields[2]).unwrap(),
|
||||
errors: str::parse::<u64>(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());
|
||||
}
|
||||
}
|
||||
|
||||
16
rustfmt.toml
Normal file
16
rustfmt.toml
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user