utils.rs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. use anyhow::Result;
  5. use serde::{Deserialize, Serialize};
  6. use serde_json::Value;
  7. use std::{collections::HashMap, fs, io::{BufRead, BufReader}, path::PathBuf, process::{Command, Output, Stdio}};
  8. #[derive(Default, Clone, Serialize, Deserialize, Debug)]
  9. pub struct BenchResult {
  10. pub created_at: String,
  11. pub sha1: String,
  12. pub exec_time: HashMap<String, HashMap<String, f64>>,
  13. pub binary_size: HashMap<String, u64>,
  14. pub max_memory: HashMap<String, u64>,
  15. pub thread_count: HashMap<String, u64>,
  16. pub syscall_count: HashMap<String, u64>,
  17. pub cargo_deps: HashMap<String, usize>,
  18. }
  19. #[allow(dead_code)]
  20. #[derive(Debug, Clone, Serialize)]
  21. pub struct StraceOutput {
  22. pub percent_time: f64,
  23. pub seconds: f64,
  24. pub usecs_per_call: Option<u64>,
  25. pub calls: u64,
  26. pub errors: u64,
  27. }
  28. pub fn get_target() -> &'static str {
  29. #[cfg(target_os = "macos")]
  30. return "x86_64-apple-darwin";
  31. #[cfg(target_os = "linux")]
  32. return "x86_64-unknown-linux-gnu";
  33. #[cfg(target_os = "windows")]
  34. return unimplemented!();
  35. }
  36. pub fn target_dir() -> PathBuf {
  37. let target_dir = bench_root_path()
  38. .join("tests")
  39. .join("target")
  40. .join(get_target())
  41. .join("release");
  42. target_dir.into()
  43. }
  44. pub fn bench_root_path() -> PathBuf {
  45. PathBuf::from(env!("CARGO_MANIFEST_DIR"))
  46. }
  47. #[allow(dead_code)]
  48. pub fn tauri_root_path() -> PathBuf {
  49. bench_root_path()
  50. .parent()
  51. .unwrap()
  52. .parent()
  53. .unwrap()
  54. .to_path_buf()
  55. }
  56. #[allow(dead_code)]
  57. pub fn run_collect(cmd: &[&str]) -> (String, String) {
  58. let mut process_builder = Command::new(cmd[0]);
  59. process_builder
  60. .args(&cmd[1..])
  61. .stdin(Stdio::piped())
  62. .stdout(Stdio::piped())
  63. .stderr(Stdio::piped());
  64. let prog = process_builder.spawn().expect("failed to spawn script");
  65. let Output {
  66. stdout,
  67. stderr,
  68. status,
  69. } = prog.wait_with_output().expect("failed to wait on child");
  70. let stdout = String::from_utf8(stdout).unwrap();
  71. let stderr = String::from_utf8(stderr).unwrap();
  72. if !status.success() {
  73. eprintln!("stdout: <<<{}>>>", stdout);
  74. eprintln!("stderr: <<<{}>>>", stderr);
  75. panic!("Unexpected exit code: {:?}", status.code());
  76. }
  77. (stdout, stderr)
  78. }
  79. #[allow(dead_code)]
  80. pub fn parse_max_mem(file_path: &str) -> Option<u64> {
  81. let file = fs::File::open(file_path).unwrap();
  82. let output = BufReader::new(file);
  83. let mut highest: u64 = 0;
  84. // MEM 203.437500 1621617192.4123
  85. for line in output.lines() {
  86. if let Ok(line) = line {
  87. // split line by space
  88. let split = line.split(" ").collect::<Vec<_>>();
  89. if split.len() == 3 {
  90. // mprof generate result in MB
  91. let current_bytes = str::parse::<f64>(split[1]).unwrap() as u64 * 1024 * 1024;
  92. if current_bytes > highest {
  93. highest = current_bytes;
  94. }
  95. }
  96. }
  97. }
  98. fs::remove_file(file_path).unwrap();
  99. if highest > 0 {
  100. return Some(highest);
  101. }
  102. None
  103. }
  104. #[allow(dead_code)]
  105. pub fn parse_strace_output(output: &str) -> HashMap<String, StraceOutput> {
  106. let mut summary = HashMap::new();
  107. let mut lines = output
  108. .lines()
  109. .filter(|line| !line.is_empty() && !line.contains("detached ..."));
  110. let count = lines.clone().count();
  111. if count < 4 {
  112. return summary;
  113. }
  114. let total_line = lines.next_back().unwrap();
  115. lines.next_back(); // Drop separator
  116. let data_lines = lines.skip(2);
  117. for line in data_lines {
  118. let syscall_fields = line.split_whitespace().collect::<Vec<_>>();
  119. let len = syscall_fields.len();
  120. let syscall_name = syscall_fields.last().unwrap();
  121. if (5..=6).contains(&len) {
  122. summary.insert(
  123. syscall_name.to_string(),
  124. StraceOutput {
  125. percent_time: str::parse::<f64>(syscall_fields[0]).unwrap(),
  126. seconds: str::parse::<f64>(syscall_fields[1]).unwrap(),
  127. usecs_per_call: Some(str::parse::<u64>(syscall_fields[2]).unwrap()),
  128. calls: str::parse::<u64>(syscall_fields[3]).unwrap(),
  129. errors: if syscall_fields.len() < 6 {
  130. 0
  131. } else {
  132. str::parse::<u64>(syscall_fields[4]).unwrap()
  133. },
  134. },
  135. );
  136. }
  137. }
  138. let total_fields = total_line.split_whitespace().collect::<Vec<_>>();
  139. summary.insert(
  140. "total".to_string(),
  141. StraceOutput {
  142. percent_time: str::parse::<f64>(total_fields[0]).unwrap(),
  143. seconds: str::parse::<f64>(total_fields[1]).unwrap(),
  144. usecs_per_call: None,
  145. calls: str::parse::<u64>(total_fields[2]).unwrap(),
  146. errors: str::parse::<u64>(total_fields[3]).unwrap(),
  147. },
  148. );
  149. summary
  150. }
  151. #[allow(dead_code)]
  152. pub fn run(cmd: &[&str]) {
  153. let mut process_builder = Command::new(cmd[0]);
  154. process_builder.args(&cmd[1..]).stdin(Stdio::piped());
  155. let mut prog = process_builder.spawn().expect("failed to spawn script");
  156. let status = prog.wait().expect("failed to wait on child");
  157. if !status.success() {
  158. panic!("Unexpected exit code: {:?}", status.code());
  159. }
  160. }
  161. #[allow(dead_code)]
  162. pub fn read_json(filename: &str) -> Result<Value> {
  163. let f = fs::File::open(filename)?;
  164. Ok(serde_json::from_reader(f)?)
  165. }
  166. #[allow(dead_code)]
  167. pub fn write_json(filename: &str, value: &Value) -> Result<()> {
  168. let f = fs::File::create(filename)?;
  169. serde_json::to_writer(f, value)?;
  170. Ok(())
  171. }