profiler/parse/
cachegrind.rs1extern crate ndarray;
2extern crate regex;
3
4use std::process::Command;
5use self::ndarray::{Axis, stack, OwnedArray, ArrayView, Ix};
6use profiler::Profiler;
7use std::cmp::Ordering::Less;
8use err::ProfError;
9use regex::Regex;
10use std::ffi::OsStr;
11
12pub type Mat<A> = OwnedArray<A, (Ix, Ix)>;
14
15pub enum Metric {
17 Ir,
18 I1mr,
19 ILmr,
20 Dr,
21 D1mr,
22 DLmr,
23 Dw,
24 D1mw,
25 DLmw,
26 NAN,
27}
28
29
30pub fn sort_matrix(mat: &Mat<f64>, sort_col: ArrayView<f64, Ix>) -> (Mat<f64>, Vec<usize>) {
32 let mut enum_col = sort_col.iter().enumerate().collect::<Vec<(usize, &f64)>>();
33 enum_col.sort_by(|a, &b| a.1.partial_cmp(b.1).unwrap_or(Less).reverse());
34 let indices = enum_col.iter().map(|x| x.0).collect::<Vec<usize>>();
35 (mat.select(Axis(0), indices.as_slice()), indices)
36}
37
38
39pub trait CacheGrindParser {
42 fn cachegrind_cli(&self, binary: &str, binargs: &[&OsStr]) -> Result<String, ProfError>;
43 fn cachegrind_parse<'b>(&'b self,
44 output: &'b str,
45 num: usize,
46 sort_metric: Metric)
47 -> Result<Profiler, ProfError>;
48}
49
50
51
52
53
54impl CacheGrindParser for Profiler {
55 fn cachegrind_cli(&self, binary: &str, binargs: &[&OsStr]) -> Result<String, ProfError> {
57
58 let _ = Command::new("valgrind")
60 .arg("--tool=cachegrind")
61 .arg("--cachegrind-out-file=cachegrind.out")
62 .arg(binary)
63 .args(binargs)
64 .output()
65 .or(Err(ProfError::CliError));
66
67 let cachegrind_output = Command::new("cg_annotate")
68 .arg("cachegrind.out")
69 .arg(binary)
70 .output()
71 .or(Err(ProfError::CliError));
72
73 cachegrind_output.and_then(|x| String::from_utf8(x.stdout).or(Err(ProfError::UTF8Error)))
74 .or(Err(ProfError::CliError))
75
76
77 }
78 fn cachegrind_parse<'b>(&'b self,
80 output: &'b str,
81 num: usize,
82 sort_metric: Metric)
83 -> Result<Profiler, ProfError> {
84 let mut out_split: Vec<&'b str> = output.split("\n").collect();
86
87 lazy_static! {
90 static ref CACHEGRIND_REGEX : Regex = Regex::new(r"\d+\s*[a-zA-Z]*$*_*:*/+\.*@*-*|\d+\s*[a-zA-Z]*$*_*\?+:*/*\.*-*@*-*").unwrap();
91 static ref COMPILER_TRASH: Regex = Regex::new(r"\$\w{2}\$|\$\w{3}\$").unwrap();
92 static ref ERROR_REGEX : Regex = Regex::new(r"Valgrind's memory management: out of memory").unwrap();
93 }
94
95 let errs = out_split.to_owned()
96 .into_iter()
97 .filter(|x| ERROR_REGEX.is_match(x))
98 .collect::<Vec<_>>();
99
100 if errs.len() > 0 {
101 return Err(ProfError::OutOfMemoryError);
102 }
103
104 out_split.retain(|x| CACHEGRIND_REGEX.is_match(x));
105
106 let mut funcs: Vec<String> = Vec::new();
107 let mut data_vec: Vec<Mat<f64>> = Vec::new();
108
109 for sample in out_split.iter() {
111
112 let mut elems = sample.trim()
115 .split(" ")
116 .collect::<Vec<&'b str>>();
117 elems.retain(|x| x.to_string() != "");
119
120 let mut numbers = Vec::new();
123
124 for elem in elems[0..elems.len() - 1].iter() {
125 let number = match elem.trim().replace(",", "").parse::<f64>() {
126 Ok(n) => n,
127 Err(_) => return Err(ProfError::RegexError),
128 };
129
130 numbers.push(number);
131 }
132
133
134 if let Ok(data_col) = OwnedArray::from_shape_vec((numbers.len(), 1), numbers) {
137 data_vec.push(data_col);
138 }
139 let path = elems[elems.len() - 1].split("/").collect::<Vec<&'b str>>();
143 let func = path[path.len() - 1];
144
145 let mut func = COMPILER_TRASH.replace_all(func, "");
146 let idx = func.rfind("::").unwrap_or(func.len());
147 func.drain(idx..).collect::<String>();
148 funcs.push(func);
149
150 }
151
152
153
154
155
156
157 let data_matrix = match stack(Axis(1),
159 &data_vec.iter()
160 .map(|x| x.view())
161 .collect::<Vec<_>>()
162 .as_slice()) {
163 Ok(m) => m.t().to_owned(),
164 Err(_) => return Err(ProfError::MisalignedData),
165
166 };
167
168
169 let sort_col = match sort_metric {
172 Metric::Ir => data_matrix.column(0),
173 Metric::I1mr => data_matrix.column(1),
174 Metric::ILmr => data_matrix.column(2),
175 Metric::Dr => data_matrix.column(3),
176 Metric::D1mr => data_matrix.column(4),
177 Metric::DLmr => data_matrix.column(5),
178 Metric::Dw => data_matrix.column(6),
179 Metric::D1mw => data_matrix.column(7),
180 Metric::DLmw => data_matrix.column(8),
181 Metric::NAN => data_matrix.column(0),
182 };
183
184 let (mut sorted_data_matrix, indices) = sort_matrix(&data_matrix, sort_col);
189
190 let mut sorted_funcs: Vec<String> = indices.iter()
191 .map(|&x| (&funcs[x]).to_owned())
192 .collect::<Vec<String>>();
193
194
195
196 let ir = sorted_data_matrix.column(0).scalar_sum();
198 let i1mr = sorted_data_matrix.column(1).scalar_sum();
199 let ilmr = sorted_data_matrix.column(2).scalar_sum();
200 let dr = sorted_data_matrix.column(3).scalar_sum();
201 let d1mr = sorted_data_matrix.column(4).scalar_sum();
202 let dlmr = sorted_data_matrix.column(5).scalar_sum();
203 let dw = sorted_data_matrix.column(6).scalar_sum();
204 let d1mw = sorted_data_matrix.column(7).scalar_sum();
205 let dlmw = sorted_data_matrix.column(8).scalar_sum();
206
207 if num < sorted_data_matrix.rows() {
210 let ls = (0..num).collect::<Vec<_>>();
211 sorted_data_matrix = sorted_data_matrix.select(Axis(0), ls.as_slice());
212 sorted_funcs = sorted_funcs.iter()
213 .take(num)
214 .cloned()
215 .collect();
216 }
217
218
219
220 Ok(Profiler::CacheGrind {
222 ir: ir,
223 i1mr: i1mr,
224 ilmr: ilmr,
225 dr: dr,
226 d1mr: d1mr,
227 dlmr: dlmr,
228 dw: dw,
229 d1mw: d1mw,
230 dlmw: dlmw,
231 data: sorted_data_matrix,
232 functs: sorted_funcs,
233 })
234 }
235}
236
237
238#[cfg(test)]
239mod test {
240 #[test]
241 fn test_cachegrind_parse_1() {
242 assert_eq!(1, 1);
243 }
244
245 #[test]
246 fn test_cachegrind_parse_2() {
247 assert_eq!(1, 1);
248 assert_eq!(1, 1);
249 }
250
251 #[test]
252 fn test_cachegrind_parse_3() {
253 assert_eq!(1, 1);
254 }
255}