profiler/parse/
callgrind.rs1extern crate regex;
2
3use std::process::Command;
4use profiler::Profiler;
5use err::ProfError;
6use regex::Regex;
7use std::ffi::OsStr;
8
9pub trait CallGrindParser {
12 fn callgrind_cli(&self, binary: &str, binargs: &[&OsStr]) -> Result<String, ProfError>;
13 fn callgrind_parse<'b>(&'b self, output: &'b str, num: usize) -> Result<Profiler, ProfError>;
14}
15
16
17impl CallGrindParser for Profiler {
18 fn callgrind_cli(&self, binary: &str, binargs: &[&OsStr]) -> Result<String, ProfError> {
20
21 Command::new("valgrind")
23 .arg("--tool=callgrind")
24 .arg("--callgrind-out-file=callgrind.out")
25 .arg(binary)
26 .args(binargs)
27 .output()
28 .unwrap_or_else(|e| panic!("failed to execute process: {}", e));
29
30 let cachegrind_output = Command::new("callgrind_annotate")
31 .arg("callgrind.out")
32 .arg(binary)
33 .output()
34 .unwrap_or_else(|e| panic!("failed to execute process: {}", e));
35
36 Ok(String::from_utf8(cachegrind_output.stdout)
37 .expect("error while returning cachegrind stdout"))
38
39 }
40
41 fn callgrind_parse<'b>(&'b self, output: &'b str, num: usize) -> Result<Profiler, ProfError> {
42
43 let mut out_split = output.split("\n").collect::<Vec<_>>();
45
46 lazy_static! {
49 static ref CALLGRIND_REGEX : Regex = Regex::new(r"\d+\s*[a-zA-Z]*$*_*:*/+\.*@*-*|\d+\s*[a-zA-Z]*$*_*\?+:*/*\.*-*@*-*").unwrap();
50 static ref COMPILER_TRASH: Regex = Regex::new(r"\$\w{2}\$|\$\w{3}\$").unwrap();
51 static ref ERROR_REGEX : Regex = Regex::new(r"out of memory").unwrap();
52
53 }
54 let errs = out_split.to_owned()
55 .into_iter()
56 .filter(|x| ERROR_REGEX.is_match(x))
57 .collect::<Vec<_>>();
58 if errs.len() > 0 {
59 return Err(ProfError::OutOfMemoryError);
60 }
61
62 out_split.retain(|x| CALLGRIND_REGEX.is_match(x));
63
64
65 let mut funcs: Vec<String> = Vec::new();
66 let mut data_vec: Vec<f64> = Vec::new();
67 for sample in out_split.iter() {
69
70
71 let elems = sample.trim().split(" ").collect::<Vec<_>>();
74
75 let data_row = match elems[0].trim().replace(",", "").parse::<f64>() {
79 Ok(rep) => rep,
80 Err(_) => return Err(ProfError::RegexError),
81 };
82
83 data_vec.push(data_row);
84
85
86 let path = elems[1].split(" ").collect::<Vec<_>>();
89 let cleaned_path = path[0].split("/").collect::<Vec<_>>();
90 let func = cleaned_path[cleaned_path.len() - 1];
91 let mut func = COMPILER_TRASH.replace_all(func, "..");
92 let idx = func.rfind("::").unwrap_or(func.len());
93 func.drain(idx..).collect::<String>();
94 funcs.push(func)
95
96 }
97
98 let total_instructions = data_vec.iter().fold(0.0, |a, b| a + b);
100
101 if num < data_vec.len() {
105 data_vec = data_vec.iter().take(num).cloned().collect();
106 funcs = funcs.iter().take(num).cloned().collect();
107 }
108 Ok(Profiler::CallGrind {
110 total_instructions: total_instructions,
111 instructions: data_vec,
112 functs: funcs,
113 })
114 }
115}
116
117#[cfg(test)]
118mod test {
119 use profiler::Profiler;
120 use super::CallGrindParser;
121 #[test]
122 fn test_callgrind_parse_1() {
123 let output = "==6072== Valgrind's memory management: out of memory:\n ==6072== \
124 Whatever the reason, Valgrind cannot continue. Sorry.";
125 let num = 10;
126 let profiler = Profiler::new_callgrind();
127 let is_err = profiler.callgrind_parse(&output, num).is_err();
128 assert!(is_err && true)
129 }
130
131 #[test]
132 fn test_callgrind_parse_2() {
133 assert_eq!(1, 1);
134 assert_eq!(1, 1);
135 }
136
137 #[test]
138 fn test_callgrind_parse_3() {
139 assert_eq!(1, 1);
140 }
141}