(&mut self, reader: R, writer: W) -> io::Result<()>
103 | where
104 | R: io::BufRead,
105 | W: io::Write;
106 |
107 | /// Collapses the contents of the provided file (or of STDIN if `infile` is `None`) and
108 | /// writes folded stack lines to provided `writer`.
109 | fn collapse_file(&mut self, infile: Option
, writer: W) -> io::Result<()>
110 | where
111 | P: AsRef,
112 | W: io::Write,
113 | {
114 | match infile {
115 | Some(ref path) => {
116 | let file = File::open(path)?;
117 | let reader = io::BufReader::with_capacity(CAPACITY_READER, file);
118 | self.collapse(reader, writer)
119 | }
120 | None => {
121 | let stdin = io::stdin();
122 | let stdin_guard = stdin.lock();
123 | let reader = io::BufReader::with_capacity(CAPACITY_READER, stdin_guard);
124 | self.collapse(reader, writer)
125 | }
126 | }
127 | }
128 |
129 | /// Collapses the contents of the provided file (or of STDIN if `infile` is `None`) and
130 | /// writes folded stack lines to STDOUT.
131 | fn collapse_file_to_stdout(&mut self, infile: Option
) -> io::Result<()>
132 | where
133 | P: AsRef,
134 | {
135 | if std::io::stdout().is_terminal() {
136 | self.collapse_file(infile, io::stdout().lock())
137 | } else {
138 | self.collapse_file(infile, io::BufWriter::new(io::stdout().lock()))
139 | }
140 | }
141 |
142 | /// Returns whether this implementation is appropriate for the given input.
143 | ///
144 | /// - `None` means "not sure -- need more input"
145 | /// - `Some(true)` means "yes, this implementation should work with this string"
146 | /// - `Some(false)` means "no, this implementation definitely won't work"
147 | #[allow(clippy::wrong_self_convention)]
148 | fn is_applicable(&mut self, input: &str) -> Option;
149 | }
150 |
151 | impl Collapse for T
152 | where
153 | T: CollapsePrivate,
154 | {
155 | fn collapse(&mut self, reader: R, writer: W) -> io::Result<()>
156 | where
157 | R: io::BufRead,
158 | W: io::Write,
159 | {
160 | ::collapse(self, reader, writer)
161 | }
162 |
163 | fn is_applicable(&mut self, input: &str) -> Option {
164 | ::is_applicable(self, input)
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/collapse/recursive.rs:
--------------------------------------------------------------------------------
1 | use super::common::{self, CollapsePrivate};
2 | use std::{borrow::Cow, io};
3 |
4 | /// Recursive backtrace folder configuration options.
5 | #[derive(Clone, Debug)]
6 | #[non_exhaustive]
7 | pub struct Options {
8 | /// The number of threads to use.
9 | ///
10 | /// Default is the number of logical cores on your machine.
11 | pub nthreads: usize,
12 | }
13 |
14 | impl Default for Options {
15 | fn default() -> Self {
16 | Self {
17 | nthreads: *common::DEFAULT_NTHREADS,
18 | }
19 | }
20 | }
21 |
22 | /// A "middleware" folder that receives and outputs the folded stack format
23 | /// expected by [`crate::flamegraph::from_lines`], collapsing direct recursive
24 | /// backtraces.
25 | #[derive(Clone)]
26 | pub struct Folder {
27 | /// The number of stacks per job to send to the threadpool.
28 | nstacks_per_job: usize,
29 |
30 | // Options...
31 | opt: Options,
32 | }
33 |
34 | impl From for Folder {
35 | fn from(mut opt: Options) -> Self {
36 | if opt.nthreads == 0 {
37 | opt.nthreads = 1;
38 | }
39 | Self {
40 | nstacks_per_job: common::DEFAULT_NSTACKS_PER_JOB,
41 | opt,
42 | }
43 | }
44 | }
45 |
46 | impl Default for Folder {
47 | fn default() -> Self {
48 | Options::default().into()
49 | }
50 | }
51 |
52 | impl CollapsePrivate for Folder {
53 | fn pre_process(
54 | &mut self,
55 | _reader: &mut R,
56 | _occurrences: &mut super::common::Occurrences,
57 | ) -> std::io::Result<()>
58 | where
59 | R: std::io::BufRead,
60 | {
61 | // Don't expect any header.
62 | Ok(())
63 | }
64 |
65 | fn collapse_single_threaded(
66 | &mut self,
67 | reader: R,
68 | occurrences: &mut super::common::Occurrences,
69 | ) -> std::io::Result<()>
70 | where
71 | R: std::io::BufRead,
72 | {
73 | for line in reader.lines() {
74 | let line = line?;
75 | let (stack, count) = Self::line_parts(&line)
76 | .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidData))?;
77 |
78 | occurrences.insert_or_add(Self::collapse_stack(stack.into()).into_owned(), count);
79 | }
80 | Ok(())
81 | }
82 |
83 | fn would_end_stack(&mut self, _line: &[u8]) -> bool {
84 | // For our purposes, every line is an independent stack
85 | true
86 | }
87 |
88 | fn clone_and_reset_stack_context(&self) -> Self {
89 | self.clone()
90 | }
91 |
92 | fn is_applicable(&mut self, _input: &str) -> Option {
93 | // It seems doubtful that the user would ever want to guess to collapse
94 | // recursive traces, so let's just never consider ourselves applicable.
95 | Some(false)
96 | }
97 |
98 | fn nstacks_per_job(&self) -> usize {
99 | self.nstacks_per_job
100 | }
101 |
102 | fn set_nstacks_per_job(&mut self, n: usize) {
103 | self.nstacks_per_job = n;
104 | }
105 |
106 | fn nthreads(&self) -> usize {
107 | self.opt.nthreads
108 | }
109 |
110 | fn set_nthreads(&mut self, n: usize) {
111 | self.opt.nthreads = n;
112 | }
113 | }
114 |
115 | impl Folder {
116 | fn line_parts(line: &str) -> Option<(&str, usize)> {
117 | line.rsplit_once(' ')
118 | .and_then(|(stack, count)| Some((stack, count.parse().ok()?)))
119 | }
120 |
121 | fn collapse_stack(stack: Cow) -> Cow {
122 | // First, determine whether we can avoid allocation by just returning
123 | // the original stack (in the case that there is no recursion, which is
124 | // likely the mainline case).
125 | if !Self::is_recursive(&stack) {
126 | return stack;
127 | }
128 |
129 | // There is recursion, so we can't get away without allocating a new
130 | // String.
131 | let mut result = String::with_capacity(stack.len());
132 | let mut last = None;
133 | for frame in stack.split(';') {
134 | if last != Some(frame) {
135 | result.push_str(frame);
136 | result.push(';')
137 | }
138 | last = Some(frame);
139 | }
140 |
141 | // Remove the trailing semicolon
142 | result.pop();
143 |
144 | result.into()
145 | }
146 |
147 | /// Determine whether or not a stack contains direct recursion.
148 | fn is_recursive(stack: &str) -> bool {
149 | let mut last = None;
150 | for current in stack.split(';') {
151 | match last {
152 | None => {
153 | last = Some(current);
154 | }
155 | Some(l) => {
156 | if l == current {
157 | // Recursion!
158 | return true;
159 | } else {
160 | last = Some(current);
161 | }
162 | }
163 | }
164 | }
165 | false
166 | }
167 | }
168 |
169 | #[cfg(test)]
170 | mod test {
171 |
172 | use super::*;
173 |
174 | #[test]
175 | fn test_collapse_stack() {
176 | assert_eq!(Folder::collapse_stack("".into()), "");
177 | assert_eq!(Folder::collapse_stack("single".into()), "single");
178 | assert_eq!(
179 | Folder::collapse_stack("not;recursive".into()),
180 | "not;recursive"
181 | );
182 | assert_eq!(
183 | Folder::collapse_stack("has;some;some;recursion;recursion".into()),
184 | "has;some;recursion"
185 | );
186 | assert_eq!(
187 | Folder::collapse_stack("co;recursive;co;recursive".into()),
188 | "co;recursive;co;recursive"
189 | );
190 | }
191 |
192 | #[test]
193 | fn test_line_parts() {
194 | assert_eq!(
195 | Folder::line_parts("foo;bar;baz 42"),
196 | Some(("foo;bar;baz", 42))
197 | );
198 | assert_eq!(Folder::line_parts(""), None);
199 | assert_eq!(Folder::line_parts("no;number"), None);
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/src/collapse/vtune.rs:
--------------------------------------------------------------------------------
1 | use std::io::{self, BufRead};
2 |
3 | use log::warn;
4 |
5 | use crate::collapse::common::Occurrences;
6 | use crate::collapse::Collapse;
7 |
8 | // The call graph begins after this line.
9 | static HEADER: &str = "Function Stack,CPU Time:Self,Module";
10 |
11 | /// `vtune` folder configuration options.
12 | #[derive(Clone, Debug, Default)]
13 | #[non_exhaustive]
14 | pub struct Options {
15 | /// Don't include modules with function names.
16 | ///
17 | /// Default is `false`.
18 | pub no_modules: bool,
19 | }
20 |
21 | /// A stack collapser for CSV call graphs created with the VTune `amplxe-cl` tool.
22 | ///
23 | /// To construct one, either use `vtune::Folder::default()` or create an [`Options`] and use
24 | /// `vtune::Folder::from(options)`.
25 | #[derive(Clone, Default)]
26 | pub struct Folder {
27 | /// Function on the stack in this entry thus far.
28 | stack: Vec,
29 |
30 | opt: Options,
31 | }
32 |
33 | impl Collapse for Folder {
34 | fn collapse(&mut self, mut reader: R, writer: W) -> io::Result<()>
35 | where
36 | R: io::BufRead,
37 | W: io::Write,
38 | {
39 | // Consume the header...
40 | let mut line = Vec::new();
41 | loop {
42 | line.clear();
43 | if reader.read_until(0x0A, &mut line)? == 0 {
44 | warn!("File ended before header");
45 | return Ok(());
46 | };
47 | let l = String::from_utf8_lossy(&line);
48 | if l.starts_with(HEADER) {
49 | break;
50 | }
51 | }
52 |
53 | // Process the data...
54 | let mut occurrences = Occurrences::new(1);
55 | loop {
56 | line.clear();
57 | if reader.read_until(0x0A, &mut line)? == 0 {
58 | break;
59 | }
60 | let l = String::from_utf8_lossy(&line);
61 | let line = l.trim_end();
62 | if line.is_empty() {
63 | continue;
64 | } else {
65 | self.on_line(line, &mut occurrences)?;
66 | }
67 | }
68 |
69 | // Write the results...
70 | occurrences.write_and_clear(writer)?;
71 |
72 | // Reset the state...
73 | self.stack.clear();
74 | Ok(())
75 | }
76 |
77 | /// Check for header
78 | fn is_applicable(&mut self, input: &str) -> Option {
79 | let mut input = input.as_bytes();
80 | let mut line = String::new();
81 | loop {
82 | line.clear();
83 | if let Ok(n) = input.read_line(&mut line) {
84 | if n == 0 {
85 | break;
86 | }
87 | } else {
88 | return Some(false);
89 | }
90 |
91 | if line.starts_with(HEADER) {
92 | return Some(true);
93 | }
94 | }
95 | None
96 | }
97 | }
98 |
99 | impl From for Folder {
100 | fn from(opt: Options) -> Self {
101 | Folder {
102 | opt,
103 | ..Default::default()
104 | }
105 | }
106 | }
107 |
108 | impl Folder {
109 | fn line_parts<'a>(&self, line: &'a str) -> Option<(&'a str, &'a str, &'a str)> {
110 | let mut line = if let Some(line) = line.strip_prefix('"') {
111 | // The function name will be in quotes if it contains spaces.
112 | line.splitn(2, "\",")
113 | } else {
114 | // We split on a string because we need to match the type of the other if branch.
115 | #[allow(clippy::single_char_pattern)]
116 | line.splitn(2, ",")
117 | };
118 |
119 | let func = line.next()?;
120 | let mut line = line.next()?.splitn(2, ',');
121 | let time = line.next()?;
122 | let module = if self.opt.no_modules {
123 | ""
124 | } else {
125 | line.next()?
126 | };
127 |
128 | Some((func, time, module))
129 | }
130 |
131 | fn on_line(&mut self, line: &str, occurrences: &mut Occurrences) -> io::Result<()> {
132 | if let Some(spaces) = line.find(|c| c != ' ') {
133 | let prev_depth = self.stack.len();
134 | let depth = spaces + 1;
135 |
136 | if depth <= prev_depth {
137 | // If the depth of this line is less than the previous one,
138 | // it means the previous line was a leaf node and we should
139 | // pop the stack back to one before the current depth.
140 | for _ in 0..=prev_depth - depth {
141 | self.stack.pop();
142 | }
143 | } else if depth > prev_depth + 1 {
144 | return invalid_data_error!("Skipped indentation level at line:\n{}", line);
145 | }
146 |
147 | if let Some((func, time, module)) = self.line_parts(&line[spaces..]) {
148 | if let Ok(time) = time.parse::() {
149 | let time_ms = (time * 1000.0).round() as usize;
150 | if module.is_empty() {
151 | self.stack.push(func.to_string());
152 | } else {
153 | self.stack.push(format!("{}`{}", module, func));
154 | }
155 | if time_ms > 0 {
156 | self.write_stack(occurrences, time_ms);
157 | }
158 | } else {
159 | return invalid_data_error!("Invalid `CPU Time:Self` field: {}", time);
160 | }
161 | } else {
162 | return invalid_data_error!("Unable to parse stack line:\n{}", line);
163 | }
164 | }
165 |
166 | Ok(())
167 | }
168 |
169 | fn write_stack(&self, occurrences: &mut Occurrences, time: usize) {
170 | occurrences.insert(self.stack.join(";"), time);
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/differential/mod.rs:
--------------------------------------------------------------------------------
1 | use std::fs::File;
2 | use std::io::{self, prelude::*};
3 | use std::path::Path;
4 |
5 | use ahash::AHashMap;
6 | use log::warn;
7 |
8 | const READER_CAPACITY: usize = 128 * 1024;
9 |
10 | #[derive(Debug, Clone, Copy, Default)]
11 | struct Counts {
12 | first: usize,
13 | second: usize,
14 | }
15 |
16 | /// Configure the generated output.
17 | ///
18 | /// All options default to off.
19 | #[derive(Debug, Clone, Copy, Default)]
20 | pub struct Options {
21 | /// Normalize the first profile count to match the second.
22 | ///
23 | /// This can help in scenarios where you take profiles at different times, under varying
24 | /// load. If you generate a differential flame graph without setting this flag, everything
25 | /// will look red if the load increased, or blue if it decreased. If this flag is set,
26 | /// the first profile is balanced so you get the full red/blue spectrum.
27 | pub normalize: bool,
28 |
29 | /// Strip hex numbers (addresses) of the form "0x45ef2173" and replace with "0x...".
30 | pub strip_hex: bool,
31 | }
32 |
33 | /// Produce an output that can be used to generate a differential flame graph.
34 | ///
35 | /// The readers are expected to contain folded stack lines of before and after profiles with
36 | /// the following whitespace-separated fields:
37 | ///
38 | /// - A semicolon-separated list of frame names (e.g., `main;foo;bar;baz`).
39 | /// - A sample count for the given stack.
40 | ///
41 | /// The output written to the `writer` will be similar to the inputs, except there will be two
42 | /// sample count columns -- one for each profile.
43 | pub fn from_readers(opt: Options, before: R1, after: R2, writer: W) -> io::Result<()>
44 | where
45 | R1: BufRead,
46 | R2: BufRead,
47 | W: Write,
48 | {
49 | let mut stack_counts = AHashMap::default();
50 | let total1 = parse_stack_counts(opt, &mut stack_counts, before, true)?;
51 | let total2 = parse_stack_counts(opt, &mut stack_counts, after, false)?;
52 | if opt.normalize && total1 != total2 {
53 | for counts in stack_counts.values_mut() {
54 | counts.first = (counts.first as f64 * total2 as f64 / total1 as f64) as usize;
55 | }
56 | }
57 | write_stacks(&stack_counts, writer)
58 | }
59 |
60 | /// Produce an output that can be used to generate a differential flame graph from
61 | /// a before and an after profile.
62 | ///
63 | /// See [`from_readers`] for the input and output formats.
64 | pub fn from_files(
65 | opt: Options,
66 | file_before: P1,
67 | file_after: P2,
68 | writer: W,
69 | ) -> io::Result<()>
70 | where
71 | P1: AsRef,
72 | P2: AsRef,
73 | W: Write,
74 | {
75 | let file1 = File::open(file_before)?;
76 | let reader1 = io::BufReader::with_capacity(READER_CAPACITY, file1);
77 | let file2 = File::open(file_after)?;
78 | let reader2 = io::BufReader::with_capacity(READER_CAPACITY, file2);
79 | from_readers(opt, reader1, reader2, writer)
80 | }
81 |
82 | // Populate stack_counts based on lines from the reader and returns the sum of the sample counts.
83 | fn parse_stack_counts(
84 | opt: Options,
85 | stack_counts: &mut AHashMap,
86 | mut reader: R,
87 | is_first: bool,
88 | ) -> io::Result
89 | where
90 | R: BufRead,
91 | {
92 | let mut total = 0;
93 | let mut line = Vec::new();
94 | let mut stripped_fractional_samples = false;
95 | loop {
96 | line.clear();
97 |
98 | if reader.read_until(0x0A, &mut line)? == 0 {
99 | break;
100 | }
101 |
102 | let l = String::from_utf8_lossy(&line);
103 | if let Some((stack, count)) =
104 | parse_line(&l, opt.strip_hex, &mut stripped_fractional_samples)
105 | {
106 | let counts = stack_counts.entry(stack).or_default();
107 | if is_first {
108 | counts.first += count;
109 | } else {
110 | counts.second += count;
111 | }
112 | total += count;
113 | } else {
114 | warn!("Unable to parse line: {}", l);
115 | }
116 | }
117 |
118 | Ok(total)
119 | }
120 |
121 | // Write three-column lines with the folded stack trace and two value columns,
122 | // one for each profile.
123 | fn write_stacks(stack_counts: &AHashMap, mut writer: W) -> io::Result<()>
124 | where
125 | W: Write,
126 | {
127 | for (stack, &Counts { first, second }) in stack_counts {
128 | writeln!(writer, "{} {} {}", stack, first, second)?;
129 | }
130 | Ok(())
131 | }
132 |
133 | // Parse stack and sample count from line.
134 | fn parse_line(
135 | line: &str,
136 | strip_hex: bool,
137 | stripped_fractional_samples: &mut bool,
138 | ) -> Option<(String, usize)> {
139 | let samplesi = line.rfind(' ')?;
140 | let mut samples = line[samplesi + 1..].trim_end();
141 |
142 | // Strip fractional part (if any);
143 | // foobar 1.klwdjlakdj
144 | //
145 | // The Perl version keeps the fractional part but inferno
146 | // strips them in its flamegraph implementation anyway.
147 | if let Some(doti) = samples.find('.') {
148 | if !samples[..doti]
149 | .chars()
150 | .chain(samples[doti + 1..].chars())
151 | .all(|c| c.is_ascii_digit())
152 | {
153 | return None;
154 | }
155 | // Warn if we're stripping a non-zero fractional part, but only the first time.
156 | if !*stripped_fractional_samples && !samples[doti + 1..].chars().all(|c| c == '0') {
157 | *stripped_fractional_samples = true;
158 | warn!("The input data has fractional sample counts that will be truncated to integers");
159 | }
160 | samples = &samples[..doti];
161 | }
162 |
163 | let nsamples = samples.parse::().ok()?;
164 | let stack = line[..samplesi].trim_end();
165 | if strip_hex {
166 | Some((strip_hex_address(stack), nsamples))
167 | } else {
168 | Some((stack.to_string(), nsamples))
169 | }
170 | }
171 |
172 | // Replace all hex strings like "0x45ef2173" with "0x...".
173 | fn strip_hex_address(mut stack: &str) -> String {
174 | let mut stripped = String::with_capacity(stack.len());
175 | while let Some(idx) = stack.find("0x") {
176 | stripped.push_str(&stack[..idx + 2]);
177 | let ndigits = stack[idx + 2..]
178 | .chars()
179 | .take_while(|c| c.is_ascii_hexdigit())
180 | .count();
181 | if ndigits > 0 {
182 | stripped.push_str("...");
183 | }
184 | stack = &stack[idx + 2 + ndigits..];
185 | }
186 | stripped.push_str(stack);
187 | stripped
188 | }
189 |
--------------------------------------------------------------------------------
/src/flamegraph/flamegraph.css:
--------------------------------------------------------------------------------
1 | #matched { text-anchor:end; }
2 | #search { text-anchor:end; opacity:0.1; cursor:pointer; }
3 | #search:hover, #search.show { opacity:1; }
4 | #subtitle { text-anchor:middle; font-color:rgb(160,160,160); }
5 | #unzoom { cursor:pointer; }
6 | #frames > *:hover { stroke:black; stroke-width:0.5; cursor:pointer; }
7 | .hide { display:none; }
8 | .parent { opacity:0.5; }
9 |
--------------------------------------------------------------------------------
/src/flamegraph/rand.rs:
--------------------------------------------------------------------------------
1 | use std::cell::RefCell;
2 |
3 | pub(super) struct XorShift64 {
4 | a: u64,
5 | }
6 |
7 | impl XorShift64 {
8 | pub(super) fn new(seed: u64) -> XorShift64 {
9 | XorShift64 { a: seed }
10 | }
11 |
12 | pub(super) fn next(&mut self) -> u64 {
13 | let mut x = self.a;
14 | x ^= x << 13;
15 | x ^= x >> 7;
16 | x ^= x << 17;
17 | self.a = x;
18 | x
19 | }
20 |
21 | pub(super) fn next_f64(&mut self) -> f64 {
22 | sample(self.next())
23 | }
24 | }
25 |
26 | thread_local! {
27 | pub(super) static RNG: RefCell = RefCell::new(XorShift64::new(1234));
28 | }
29 |
30 | // Copied from `rand` with minor modifications.
31 | fn sample(value: u64) -> f64 {
32 | let fraction_bits = 52;
33 |
34 | // Multiply-based method; 24/53 random bits; [0, 1) interval.
35 | // We use the most significant bits because for simple RNGs
36 | // those are usually more random.
37 | let float_size = std::mem::size_of::() as u32 * 8;
38 | let precision = fraction_bits + 1;
39 | let scale = 1.0 / ((1_u64 << precision) as f64);
40 |
41 | let value = value >> (float_size - precision);
42 | scale * (value as f64)
43 | }
44 |
45 | pub(super) fn thread_rng() -> impl Fn() -> f32 {
46 | || RNG.with(|rng| rng.borrow_mut().next_f64() as f32)
47 | }
48 |
49 | #[test]
50 | fn test_rng() {
51 | const ITERATIONS: usize = 10000;
52 |
53 | let mut rng = XorShift64::new(1234);
54 | let mut sum = rng.next_f64();
55 | let mut min = sum;
56 | let mut max = sum;
57 | for _ in 0..ITERATIONS - 1 {
58 | let value = rng.next_f64();
59 | sum += value;
60 | if value < min {
61 | min = value;
62 | }
63 | if value > max {
64 | max = value;
65 | }
66 | }
67 |
68 | let avg = sum / ITERATIONS as f64;
69 |
70 | // Make sure the RNG is uniform.
71 | assert!(min >= 0.000);
72 | assert!(min <= 0.001);
73 | assert!(max <= 1.000);
74 | assert!(max >= 0.999);
75 | assert!(avg >= 0.490);
76 | assert!(avg <= 0.510);
77 | }
78 |
--------------------------------------------------------------------------------
/tests/collapse-dtrace.rs:
--------------------------------------------------------------------------------
1 | mod common;
2 |
3 | use std::fs::File;
4 | use std::io::{self, BufReader, Cursor};
5 | use std::process::{Command, Stdio};
6 |
7 | use assert_cmd::cargo::CommandCargoExt;
8 | use inferno::collapse::dtrace::{Folder, Options};
9 | use log::Level;
10 | use pretty_assertions::assert_eq;
11 | use testing_logger::CapturedLog;
12 |
13 | fn test_collapse_dtrace(test_file: &str, expected_file: &str, options: Options) -> io::Result<()> {
14 | for &n in &[1, 2] {
15 | let mut options = options.clone();
16 | options.nthreads = n;
17 | common::test_collapse(Folder::from(options), test_file, expected_file, false)?;
18 | }
19 | Ok(())
20 | }
21 |
22 | fn test_collapse_dtrace_logs_with_options(input_file: &str, asserter: F, mut options: Options)
23 | where
24 | F: Fn(&Vec),
25 | {
26 | // We must run log tests in a single thread to play nicely with `testing_logger`.
27 | options.nthreads = 1;
28 | common::test_collapse_logs(Folder::from(options), input_file, asserter);
29 | }
30 |
31 | fn test_collapse_dtrace_logs(input_file: &str, asserter: F)
32 | where
33 | F: Fn(&Vec),
34 | {
35 | test_collapse_dtrace_logs_with_options(input_file, asserter, Options::default());
36 | }
37 |
38 | #[test]
39 | fn collapse_dtrace_compare_to_upstream() {
40 | let test_file = "./flamegraph/example-dtrace-stacks.txt";
41 | let result_file = "./tests/data/collapse-dtrace/results/dtrace-example.txt";
42 | test_collapse_dtrace(test_file, result_file, Options::default()).unwrap()
43 | }
44 |
45 | #[test]
46 | fn collapse_dtrace_compare_to_upstream_with_offsets() {
47 | let test_file = "./flamegraph/example-dtrace-stacks.txt";
48 | let result_file = "./tests/data/collapse-dtrace/results/dtrace-example-offsets.txt";
49 |
50 | let mut options = Options::default();
51 | options.includeoffset = true;
52 |
53 | test_collapse_dtrace(test_file, result_file, options).unwrap()
54 | }
55 |
56 | #[test]
57 | fn collapse_dtrace_compare_to_upstream_java() {
58 | let test_file = "./tests/data/collapse-dtrace/java.txt";
59 | let result_file = "./tests/data/collapse-dtrace/results/java.txt";
60 | test_collapse_dtrace(test_file, result_file, Options::default()).unwrap()
61 | }
62 |
63 | #[test]
64 | fn collapse_dtrace_hex_addresses() {
65 | let test_file = "./tests/data/collapse-dtrace/hex-addresses.txt";
66 | let result_file = "./tests/data/collapse-dtrace/results/hex-addresses.txt";
67 | test_collapse_dtrace(test_file, result_file, Options::default()).unwrap()
68 | }
69 |
70 | #[test]
71 | fn collapse_dtrace_compare_to_flamegraph_bug() {
72 | // There is a bug in flamegraph that causes the following stack to render
73 | // badly. We fix this but keep the test around to point out this breakage
74 | // of bug compatibility.
75 | //
76 | // https://github.com/brendangregg/FlameGraph/issues/202
77 | let test_file = "./tests/data/collapse-dtrace/flamegraph-bug.txt";
78 | let result_file = "./tests/data/collapse-dtrace/results/flamegraph-bug.txt";
79 |
80 | let mut options = Options::default();
81 | options.includeoffset = true;
82 |
83 | test_collapse_dtrace(test_file, result_file, options).unwrap()
84 | }
85 |
86 | #[test]
87 | fn collapse_dtrace_stack_ustack() {
88 | let test_file = "./tests/data/collapse-dtrace/stack-ustack.txt";
89 | let result_file = "./tests/data/collapse-dtrace/results/stack-ustack.txt";
90 |
91 | test_collapse_dtrace(test_file, result_file, Options::default()).unwrap()
92 | }
93 |
94 | #[test]
95 | fn collapse_dtrace_should_log_warning_for_only_header_lines() {
96 | test_collapse_dtrace_logs(
97 | "./tests/data/collapse-dtrace/only-header-lines.txt",
98 | |captured_logs| {
99 | let nwarnings = captured_logs
100 | .iter()
101 | .filter(|log| {
102 | log.body == "File ended while skipping headers" && log.level == Level::Warn
103 | })
104 | .count();
105 | assert_eq!(
106 | nwarnings, 1,
107 | "warning logged {} times, but should be logged exactly once",
108 | nwarnings
109 | );
110 | },
111 | );
112 | }
113 |
114 | #[test]
115 | fn collapse_dtrace_scope_with_no_argument_list() {
116 | let test_file = "./tests/data/collapse-dtrace/scope_with_no_argument_list.txt";
117 | let result_file = "./tests/data/collapse-dtrace/results/scope_with_no_argument_list.txt";
118 | test_collapse_dtrace(test_file, result_file, Options::default()).unwrap()
119 | }
120 |
121 | #[test]
122 | fn collapse_dtrace_rust_names() {
123 | let test_file = "./tests/data/collapse-dtrace/rust-names.txt";
124 | let result_file = "./tests/data/collapse-dtrace/results/rust-names.txt";
125 | test_collapse_dtrace(test_file, result_file, Options::default()).unwrap()
126 | }
127 |
128 | #[test]
129 | fn collapse_dtrace_cli() {
130 | let input_file = "./flamegraph/example-dtrace-stacks.txt";
131 | let expected_file = "./tests/data/collapse-dtrace/results/dtrace-example.txt";
132 |
133 | // Test with file passed in
134 | let output = Command::cargo_bin("inferno-collapse-dtrace")
135 | .unwrap()
136 | .arg(input_file)
137 | .output()
138 | .expect("failed to execute process");
139 | let expected = BufReader::new(File::open(expected_file).unwrap());
140 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
141 |
142 | // Test with STDIN
143 | let mut child = Command::cargo_bin("inferno-collapse-dtrace")
144 | .unwrap()
145 | .stdin(Stdio::piped())
146 | .stdout(Stdio::piped())
147 | .spawn()
148 | .expect("Failed to spawn child process");
149 | let mut input = BufReader::new(File::open(input_file).unwrap());
150 | let stdin = child.stdin.as_mut().expect("Failed to open stdin");
151 | io::copy(&mut input, stdin).unwrap();
152 | let output = child.wait_with_output().expect("Failed to read stdout");
153 | let expected = BufReader::new(File::open(expected_file).unwrap());
154 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
155 | }
156 |
--------------------------------------------------------------------------------
/tests/collapse-ghcprof.rs:
--------------------------------------------------------------------------------
1 | mod common;
2 |
3 | use std::fs::File;
4 | use std::io::{self, BufReader, Cursor};
5 | use std::process::{Command, Stdio};
6 |
7 | use assert_cmd::prelude::CommandCargoExt;
8 | use inferno::collapse::ghcprof::{Folder, Options, Source};
9 |
10 | fn test_collapse_ghcprof(test_file: &str, expected_file: &str, options: Options) -> io::Result<()> {
11 | common::test_collapse(Folder::from(options), test_file, expected_file, false)
12 | }
13 |
14 | #[test]
15 | fn collapse_percent_default() {
16 | let test_file = "./tests/data/collapse-ghcprof/percent.prof";
17 | let result_file = "./tests/data/collapse-ghcprof/results/percent.txt";
18 | test_collapse_ghcprof(test_file, result_file, Options::default()).unwrap()
19 | }
20 |
21 | #[test]
22 | fn collapse_ticks_default() {
23 | let test_file = "./tests/data/collapse-ghcprof/ticks.prof";
24 | let result_file = "./tests/data/collapse-ghcprof/results/ticks.txt";
25 | test_collapse_ghcprof(test_file, result_file, Options::default()).unwrap()
26 | }
27 |
28 | #[test]
29 | fn collapse_ticks_percent() {
30 | let test_file = "./tests/data/collapse-ghcprof/ticks.prof";
31 | let result_file = "./tests/data/collapse-ghcprof/results/ticks.txt";
32 | let mut options = Options::default();
33 | options.source = Source::PercentTime;
34 | test_collapse_ghcprof(test_file, result_file, options).unwrap()
35 | }
36 |
37 | #[test]
38 | fn collapse_ticks_ticks() {
39 | let test_file = "./tests/data/collapse-ghcprof/ticks.prof";
40 | let result_file = "./tests/data/collapse-ghcprof/results/ticks_ticks.txt";
41 | let mut options = Options::default();
42 | options.source = Source::Ticks;
43 | test_collapse_ghcprof(test_file, result_file, options).unwrap()
44 | }
45 |
46 | #[test]
47 | fn collapse_bytes_bytes() {
48 | let test_file = "./tests/data/collapse-ghcprof/ticks.prof";
49 | let result_file = "./tests/data/collapse-ghcprof/results/ticks_bytes.txt";
50 | let mut options = Options::default();
51 | options.source = Source::Bytes;
52 | test_collapse_ghcprof(test_file, result_file, options).unwrap()
53 | }
54 |
55 | #[test]
56 | fn collapse_utf8_default() {
57 | let test_file = "./tests/data/collapse-ghcprof/utf8.prof";
58 | let result_file = "./tests/data/collapse-ghcprof/results/utf8.txt";
59 | test_collapse_ghcprof(test_file, result_file, Options::default()).unwrap()
60 | }
61 |
62 | #[test]
63 | fn collapse_utf8_ticks() {
64 | let test_file = "./tests/data/collapse-ghcprof/utf8.prof";
65 | let result_file = "./tests/data/collapse-ghcprof/results/utf8_ticks.txt";
66 | let mut options = Options::default();
67 | options.source = Source::Ticks;
68 | test_collapse_ghcprof(test_file, result_file, options).unwrap()
69 | }
70 |
71 | #[test]
72 | fn collapse_utf8_bytes() {
73 | let test_file = "./tests/data/collapse-ghcprof/utf8.prof";
74 | let result_file = "./tests/data/collapse-ghcprof/results/utf8_bytes.txt";
75 | let mut options = Options::default();
76 | options.source = Source::Bytes;
77 | test_collapse_ghcprof(test_file, result_file, options).unwrap()
78 | }
79 |
80 | #[test]
81 | fn collapse_ghcprof_cli() {
82 | let input_file = "./tests/data/collapse-ghcprof/ticks.prof";
83 | let expected_file = "./tests/data/collapse-ghcprof/results/ticks.txt";
84 |
85 | // Test with file passed in
86 | let output = Command::cargo_bin("inferno-collapse-ghcprof")
87 | .unwrap()
88 | .arg(input_file)
89 | .output()
90 | .expect("failed to execute process");
91 | let expected = BufReader::new(File::open(expected_file).unwrap());
92 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
93 |
94 | // Test with STDIN
95 | let mut child = Command::cargo_bin("inferno-collapse-ghcprof")
96 | .unwrap()
97 | .stdin(Stdio::piped())
98 | .stdout(Stdio::piped())
99 | .spawn()
100 | .expect("Failed to spawn child process");
101 | let mut input = BufReader::new(File::open(input_file).unwrap());
102 | let stdin = child.stdin.as_mut().expect("Failed to open stdin");
103 | io::copy(&mut input, stdin).unwrap();
104 | let output = child.wait_with_output().expect("Failed to read stdout");
105 | let expected = BufReader::new(File::open(expected_file).unwrap());
106 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
107 |
108 | // Test --ticks and --bytes conflict
109 | let output = Command::cargo_bin("inferno-collapse-ghcprof")
110 | .unwrap()
111 | .arg(input_file)
112 | .arg("--ticks")
113 | .arg("--bytes")
114 | .output()
115 | .expect("failed to execute process");
116 | assert!(!output.status.success());
117 | }
118 |
--------------------------------------------------------------------------------
/tests/collapse-recursive.rs:
--------------------------------------------------------------------------------
1 | mod common;
2 |
3 | use std::fs::File;
4 | use std::io::{self, BufReader, Cursor};
5 | use std::process::{Command, Stdio};
6 |
7 | use assert_cmd::cargo::CommandCargoExt;
8 | use inferno::collapse::recursive::{Folder, Options};
9 |
10 | fn test_collapse_recursive(
11 | test_file: &str,
12 | expected_file: &str,
13 | options: Options,
14 | ) -> io::Result<()> {
15 | for &n in &[1, 2] {
16 | let mut options = options.clone();
17 | options.nthreads = n;
18 | common::test_collapse(Folder::from(options), test_file, expected_file, false)?;
19 | }
20 | Ok(())
21 | }
22 |
23 | #[test]
24 | fn collapse_recursive_basic() {
25 | let test_file = "./tests/data/collapse-recursive/basic.txt";
26 | let result_file = "./tests/data/collapse-recursive/results/basic-collapsed.txt";
27 | test_collapse_recursive(test_file, result_file, Options::default()).unwrap()
28 | }
29 |
30 | #[test]
31 | fn collapse_recursive_cli() {
32 | let input_file = "./tests/data/collapse-recursive/basic.txt";
33 | let expected_file = "./tests/data/collapse-recursive/results/basic-collapsed.txt";
34 |
35 | // Test with file passed in
36 | let output = Command::cargo_bin("inferno-collapse-recursive")
37 | .unwrap()
38 | .arg(input_file)
39 | .output()
40 | .expect("failed to execute process");
41 | let expected = BufReader::new(File::open(expected_file).unwrap());
42 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
43 |
44 | // Test with STDIN
45 | let mut child = Command::cargo_bin("inferno-collapse-recursive")
46 | .unwrap()
47 | .stdin(Stdio::piped())
48 | .stdout(Stdio::piped())
49 | .spawn()
50 | .expect("Failed to spawn child process");
51 | let mut input = BufReader::new(File::open(input_file).unwrap());
52 | let stdin = child.stdin.as_mut().expect("Failed to open stdin");
53 | io::copy(&mut input, stdin).unwrap();
54 | let output = child.wait_with_output().expect("Failed to read stdout");
55 | let expected = BufReader::new(File::open(expected_file).unwrap());
56 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
57 | }
58 |
--------------------------------------------------------------------------------
/tests/collapse-vsprof.rs:
--------------------------------------------------------------------------------
1 | mod common;
2 |
3 | use std::fs::File;
4 | use std::io::{self, BufReader, Cursor};
5 | use std::process::{Command, Stdio};
6 |
7 | use assert_cmd::prelude::*;
8 | use inferno::collapse::vsprof::Folder;
9 | use log::Level;
10 | use pretty_assertions::assert_eq;
11 | use testing_logger::CapturedLog;
12 |
13 | fn test_collapse_vsprof(test_file: &str, expected_file: &str) -> io::Result<()> {
14 | common::test_collapse(Folder::default(), test_file, expected_file, false)
15 | }
16 |
17 | fn test_collapse_vsprof_error(test_file: &str) -> io::Error {
18 | common::test_collapse_error(Folder::default(), test_file)
19 | }
20 |
21 | fn test_collapse_vsprof_logs(input_file: &str, asserter: F)
22 | where
23 | F: Fn(&Vec),
24 | {
25 | common::test_collapse_logs(Folder::default(), input_file, asserter);
26 | }
27 |
28 | #[test]
29 | fn collapse_vsprof_default() {
30 | let test_file = "./tests/data/collapse-vsprof/CallTreeSummary.csv";
31 | let result_file = "./tests/data/collapse-vsprof/results/sample-default.txt";
32 | test_collapse_vsprof(test_file, result_file).unwrap()
33 | }
34 |
35 | #[test]
36 | fn collapse_vsprof_should_log_warning_for_ending_before_call_graph_start() {
37 | test_collapse_vsprof_logs(
38 | "./tests/data/collapse-vsprof/empty-file.csv",
39 | |captured_logs| {
40 | let nwarnings = captured_logs
41 | .iter()
42 | .filter(|log| {
43 | log.body == "File ended before start of call graph" && log.level == Level::Warn
44 | })
45 | .count();
46 | assert_eq!(
47 | nwarnings, 1,
48 | "warning logged {} times, but should be logged exactly once",
49 | nwarnings
50 | );
51 | },
52 | );
53 | }
54 |
55 | #[test]
56 | fn collapse_vsprof_should_return_error_for_incorrect_header() {
57 | let test_file = "./tests/data/collapse-vsprof/incorrect-header.csv";
58 | let error = test_collapse_vsprof_error(test_file);
59 | assert_eq!(error.kind(), io::ErrorKind::InvalidData);
60 | assert!(error
61 | .to_string()
62 | .starts_with("Expected first line to be header line"));
63 | }
64 |
65 | #[test]
66 | fn collapse_vsprof_should_return_error_for_missing_function_name() {
67 | let test_file = "./tests/data/collapse-vsprof/missing-function-name.csv";
68 | let error = test_collapse_vsprof_error(test_file);
69 | assert_eq!(error.kind(), io::ErrorKind::InvalidData);
70 | assert!(error
71 | .to_string()
72 | .starts_with("Missing function name in line:"));
73 | }
74 |
75 | #[test]
76 | fn collapse_vsprof_should_return_error_for_invalid_function_name() {
77 | let test_file = "./tests/data/collapse-vsprof/invalid-function-name.csv";
78 | let error = test_collapse_vsprof_error(test_file);
79 | assert_eq!(error.kind(), io::ErrorKind::InvalidData);
80 | assert!(error
81 | .to_string()
82 | .starts_with("Unable to parse function name from line:"));
83 | }
84 |
85 | #[test]
86 | fn collapse_vsprof_should_return_error_for_invalid_depth() {
87 | let test_file = "./tests/data/collapse-vsprof/invalid-depth.csv";
88 | let error = test_collapse_vsprof_error(test_file);
89 | assert_eq!(error.kind(), io::ErrorKind::InvalidData);
90 | assert!(error
91 | .to_string()
92 | .starts_with("Unable to parse integer from"));
93 | }
94 |
95 | #[test]
96 | fn collapse_vsprof_should_return_error_for_invalid_number_of_calls() {
97 | let test_file = "./tests/data/collapse-vsprof/invalid-number-of-calls.csv";
98 | let error = test_collapse_vsprof_error(test_file);
99 | assert_eq!(error.kind(), io::ErrorKind::InvalidData);
100 | assert!(error
101 | .to_string()
102 | .starts_with("Unable to parse integer from"));
103 | }
104 |
105 | #[test]
106 | fn collapse_vsprof_cli() {
107 | let input_file = "./tests/data/collapse-vsprof/CallTreeSummary.csv";
108 | let expected_file = "./tests/data/collapse-vsprof/results/sample-default.txt";
109 |
110 | // Test with file passed in
111 | let output = Command::cargo_bin("inferno-collapse-vsprof")
112 | .unwrap()
113 | .arg(input_file)
114 | .output()
115 | .expect("failed to execute process");
116 | let expected = BufReader::new(File::open(expected_file).unwrap());
117 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
118 |
119 | // Test with STDIN
120 | let mut child = Command::cargo_bin("inferno-collapse-vsprof")
121 | .unwrap()
122 | .stdin(Stdio::piped())
123 | .stdout(Stdio::piped())
124 | .spawn()
125 | .expect("Failed to spawn child process");
126 | let mut input = BufReader::new(File::open(input_file).unwrap());
127 | let stdin = child.stdin.as_mut().expect("Failed to open stdin");
128 | io::copy(&mut input, stdin).unwrap();
129 | let output = child.wait_with_output().expect("Failed to read stdout");
130 | let expected = BufReader::new(File::open(expected_file).unwrap());
131 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
132 | }
133 |
--------------------------------------------------------------------------------
/tests/collapse-vtune.rs:
--------------------------------------------------------------------------------
1 | mod common;
2 |
3 | use std::fs::File;
4 | use std::io::{self, BufReader, Cursor};
5 | use std::process::{Command, Stdio};
6 |
7 | use assert_cmd::prelude::*;
8 | use inferno::collapse::vtune::{Folder, Options};
9 | use log::Level;
10 | use pretty_assertions::assert_eq;
11 | use testing_logger::CapturedLog;
12 |
13 | fn test_collapse_vtune(test_file: &str, expected_file: &str, options: Options) -> io::Result<()> {
14 | common::test_collapse(Folder::from(options), test_file, expected_file, false)
15 | }
16 |
17 | fn test_collapse_vtune_error(test_file: &str, options: Options) -> io::Error {
18 | common::test_collapse_error(Folder::from(options), test_file)
19 | }
20 |
21 | fn test_collapse_vtune_logs_with_options(input_file: &str, asserter: F, options: Options)
22 | where
23 | F: Fn(&Vec),
24 | {
25 | common::test_collapse_logs(Folder::from(options), input_file, asserter);
26 | }
27 |
28 | fn test_collapse_vtune_logs(input_file: &str, asserter: F)
29 | where
30 | F: Fn(&Vec),
31 | {
32 | test_collapse_vtune_logs_with_options(input_file, asserter, Options::default());
33 | }
34 |
35 | #[test]
36 | fn collapse_vtune_default() {
37 | let test_file = "./tests/data/collapse-vtune/vtune.csv";
38 | let result_file = "./tests/data/collapse-vtune/results/vtune-default.txt";
39 | test_collapse_vtune(test_file, result_file, Options::default()).unwrap()
40 | }
41 |
42 | #[test]
43 | fn collapse_vtune_no_modules() {
44 | let test_file = "./tests/data/collapse-vtune/vtune.csv";
45 | let result_file = "./tests/data/collapse-vtune/results/vtune-no-modules.txt";
46 |
47 | let mut options = Options::default();
48 | options.no_modules = true;
49 |
50 | test_collapse_vtune(test_file, result_file, options).unwrap()
51 | }
52 |
53 | #[test]
54 | fn collapse_vtune_should_log_warning_for_ending_before_header() {
55 | test_collapse_vtune_logs(
56 | "./tests/data/collapse-vtune/end-before-header.csv",
57 | |captured_logs| {
58 | let nwarnings = captured_logs
59 | .iter()
60 | .filter(|log| log.body == "File ended before header" && log.level == Level::Warn)
61 | .count();
62 | assert_eq!(
63 | nwarnings, 1,
64 | "warning logged {} times, but should be logged exactly once",
65 | nwarnings
66 | );
67 | },
68 | );
69 | }
70 |
71 | #[test]
72 | fn collapse_vtune_should_return_error_for_skipped_indent_level() {
73 | let test_file = "./tests/data/collapse-vtune/skipped-indentation.csv";
74 | let error = test_collapse_vtune_error(test_file, Options::default());
75 | assert_eq!(error.kind(), io::ErrorKind::InvalidData);
76 | assert!(error
77 | .to_string()
78 | .starts_with("Skipped indentation level at line"));
79 | }
80 |
81 | #[test]
82 | fn collapse_vtune_should_return_error_for_invalid_time_field() {
83 | let test_file = "./tests/data/collapse-vtune/invalid-time-field.csv";
84 | let error = test_collapse_vtune_error(test_file, Options::default());
85 | assert_eq!(error.kind(), io::ErrorKind::InvalidData);
86 | assert!(error
87 | .to_string()
88 | .starts_with("Invalid `CPU Time:Self` field"));
89 | }
90 |
91 | #[test]
92 | fn collapse_vtune_should_return_error_for_bad_stack_line() {
93 | let test_file = "./tests/data/collapse-vtune/bad-stack-line.csv";
94 | let error = test_collapse_vtune_error(test_file, Options::default());
95 | assert_eq!(error.kind(), io::ErrorKind::InvalidData);
96 | assert!(error.to_string().starts_with("Unable to parse stack line"));
97 | }
98 |
99 | #[test]
100 | fn collapse_vtune_cli() {
101 | let input_file = "./tests/data/collapse-vtune/vtune.csv";
102 | let expected_file = "./tests/data/collapse-vtune/results/vtune-default.txt";
103 |
104 | // Test with file passed in
105 | let output = Command::cargo_bin("inferno-collapse-vtune")
106 | .unwrap()
107 | .arg(input_file)
108 | .output()
109 | .expect("failed to execute process");
110 | let expected = BufReader::new(File::open(expected_file).unwrap());
111 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
112 |
113 | // Test with STDIN
114 | let mut child = Command::cargo_bin("inferno-collapse-vtune")
115 | .unwrap()
116 | .stdin(Stdio::piped())
117 | .stdout(Stdio::piped())
118 | .spawn()
119 | .expect("Failed to spawn child process");
120 | let mut input = BufReader::new(File::open(input_file).unwrap());
121 | let stdin = child.stdin.as_mut().expect("Failed to open stdin");
122 | io::copy(&mut input, stdin).unwrap();
123 | let output = child.wait_with_output().expect("Failed to read stdout");
124 | let expected = BufReader::new(File::open(expected_file).unwrap());
125 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
126 | }
127 |
--------------------------------------------------------------------------------
/tests/collapse-xctrace.rs:
--------------------------------------------------------------------------------
1 | mod common;
2 |
3 | use std::fs::File;
4 | use std::io::{self, BufReader, Cursor};
5 | use std::process::{Command, Stdio};
6 |
7 | use assert_cmd::cargo::CommandCargoExt;
8 | use inferno::collapse::xctrace::Folder;
9 |
10 | fn test_collapse_xctrace(test_file: &str, expected_file: &str) -> io::Result<()> {
11 | common::test_collapse(Folder::default(), test_file, expected_file, false)?;
12 | Ok(())
13 | }
14 |
15 | #[test]
16 | fn collapse_xctrace_basic() {
17 | let test_file = "./tests/data/collapse-xctrace/basic.xml";
18 | let result_file = "./tests/data/collapse-xctrace/results/basic.folded";
19 | test_collapse_xctrace(test_file, result_file).unwrap()
20 | }
21 |
22 | #[test]
23 | fn collapse_xctrace_simple_frame_without_binary_info() {
24 | let test_file = "./tests/data/collapse-xctrace/simple_frame_without_binary_info.xml";
25 | let result_file =
26 | "./tests/data/collapse-xctrace/results/simple_frame_without_binary_info.folded";
27 | test_collapse_xctrace(test_file, result_file).unwrap()
28 | }
29 |
30 | #[test]
31 | fn collapse_xctrace_cli() {
32 | let input_file = "./tests/data/collapse-xctrace/basic.xml";
33 | let expected_file = "./tests/data/collapse-xctrace/results/basic.folded";
34 |
35 | // Test with file passed in
36 | let output = Command::cargo_bin("inferno-collapse-xctrace")
37 | .unwrap()
38 | .arg(input_file)
39 | .output()
40 | .expect("failed to execute process");
41 | let expected = BufReader::new(File::open(expected_file).unwrap());
42 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
43 |
44 | // Test with STDIN
45 | let mut child = Command::cargo_bin("inferno-collapse-xctrace")
46 | .unwrap()
47 | .stdin(Stdio::piped())
48 | .stdout(Stdio::piped())
49 | .spawn()
50 | .expect("Failed to spawn child process");
51 | let mut input = BufReader::new(File::open(input_file).unwrap());
52 | let stdin = child.stdin.as_mut().expect("Failed to open stdin");
53 | io::copy(&mut input, stdin).unwrap();
54 | let output = child.wait_with_output().expect("Failed to read stdout");
55 | let expected = BufReader::new(File::open(expected_file).unwrap());
56 | common::compare_results(Cursor::new(output.stdout), expected, expected_file, false);
57 | }
58 |
--------------------------------------------------------------------------------
/tests/common/collapse.rs:
--------------------------------------------------------------------------------
1 | use std::fs::{self, File};
2 | use std::io::{self, BufRead, BufReader, Cursor};
3 |
4 | use inferno::collapse::Collapse;
5 | use libflate::gzip::Decoder;
6 | use pretty_assertions::assert_eq;
7 | use testing_logger::CapturedLog;
8 |
9 | pub fn compare_results(result: R, mut expected: E, expected_file: &str, strip_quotes: bool)
10 | where
11 | R: BufRead,
12 | E: BufRead,
13 | {
14 | let mut buf = String::new();
15 | let mut line_num = 1;
16 | for line in result.lines() {
17 | let line = if strip_quotes {
18 | line.unwrap().replace(['\"', '\''], "")
19 | } else {
20 | line.unwrap()
21 | };
22 | if expected.read_line(&mut buf).unwrap() == 0 {
23 | panic!(
24 | "\noutput has more lines than expected result file: {}",
25 | expected_file
26 | );
27 | }
28 | assert_eq!(line, buf.trim_end(), "\n{}:{}", expected_file, line_num);
29 | buf.clear();
30 | line_num += 1;
31 | }
32 |
33 | if expected.read_line(&mut buf).unwrap() > 0 {
34 | panic!(
35 | "\n{} has more lines than output, beginning at line: {}",
36 | expected_file, line_num
37 | )
38 | }
39 | }
40 |
41 | pub fn test_collapse(
42 | mut collapser: C,
43 | test_filename: &str,
44 | expected_filename: &str,
45 | strip_quotes: bool,
46 | ) -> io::Result<()>
47 | where
48 | C: Collapse,
49 | {
50 | if let Err(e) = fs::metadata(test_filename) {
51 | eprintln!("Failed to open input file '{}'", test_filename);
52 | return Err(e);
53 | }
54 |
55 | let mut collapse = move |out: &mut dyn io::Write| {
56 | if test_filename.ends_with(".gz") {
57 | let test_file = File::open(test_filename)?;
58 | let r = BufReader::new(Decoder::new(test_file).unwrap());
59 | collapser.collapse(r, out)
60 | } else {
61 | collapser.collapse_file(Some(test_filename), out)
62 | }
63 | };
64 |
65 | let metadata = match fs::metadata(expected_filename) {
66 | Ok(m) => m,
67 | Err(e) => {
68 | if e.kind() == io::ErrorKind::NotFound {
69 | // be nice to the dev and make the file
70 | let mut f = File::create(expected_filename).unwrap();
71 | collapse(&mut f)?;
72 | fs::metadata(expected_filename).unwrap()
73 | } else {
74 | eprintln!("Tried to open {}.", expected_filename);
75 | return Err(e);
76 | }
77 | }
78 | };
79 |
80 | let expected_len = metadata.len() as usize;
81 | let mut result = Cursor::new(Vec::with_capacity(expected_len));
82 | collapse(&mut result)?;
83 | let expected = BufReader::new(File::open(expected_filename)?);
84 | // write out the expected result to /tmp for easy restoration
85 | result.set_position(0);
86 | let rand: u64 = rand::random();
87 | let tm = std::env::temp_dir().join(format!("test-{}.folded", rand));
88 | if fs::write(&tm, result.get_ref()).is_ok() {
89 | eprintln!("test output in {}", tm.display());
90 | }
91 | // and then compare
92 | if let Err(e) = std::panic::catch_unwind(|| {
93 | compare_results(result.clone(), expected, expected_filename, strip_quotes)
94 | }) {
95 | if std::env::var("INFERNO_BLESS_TESTS").is_ok() {
96 | fs::write(expected_filename, result.get_ref()).unwrap();
97 | } else {
98 | std::panic::resume_unwind(e);
99 | }
100 | }
101 | Ok(())
102 | }
103 |
104 | pub fn test_collapse_logs(mut collapser: C, input_file: &str, asserter: F)
105 | where
106 | C: Collapse,
107 | F: Fn(&Vec),
108 | {
109 | testing_logger::setup();
110 | let r = BufReader::new(File::open(input_file).unwrap());
111 | collapser.collapse(r, std::io::sink()).unwrap();
112 | testing_logger::validate(asserter);
113 | }
114 |
115 | pub fn test_collapse_error(mut collapser: C, test_filename: &str) -> io::Error
116 | where
117 | C: Collapse,
118 | {
119 | if fs::metadata(test_filename).is_err() {
120 | panic!("Failed to open input file '{}'", test_filename);
121 | }
122 |
123 | let mut collapse = move |out: &mut dyn io::Write| {
124 | if test_filename.ends_with(".gz") {
125 | let test_file = File::open(test_filename)?;
126 | let r = BufReader::new(Decoder::new(test_file).unwrap());
127 | collapser.collapse(r, out)
128 | } else {
129 | collapser.collapse_file(Some(test_filename), out)
130 | }
131 | };
132 |
133 | collapse(&mut io::sink()).expect_err("Expected an error")
134 | }
135 |
--------------------------------------------------------------------------------
/tests/common/mod.rs:
--------------------------------------------------------------------------------
1 | #![allow(dead_code)]
2 | #![allow(unused_imports)]
3 |
4 | mod collapse;
5 |
6 | pub use self::collapse::{compare_results, test_collapse, test_collapse_error, test_collapse_logs};
7 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/flamegraph-bug.txt:
--------------------------------------------------------------------------------
1 | CPU ID FUNCTION:NAME
2 | 0 64091 :tick-60s
3 |
4 |
5 | genunix`segvn_fault
6 | unix`pagefault+0x96
7 | unix`trap+0x2c7
8 | unix`0xfffffffffb8001d6
9 | 1
10 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/hex-addresses.txt:
--------------------------------------------------------------------------------
1 | CPU ID FUNCTION:NAME
2 | 8 35077 :tick-60s
3 |
4 | 0x104d08831
5 | 0x104cecffd
6 | 0x104cecffd
7 | 0x104cecffd
8 | 0x104ce54e7
9 | libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*)+0x6ae
10 | libjvm.dylib`JavaCalls::call_virtual(JavaValue*, KlassHandle, Symbol*, Symbol*, JavaCallArguments*, Thread*)+0x164
11 | libjvm.dylib`JavaCalls::call_virtual(JavaValue*, Handle, KlassHandle, Symbol*, Symbol*, Thread*)+0x4a
12 | libjvm.dylib`thread_entry(JavaThread*, Thread*)+0x7c
13 | libjvm.dylib`JavaThread::thread_main_inner()+0x9b
14 | libjvm.dylib`JavaThread::run()+0x1c0
15 | libjvm.dylib`java_start(Thread*)+0xf6
16 | libsystem_pthread.dylib`_pthread_body+0x7e
17 | libsystem_pthread.dylib`_pthread_start+0x46
18 | libsystem_pthread.dylib`thread_start+0xd
19 | 1
20 |
21 | libjvm.dylib`Node::replace_edge(Node*, Node*)+0x4f
22 | libjvm.dylib`PhaseIterGVN::remove_globally_dead_node(Node*)+0x109
23 | libjvm.dylib`PhaseIterGVN::subsume_node(Node*, Node*)+0x199
24 | libjvm.dylib`RegionNode::Ideal(PhaseGVN*, bool)+0x5b3
25 | libjvm.dylib`PhaseIterGVN::transform_old(Node*)+0x3a
26 | libjvm.dylib`PhaseIterGVN::optimize()+0x35
27 | libjvm.dylib`PhaseIdealLoop::build_and_optimize(bool, bool)+0x988
28 | libjvm.dylib`Compile::Optimize()+0x6a5
29 | libjvm.dylib`Compile::Compile(ciEnv*, C2Compiler*, ciMethod*, int, bool, bool, bool)+0x8e1
30 | libjvm.dylib`C2Compiler::compile_method(ciEnv*, ciMethod*, int)+0xb2
31 | libjvm.dylib`CompileBroker::invoke_compiler_on_method(CompileTask*)+0x5b2
32 | libjvm.dylib`CompileBroker::compiler_thread_loop()+0x291
33 | libjvm.dylib`JavaThread::thread_main_inner()+0x9b
34 | libjvm.dylib`JavaThread::run()+0x1c0
35 | libjvm.dylib`java_start(Thread*)+0xf6
36 | libsystem_pthread.dylib`_pthread_body+0x7e
37 | libsystem_pthread.dylib`_pthread_start+0x46
38 | libsystem_pthread.dylib`thread_start+0xd
39 | 1
40 |
41 | libsystem_kernel.dylib`read+0xa
42 | libzip.dylib`ZIP_Read+0xd3
43 | libzip.dylib`Java_java_util_zip_ZipFile_read+0x60
44 | 0x104e7945e
45 | 0x105048088
46 | 0x5a3ef800758e
47 | 2
48 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/java.txt:
--------------------------------------------------------------------------------
1 | header
2 | header2
3 |
4 |
5 | test`baz
6 | test`foo->bar
7 | test`main
8 | 1
9 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/only-header-lines.txt:
--------------------------------------------------------------------------------
1 | CPU ID FUNCTION:NAME
2 | 8 35077 :tick-60s
3 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/results/flamegraph-bug.txt:
--------------------------------------------------------------------------------
1 | unix`0xfffffffffb8001d6;unix`trap+0x2c7;unix`pagefault+0x96;genunix`segvn_fault 1
2 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/results/hex-addresses.txt:
--------------------------------------------------------------------------------
1 | 0x5a3ef800758e;0x105048088;0x104e7945e;libzip.dylib`Java_java_util_zip_ZipFile_read;libzip.dylib`ZIP_Read;libsystem_kernel.dylib`read 2
2 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;libjvm.dylib`java_start(Thread*);libjvm.dylib`JavaThread::run;libjvm.dylib`JavaThread::thread_main_inner;libjvm.dylib`CompileBroker::compiler_thread_loop;libjvm.dylib`CompileBroker::invoke_compiler_on_method;libjvm.dylib`C2Compiler::compile_method;libjvm.dylib`Compile::Compile;libjvm.dylib`Compile::Optimize;libjvm.dylib`PhaseIdealLoop::build_and_optimize;libjvm.dylib`PhaseIterGVN::optimize;libjvm.dylib`PhaseIterGVN::transform_old;libjvm.dylib`RegionNode::Ideal;libjvm.dylib`PhaseIterGVN::subsume_node;libjvm.dylib`PhaseIterGVN::remove_globally_dead_node;libjvm.dylib`Node::replace_edge 1
3 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;libjvm.dylib`java_start(Thread*);libjvm.dylib`JavaThread::run;libjvm.dylib`JavaThread::thread_main_inner;libjvm.dylib`thread_entry(JavaThread*, Thread*);libjvm.dylib`JavaCalls::call_virtual;libjvm.dylib`JavaCalls::call_virtual;libjvm.dylib`JavaCalls::call_helper;0x104ce54e7;0x104cecffd;0x104cecffd;0x104cecffd;0x104d08831 1
4 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/results/java.txt:
--------------------------------------------------------------------------------
1 | test`main;test`foo;bar_[i];test`baz 1
2 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/results/rust-names.txt:
--------------------------------------------------------------------------------
1 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;rg`std::sys::unix::thread::Thread::new::thread_start;rg`std::sys_common::thread::start_thread;rg`>::call_box;rg`__rust_maybe_catch_panic;rg`std::panicking::try::do_call;rg`std::sys_common::backtrace::__rust_begin_short_backtrace;rg`ignore::walk::Worker::run;rg` as core::convert::From<&'a [T]>>::from 1
2 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;rg`std::sys::unix::thread::Thread::new::thread_start;rg`std::sys_common::thread::start_thread;rg`>::call_box;rg`__rust_maybe_catch_panic;rg`std::panicking::try::do_call;rg`std::sys_common::backtrace::__rust_begin_short_backtrace;rg`ignore::walk::Worker::run;rg`::next;libsystem_platform.dylib`_platform_memset$VARIANT$Haswell 1
3 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;rg`std::sys::unix::thread::Thread::new::thread_start;rg`std::sys_common::thread::start_thread;rg`>::call_box;rg`__rust_maybe_catch_panic;rg`std::panicking::try::do_call;rg`std::sys_common::backtrace::__rust_begin_short_backtrace;rg`ignore::walk::Worker::run;rg`ignore::dir::Ignore::add_child_path;rg`ignore::gitignore::GitignoreBuilder::add;rg`std::path::Path::to_path_buf;rg` as core::convert::From<&'a [T]>>::from;libsystem_malloc.dylib`malloc;libsystem_malloc.dylib`malloc_zone_malloc 1
4 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;rg`std::sys::unix::thread::Thread::new::thread_start;rg`std::sys_common::thread::start_thread;rg`>::call_box;rg`__rust_maybe_catch_panic;rg`std::panicking::try::do_call;rg`std::sys_common::backtrace::__rust_begin_short_backtrace;rg`ignore::walk::Worker::run;rg`rg::search_parallel::_{{closure}}::_{{closure}};rg`>::search_impl;rg`grep_searcher::searcher::Searcher::search_path;rg`>::run;rg`>::fill;rg` as std::io::Read>::read;rg`encoding_rs_io::util::PossibleBom::as_slice 1
5 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;rg`std::sys::unix::thread::Thread::new::thread_start;rg`std::sys_common::thread::start_thread;rg`>::call_box;rg`__rust_maybe_catch_panic;rg`std::panicking::try::do_call;rg`std::sys_common::backtrace::__rust_begin_short_backtrace;rg`ignore::walk::Worker::run;rg`rg::search_parallel::_{{closure}}::_{{closure}};rg`>::search_impl;rg`grep_searcher::searcher::Searcher::search_path;rg`std::fs::OpenOptions::_open;rg`std::sys::unix::fs::File::open;rg`>::reserve_internal 1
6 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;rg`std::sys::unix::thread::Thread::new::thread_start;rg`std::sys_common::thread::start_thread;rg`>::call_box;rg`__rust_maybe_catch_panic;rg`std::panicking::try::do_call;rg`std::sys_common::backtrace::__rust_begin_short_backtrace;rg`ignore::walk::Worker::run;rg`rg::search_parallel::_{{closure}}::_{{closure}};rg`rg::subject::SubjectBuilder::build_from_result;rg`ignore::walk::DirEntry::is_stdin 1
7 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/results/scope_with_no_argument_list.txt:
--------------------------------------------------------------------------------
1 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;libjvm.dylib`java_start(Thread*);libjvm.dylib`JavaThread::run;libjvm.dylib`JavaThread::thread_main_inner;libjvm.dylib`CompileBroker::compiler_thread_loop;libjvm.dylib`CompileBroker::invoke_compiler_on_method;libjvm.dylib`C2Compiler::compile_method;libjvm.dylib`Compile::Compile;libjvm.dylib`Compile::Optimize;libjvm.dylib`PhaseIdealLoop::build_and_optimize;libjvm.dylib`PhaseIterGVN::optimize;libjvm.dylib`PhaseIterGVN::transform_old;libjvm.dylib`RegionNode::Ideal;libjvm.dylib`PhaseIterGVN::subsume_node;libjvm.dylib`PhaseIterGVN::remove_globally_dead_node;libjvm.dylib`Node::replace_edge 1
2 | libsystem_pthread.dylib`thread_start;libsystem_pthread.dylib`_pthread_start;libsystem_pthread.dylib`_pthread_body;libjvm.dylib`java_start(Thread*);libjvm.dylib`JavaThread::run;libjvm.dylib`JavaThread::thread_main_inner;libjvm.dylib`thread_entry(JavaThread*, Thread*);libjvm.dylib`JavaCalls::call_virtual;libjvm.dylib`JavaCalls::call_virtual;libjvm.dylib`JavaCalls::call_helper 1
3 | libzip.dylib`Java_java_util_zip_ZipFile_read;libzip.dylib`ZIP_Read;libsystem_kernel.dylib`read 2
4 |
--------------------------------------------------------------------------------
/tests/data/collapse-dtrace/results/stack-ustack.txt:
--------------------------------------------------------------------------------
1 | libc.so.1`_lwp_start;libc.so.1`_thrp_setup;cru-ds-fdsync-v1`std::sys::unix::thread::Thread::new::thread_start;cru-ds-fdsync-v1`core::ops::function::FnOnce::call_once{{vtable.shim}};cru-ds-fdsync-v1`std::sys_common::backtrace::__rust_begin_short_backtrace;cru-ds-fdsync-v1`rayon_core::registry::ThreadBuilder::run;cru-ds-fdsync-v1`rayon_core::registry::WorkerThread::wait_until_cold;cru-ds-fdsync-v1` as rayon_core::job::Job>::execute;cru-ds-fdsync-v1`std::panicking::try;cru-ds-fdsync-v1`crucible_downstairs::extent::Extent::flush;cru-ds-fdsync-v1`::flush;cru-ds-fdsync-v1`std::fs::File::sync_all;libc.so.1`__fdsync;unix`sys_syscall;genunix`fdsync;genunix`fop_fsync;zfs`zfs_fsync;zfs`zil_commit;zfs`zil_commit_impl;zfs`zil_commit_itx_assign;zfs`zil_itx_assign;zfs`dmu_objset_ds 1
2 | libc.so.1`_lwp_start;libc.so.1`_thrp_setup;cru-ds-fdsync-v1`std::sys::unix::thread::Thread::new::thread_start;cru-ds-fdsync-v1`core::ops::function::FnOnce::call_once{{vtable.shim}};cru-ds-fdsync-v1`std::sys_common::backtrace::__rust_begin_short_backtrace;cru-ds-fdsync-v1`tokio::runtime::task::harness::Harness;cru-ds-fdsync-v1`tokio::runtime::task::core::Core;cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::run;cru-ds-fdsync-v1`tokio::runtime::context::runtime::enter_runtime;cru-ds-fdsync-v1`tokio::runtime::context::scoped::Scoped;cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::Context::run;cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::Context::run_task;cru-ds-fdsync-v1`tokio::runtime::task::harness::Harness;cru-ds-fdsync-v1`tokio::runtime::task::core::Core;cru-ds-fdsync-v1`crucible_downstairs::Downstairs::run::_{{closure}};cru-ds-fdsync-v1`crucible_downstairs::ActiveConnection::do_work_if_ready::{{closure}};cru-ds-fdsync-v1`crucible_downstairs::ActiveConnection::do_work::{{closure}};cru-ds-fdsync-v1`crucible_downstairs::region::Region::region_write;cru-ds-fdsync-v1`crucible_downstairs::extent::Extent::write;cru-ds-fdsync-v1`::write;libc.so.1`__pwrite;unix`sys_syscall;genunix`pwrite;genunix`fop_write;zfs`zfs_write;zfs`dmu_tx_assign;zfs`dmu_tx_try_assign;zfs`dsl_dir_tempreserve_space;zfs`arc_memory_throttle 1
3 | libc.so.1`_lwp_start;libc.so.1`_thrp_setup;cru-ds-fdsync-v1`std::sys::unix::thread::Thread::new::thread_start;cru-ds-fdsync-v1`core::ops::function::FnOnce::call_once{{vtable.shim}};cru-ds-fdsync-v1`std::sys_common::backtrace::__rust_begin_short_backtrace;cru-ds-fdsync-v1`tokio::runtime::task::harness::Harness;cru-ds-fdsync-v1`tokio::runtime::task::core::Core;cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::run;cru-ds-fdsync-v1`tokio::runtime::context::runtime::enter_runtime;cru-ds-fdsync-v1`tokio::runtime::context::scoped::Scoped;cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::Context::run;cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::Context::run_task;cru-ds-fdsync-v1`tokio::runtime::task::harness::Harness;cru-ds-fdsync-v1`tokio::runtime::task::core::Core;cru-ds-fdsync-v1`crucible_downstairs::recv_task::_{{closure}};cru-ds-fdsync-v1` as futures_core::stream::Stream>::poll_next::h375c4bf72398a9c9+0x451
7 | cru-ds-fdsync-v1` as core::future::future::Future>::poll::hdb622d175ae42c67+0x376
8 | cru-ds-fdsync-v1`crucible_downstairs::recv_task::_$u7b$$u7b$closure$u7d$$u7d$::h2313d0ca35c97b46 (.llvm.9599067906520872268)+0x1e8
9 | cru-ds-fdsync-v1`tokio::runtime::task::core::Core::poll::ha1b200ead37ecb81+0x3e
10 | cru-ds-fdsync-v1`tokio::runtime::task::harness::Harness::poll::h6096748dfbf63e3f+0x47
11 | cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::Context::run_task::hbc7adf21738f2cc8+0x146
12 | cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::Context::run::h8894624b64f9ebd1+0xabe
13 | cru-ds-fdsync-v1`tokio::runtime::context::scoped::Scoped::set::h7f53e80a35be279f+0x2b
14 | cru-ds-fdsync-v1`tokio::runtime::context::runtime::enter_runtime::ha36cde2fe36fc9dc+0x172
15 | cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::run::heea3712ec5628e2e+0x4b
16 | cru-ds-fdsync-v1`tokio::runtime::task::core::Core::poll::h4fdbe1f8b2e046e9+0x43
17 | cru-ds-fdsync-v1`tokio::runtime::task::harness::Harness::poll::hdaaa15b8bfc6c3b5+0x45
18 | cru-ds-fdsync-v1`std::sys_common::backtrace::__rust_begin_short_backtrace::h07e5ebb552c48fa6+0x1b6
19 | cru-ds-fdsync-v1`core::ops::function::FnOnce::call_once{{vtable.shim}}::hfb58463ecc052a89+0x75
20 | cru-ds-fdsync-v1`std::sys::unix::thread::Thread::new::thread_start::h1783cbcbbf061711+0x29
21 | libc.so.1`_thrp_setup+0x77
22 | libc.so.1`_lwp_start
23 | 1
24 |
25 | zfs`arc_memory_throttle+0x1
26 | zfs`dsl_dir_tempreserve_space+0x9e
27 | zfs`dmu_tx_try_assign+0x149
28 | zfs`dmu_tx_assign+0x56
29 | zfs`zfs_write+0x475
30 | genunix`fop_write+0x5d
31 | genunix`pwrite+0x172
32 | unix`sys_syscall+0x17d
33 |
34 | libc.so.1`__pwrite+0xa
35 | cru-ds-fdsync-v1`::write::hef63fa757835e3ff+0x1621
36 | cru-ds-fdsync-v1`crucible_downstairs::extent::Extent::write::hfeced6743c01c23b+0x2fd
37 | cru-ds-fdsync-v1`crucible_downstairs::region::Region::region_write::hfbbb7f74fb6b1568+0x654
38 | cru-ds-fdsync-v1`crucible_downstairs::ActiveConnection::do_work::{{closure}}::h50e10780011359fc+0x1128
39 | cru-ds-fdsync-v1`crucible_downstairs::ActiveConnection::do_work_if_ready::{{closure}}::h65a7bded82d12d6c+0x148
40 | cru-ds-fdsync-v1`crucible_downstairs::Downstairs::run::_$u7b$$u7b$closure$u7d$$u7d$::h7a3087a6f836e6c7 (.llvm.14070482526595365531)+0x2012
41 | cru-ds-fdsync-v1`tokio::runtime::task::core::Core::poll::hf3cf7a78e14ca649+0x47
42 | cru-ds-fdsync-v1`tokio::runtime::task::harness::Harness::poll::h2d72b7b7afc40df2+0x49
43 | cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::Context::run_task::hbc7adf21738f2cc8+0x190
44 | cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::Context::run::h8894624b64f9ebd1+0xabe
45 | cru-ds-fdsync-v1`tokio::runtime::context::scoped::Scoped::set::h7f53e80a35be279f+0x2b
46 | cru-ds-fdsync-v1`tokio::runtime::context::runtime::enter_runtime::ha36cde2fe36fc9dc+0x172
47 | cru-ds-fdsync-v1`tokio::runtime::scheduler::multi_thread::worker::run::heea3712ec5628e2e+0x4b
48 | cru-ds-fdsync-v1`tokio::runtime::task::core::Core::poll::h4fdbe1f8b2e046e9+0x43
49 | cru-ds-fdsync-v1`tokio::runtime::task::harness::Harness::poll::hdaaa15b8bfc6c3b5+0x45
50 | cru-ds-fdsync-v1`std::sys_common::backtrace::__rust_begin_short_backtrace::h07e5ebb552c48fa6+0x1b6
51 | cru-ds-fdsync-v1`core::ops::function::FnOnce::call_once{{vtable.shim}}::hfb58463ecc052a89+0x75
52 | cru-ds-fdsync-v1`std::sys::unix::thread::Thread::new::thread_start::h1783cbcbbf061711+0x29
53 | libc.so.1`_thrp_setup+0x77
54 | libc.so.1`_lwp_start
55 | 1
56 |
57 | zfs`metaslab_group_alloc_verify+0x1
58 | zfs`zio_execute+0xa7
59 | genunix`taskq_thread+0x2a6
60 | unix`thread_start+0xb
61 |
62 | 1
63 |
64 | zfs`dmu_objset_ds+0x1
65 | zfs`zil_itx_assign+0x194
66 | zfs`zil_commit_itx_assign+0x65
67 | zfs`zil_commit_impl+0x26
68 | zfs`zil_commit+0x4b
69 | zfs`zfs_fsync+0xf6
70 | genunix`fop_fsync+0x4a
71 | genunix`fdsync+0xc4
72 | unix`sys_syscall+0x17d
73 |
74 | libc.so.1`__fdsync+0xa
75 | cru-ds-fdsync-v1`std::fs::File::sync_all::hcd4d0768a77cbc2e+0x14
76 | cru-ds-fdsync-v1`::flush::h68fcf1774758d74e+0x9c
77 | cru-ds-fdsync-v1`crucible_downstairs::extent::Extent::flush::h0eac5b95dfa4f5f0+0x472
78 | cru-ds-fdsync-v1`std::panicking::try::h7ba6611983f64757+0x4c
79 | cru-ds-fdsync-v1`_$LT$rayon_core..job..HeapJob$LT$BODY$GT$$u20$as$u20$rayon_core..job..Job$GT$::execute::h60b9d586fc4f8a0f (.llvm.8052073739315931670)+0x46
80 | cru-ds-fdsync-v1`rayon_core::registry::WorkerThread::wait_until_cold::haa78671c0e7aa9b1+0x50f
81 | cru-ds-fdsync-v1`rayon_core::registry::ThreadBuilder::run::hf28d413d115bded0+0x398
82 | cru-ds-fdsync-v1`std::sys_common::backtrace::__rust_begin_short_backtrace::hfcd6324a3e87fc1e+0x48
83 | cru-ds-fdsync-v1`core::ops::function::FnOnce::call_once{{vtable.shim}}::hbfa4fc2e086997af+0xb2
84 | cru-ds-fdsync-v1`std::sys::unix::thread::Thread::new::thread_start::h1783cbcbbf061711+0x29
85 | libc.so.1`_thrp_setup+0x77
86 | libc.so.1`_lwp_start
87 | 1
88 |
--------------------------------------------------------------------------------
/tests/data/collapse-ghcprof/results/utf8.txt:
--------------------------------------------------------------------------------
1 | MAIN.MAIN 26
2 | MAIN.MAIN;GHC.Conc.Signal.CAF 0
3 | MAIN.MAIN;GHC.Event.Thread.CAF 0
4 | MAIN.MAIN;GHC.IO.Encoding.CAF 0
5 | MAIN.MAIN;GHC.IO.Encoding.Iconv.CAF 0
6 | MAIN.MAIN;GHC.IO.Handle.FD.CAF 0
7 | MAIN.MAIN;Lib.CAF:f_rPV 0
8 | MAIN.MAIN;Lib.CAF:一些函数1 0
9 | MAIN.MAIN;Lib.CAF:一些函数1;Lib.一二三 0
10 | MAIN.MAIN;Lib.CAF:一些函数1;Lib.一些函数 0
11 | MAIN.MAIN;Lib.CAF:一些函数1;Lib.你好世界 0
12 | MAIN.MAIN;Lib.你好世界 974
13 | MAIN.MAIN;Main.CAF:main1 0
14 | MAIN.MAIN;Main.CAF:main1;Main.main 0
15 |
--------------------------------------------------------------------------------
/tests/data/collapse-ghcprof/results/utf8_bytes.txt:
--------------------------------------------------------------------------------
1 | MAIN.MAIN 456096
2 | MAIN.MAIN;GHC.Conc.Signal.CAF 640
3 | MAIN.MAIN;GHC.Event.Thread.CAF 1528
4 | MAIN.MAIN;GHC.IO.Encoding.CAF 2448
5 | MAIN.MAIN;GHC.IO.Encoding.Iconv.CAF 200
6 | MAIN.MAIN;GHC.IO.Handle.FD.CAF 34736
7 | MAIN.MAIN;Lib.CAF:f_rPV 256
8 | MAIN.MAIN;Lib.CAF:一些函数1 16
9 | MAIN.MAIN;Lib.CAF:一些函数1;Lib.一二三 0
10 | MAIN.MAIN;Lib.CAF:一些函数1;Lib.一些函数 0
11 | MAIN.MAIN;Lib.CAF:一些函数1;Lib.你好世界 0
12 | MAIN.MAIN;Lib.你好世界 90486357376
13 | MAIN.MAIN;Main.CAF:main1 16
14 | MAIN.MAIN;Main.CAF:main1;Main.main 0
15 |
--------------------------------------------------------------------------------
/tests/data/collapse-ghcprof/results/utf8_ticks.txt:
--------------------------------------------------------------------------------
1 | MAIN.MAIN 510
2 | MAIN.MAIN;GHC.Conc.Signal.CAF 0
3 | MAIN.MAIN;GHC.Event.Thread.CAF 0
4 | MAIN.MAIN;GHC.IO.Encoding.CAF 0
5 | MAIN.MAIN;GHC.IO.Encoding.Iconv.CAF 0
6 | MAIN.MAIN;GHC.IO.Handle.FD.CAF 0
7 | MAIN.MAIN;Lib.CAF:f_rPV 0
8 | MAIN.MAIN;Lib.CAF:一些函数1 0
9 | MAIN.MAIN;Lib.CAF:一些函数1;Lib.一二三 0
10 | MAIN.MAIN;Lib.CAF:一些函数1;Lib.一些函数 0
11 | MAIN.MAIN;Lib.CAF:一些函数1;Lib.你好世界 0
12 | MAIN.MAIN;Lib.你好世界 19317
13 | MAIN.MAIN;Main.CAF:main1 0
14 | MAIN.MAIN;Main.CAF:main1;Main.main 0
15 |
--------------------------------------------------------------------------------
/tests/data/collapse-ghcprof/utf8.prof:
--------------------------------------------------------------------------------
1 | Sun Aug 13 10:47 2023 Time and Allocation Profiling Report (Final)
2 |
3 | utf8test-exe +RTS -N -P -RTS
4 |
5 | total time = 10.25 secs (19827 ticks @ 1000 us, 32 processors)
6 | total alloc = 90,486,853,312 bytes (excludes profiling overheads)
7 |
8 | COST CENTRE MODULE SRC %time %alloc ticks bytes
9 |
10 | 你好世界 Lib src/Lib.hs:(14,1)-(15,41) 97.4 100.0 19317 90486357376
11 | MAIN MAIN 2.6 0.0 510 456096
12 |
13 |
14 | individual inherited
15 | COST CENTRE MODULE SRC no. entries %time %alloc %time %alloc ticks bytes
16 |
17 | MAIN MAIN 168 0 2.6 0.0 100.0 100.0 510 456096
18 | CAF GHC.Conc.Signal 289 0 0.0 0.0 0.0 0.0 0 640
19 | CAF GHC.IO.Encoding 279 0 0.0 0.0 0.0 0.0 0 2448
20 | CAF GHC.IO.Encoding.Iconv 277 0 0.0 0.0 0.0 0.0 0 200
21 | CAF GHC.IO.Handle.FD 269 0 0.0 0.0 0.0 0.0 0 34736
22 | CAF GHC.Event.Thread 228 0 0.0 0.0 0.0 0.0 0 1528
23 | CAF:f_rPV Lib 295 0 0.0 0.0 0.0 0.0 0 256
24 | CAF:main1 Main 334 0 0.0 0.0 0.0 0.0 0 16
25 | main Main app/Main.hs:6:1-11 336 1 0.0 0.0 0.0 0.0 0 0
26 | CAF:一些函数1 Lib 296 0 0.0 0.0 0.0 0.0 0 16
27 | 一二三 Lib src/Lib.hs:11:1-10 338 1 0.0 0.0 0.0 0.0 0 0
28 | 一些函数 Lib src/Lib.hs:8:1-10 337 1 0.0 0.0 0.0 0.0 0 0
29 | 你好世界 Lib src/Lib.hs:(14,1)-(15,41) 339 1 0.0 0.0 0.0 0.0 0 0
30 | 你好世界 Lib src/Lib.hs:(14,1)-(15,41) 340 0 97.4 100.0 97.4 100.0 19317 90486357376
31 |
--------------------------------------------------------------------------------
/tests/data/collapse-guess/invalid-perf-with-empty-line-after-event-line.txt:
--------------------------------------------------------------------------------
1 | java 10488 9962.502413: 10101010 cpu-clock:
2 |
3 | ffffffffaee8017b fput+0xb ([kernel.kallsyms])
4 | ffffffffaee7f61c ksys_write+0x9c ([kernel.kallsyms])
5 | ffffffffaec041cb do_syscall_64+0x5b ([kernel.kallsyms])
6 | ffffffffaf60008c entry_SYSCALL_64_after_hwframe+0x44 ([kernel.kallsyms])
7 | 7f89e341d84f __GI___libc_write+0x4f (/usr/lib/libc-2.28.so)
8 | 5966605dd52f8e00 [unknown] ([unknown])
9 |
--------------------------------------------------------------------------------
/tests/data/collapse-guess/unknown-format.txt:
--------------------------------------------------------------------------------
1 |
2 | this
3 | is an unknown
4 | format
5 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/empty-line.txt:
--------------------------------------------------------------------------------
1 | inline-counter 26037 8801.193547: 250000 cpu-clock:uhH:
2 | 401b97 main+0x1f (./tests/data/inline-counter/inline-counter)
3 |
4 | inline-counter 26037 8801.194312: 250000 cpu-clock:uhH:
5 |
6 | 401b94 main+0x1c (./tests/data/inline-counter/inline-counter)
7 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/no-events.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonhoo/inferno/5ee7d6bb68ac9627010ef468c81f4f264cd0d399/tests/data/collapse-perf/no-events.txt
--------------------------------------------------------------------------------
/tests/data/collapse-perf/results/cpp-stacks-std-function-collapsed.txt:
--------------------------------------------------------------------------------
1 | perf_stacks;[unknown];std::ostream::sentry::sentry 4614996
2 | perf_stacks;_dl_start;[[kernel.kallsyms]] 438507
3 | perf_stacks;_start;[[kernel.kallsyms]] 29005
4 | perf_stacks;_start;__libc_start_main;__libc_csu_init;_GLOBAL__sub_I_main;__static_initialization_and_destruction_0;std::ios_base::Init::Init;std::locale::locale;[libstdc++.so.6.0.25];std::locale::_Impl::_Impl;std::__timepunct::__timepunct;std::__timepunct::_M_initialize_timepunct 3946818
5 | perf_stacks;_start;__libc_start_main;main;std::endl >;std::ostream::put;_IO_new_file_overflow;_IO_new_do_write;new_do_write;_IO_new_file_write;__GI___libc_write;[[kernel.kallsyms]] 62360120
6 | perf_stacks;_start;__libc_start_main;main;std::function::operator;std::_Function_handler::_M_invoke 3306084
7 | perf_stacks;_start;__libc_start_main;main;std::ostream::flush 2947000
8 | perf_stacks;_start;_dl_start;_dl_start_final;_dl_sysdep_start;dl_main;_dl_map_object_deps;_dl_catch_exception;openaux;_dl_map_object;_dl_map_object_from_fd;_dl_map_segments;__mmap64;[[kernel.kallsyms]] 2925420
9 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/results/go-stacks-collapsed.txt:
--------------------------------------------------------------------------------
1 | go;[unknown];[unknown];runtime.main;main.main;cmd/go/internal/run.runRun;cmd/go/internal/load.PackagesAndErrors;cmd/go/internal/load.loadPackage;cmd/go/internal/load.LoadImport;cmd/go/internal/load.(*Package).load;cmd/go/internal/load.LoadImport;cmd/go/internal/load.(*Package).load;cmd/go/internal/load.LoadImport;cmd/go/internal/load.(*Package).load;cmd/go/internal/load.LoadImport;cmd/go/internal/load.(*Package).load;cmd/go/internal/load.LoadImport;go/build.(*Context).Import;go/build.(*Context).matchFile;go/build.readImports;go/build.(*importReader).readKeyword;go/build.(*importReader).peekByte;go/build.(*importReader).readByte 250000
2 | go;[unknown];[unknown];runtime.main;main.main;cmd/go/internal/run.runRun;cmd/go/internal/load.PackagesAndErrors;cmd/go/internal/load.loadPackage;cmd/go/internal/load.LoadImport;cmd/go/internal/load.(*Package).load;cmd/go/internal/load.LoadImport;cmd/go/internal/load.(*Package).load;cmd/go/internal/load.LoadImport;cmd/go/internal/load.(*Package).load;cmd/go/internal/load.LoadImport;cmd/go/internal/load.(*Package).load;cmd/go/internal/load.LoadImport;go/build.(*Context).Import;go/parser.ParseFile;go/parser.(*parser).parseFile;go/parser.(*parser).expectSemi;go/parser.(*parser).next;go/parser.(*parser).consumeComment 250000
3 | go;[unknown];x_cgo_notify_runtime_init_done;runtime.main;main.init;cmd/go/internal/base.init;cmd/go/internal/cfg.init;go/build.init;go/doc.init;text/template.init;text/template.init.ializers;text/template.createValueFuncs;text/template.addValueFuncs;runtime.mapassign_faststr 250000
4 | go;[unknown];x_cgo_notify_runtime_init_done;runtime.main;main.init;cmd/go/internal/bug.init;cmd/go/internal/envcmd.init;cmd/go/internal/modload.init;cmd/go/internal/modfetch.init;cmd/go/internal/get.init;cmd/go/internal/work.init;cmd/go/internal/work.init.ializers;regexp.MustCompile;regexp.compile;regexp/syntax.Compile;runtime.growslice 250000
5 | go;[unknown];x_cgo_notify_runtime_init_done;runtime.main;main.init;cmd/go/internal/bug.init;cmd/go/internal/envcmd.init;cmd/go/internal/modload.init;cmd/go/internal/modfetch.init;cmd/go/internal/get.init;cmd/go/internal/work.init;cmd/go/internal/work.init.ializers;regexp.MustCompile;regexp.compile;regexp/syntax.Parse;regexp/syntax.(*parser).literal;regexp/syntax.(*parser).push;regexp/syntax.(*parser).maybeConcat;runtime.growslice 250000
6 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/results/java-inline-collapsed.txt:
--------------------------------------------------------------------------------
1 | java;[unknown];__GI___libc_write 60606060
2 | java;[unknown];__GI___libc_write;entry_SYSCALL_64_after_hwframe;do_syscall_64 20202020
3 | java;[unknown];__GI___libc_write;entry_SYSCALL_64_after_hwframe;do_syscall_64;ksys_write;__fdget_pos;__fget_light 30303030
4 | java;[unknown];__GI___libc_write;entry_SYSCALL_64_after_hwframe;do_syscall_64;ksys_write;fput 10101010
5 | java;[unknown];__GI___libc_write;entry_SYSCALL_64_after_hwframe;do_syscall_64;ksys_write;vfs_write;__vfs_write;tty_write;n_tty_write 10101010
6 | java;[unknown];__GI___libc_write;entry_SYSCALL_64_after_hwframe;do_syscall_64;ksys_write;vfs_write;__vfs_write;tty_write;n_tty_write;_raw_spin_unlock_irqrestore 10101010
7 | java;[unknown];__GI___libc_write;entry_SYSCALL_64_after_hwframe;do_syscall_64;ksys_write;vfs_write;__vfs_write;tty_write;n_tty_write;pty_write;_raw_spin_unlock_irqrestore 20202020
8 | java;[unknown];__GI___libc_write;entry_SYSCALL_64_after_hwframe;do_syscall_64;ksys_write;vfs_write;__vfs_write;tty_write;tty_write_unlock 10101010
9 | java;start_thread;[libjli.so];[libjvm.so];[libjvm.so];[libjvm.so];call_stub;Interpreter;Interpreter;LCounter:::countTo;java/io/PrintStream:::println;java/io/PrintStream:::newLine_[i];java/io/OutputStreamWriter:::flushBuffer_[i];sun/nio/cs/StreamEncoder:::flushBuffer;sun/nio/cs/StreamEncoder:::implFlushBuffer_[i];sun/nio/cs/StreamEncoder:::writeBytes_[i];java/io/PrintStream:::write_[i];java/io/BufferedOutputStream:::flush_[i];java/io/BufferedOutputStream:::flushBuffer_[i];java/io/FileOutputStream:::write_[i] 10101010
10 | java;start_thread;[libjli.so];[libjvm.so];[libjvm.so];[libjvm.so];call_stub;Interpreter;Interpreter;LCounter:::countTo;java/io/PrintStream:::println;java/io/PrintStream:::newLine_[i];java/io/OutputStreamWriter:::flushBuffer_[i];sun/nio/cs/StreamEncoder:::flushBuffer;sun/nio/cs/StreamEncoder:::implFlushBuffer_[i];sun/nio/cs/StreamEncoder:::writeBytes_[i];java/io/PrintStream:::write_[i];java/io/BufferedOutputStream:::flush_[i];java/io/BufferedOutputStream:::flushBuffer_[i];java/io/FileOutputStream:::write_[i];java/io/FileOutputStream:::writeBytes;Java_java_io_FileOutputStream_writeBytes;[libjava.so];[libjvm.so];[libjvm.so] 10101010
11 | java;start_thread;[libjli.so];[libjvm.so];[libjvm.so];[libjvm.so];call_stub;Interpreter;Interpreter;LCounter:::countTo;java/io/PrintStream:::println;java/io/PrintStream:::print_[i];java/io/PrintStream:::write_[i];java/io/BufferedWriter:::flushBuffer;java/io/OutputStreamWriter:::write_[i];sun/nio/cs/StreamEncoder:::write_[i];sun/nio/cs/StreamEncoder:::implWrite_[i];sun/nio/cs/StreamEncoder:::implWrite_[i];java/nio/charset/CharsetEncoder:::encode_[i];sun/nio/cs/UTF_8$Encoder:::encodeLoop_[i] 10101010
12 | java;start_thread;[libjli.so];[libjvm.so];[libjvm.so];[libjvm.so];call_stub;Interpreter;Interpreter;LCounter:::countTo;java/io/PrintStream:::println;java/io/PrintStream:::print_[i];java/io/PrintStream:::write_[i];java/io/OutputStreamWriter:::flushBuffer_[i];sun/nio/cs/StreamEncoder:::flushBuffer;sun/nio/cs/StreamEncoder:::implFlushBuffer_[i];sun/nio/cs/StreamEncoder:::writeBytes_[i];java/io/PrintStream:::write_[i];java/io/BufferedOutputStream:::flush_[i] 10101010
13 | java;start_thread;[libjli.so];[libjvm.so];[libjvm.so];[libjvm.so];call_stub;Interpreter;Interpreter;LCounter:::countTo;java/io/PrintStream:::println;java/io/PrintStream:::print_[i];java/io/PrintStream:::write_[i];java/io/OutputStreamWriter:::flushBuffer_[i];sun/nio/cs/StreamEncoder:::flushBuffer;sun/nio/cs/StreamEncoder:::implFlushBuffer_[i];sun/nio/cs/StreamEncoder:::writeBytes_[i];java/io/PrintStream:::write_[i];java/io/BufferedOutputStream:::flush_[i];java/io/BufferedOutputStream:::flushBuffer_[i];java/io/FileOutputStream:::write_[i] 10101010
14 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/results/no-events-collapsed.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonhoo/inferno/5ee7d6bb68ac9627010ef468c81f4f264cd0d399/tests/data/collapse-perf/results/no-events-collapsed.txt
--------------------------------------------------------------------------------
/tests/data/collapse-perf/results/single-event-collapsed.txt:
--------------------------------------------------------------------------------
1 | boa_cli;[unknown];boa_cli::main;boa::realm::Realm::create;boa::realm::Realm::create_instrinsics;boa::builtins::console::create_constructor;boa::builtins::value::ValueData::set_field_slice;boa::builtins::value::ValueData::set_field;boa::builtins::object::internal_methods_trait::ObjectInternalMethods::set;::define_own_property;boa::builtins::value::to_value;::to_value;gc::Gc::new;gc::gc::GcBox::new;std::thread::local::LocalKey::with;std::thread::local::LocalKey::try_with;gc::gc::GcBox::new::_{{closure}};gc::gc::collect_garbage;gc::gc::collect_garbage::mark;gc::gc::GcBox::trace_inner; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark;::trace;::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark;::trace;::trace::mark; as gc::trace::Trace>::trace;gc::gc::GcBox::trace_inner;::trace;::trace::mark; as gc::trace::Trace>::trace;::trace;::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark;::trace;::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark; as gc::trace::Trace>::trace;gc::gc::GcBox::trace_inner;::trace;::trace::mark; as gc::trace::Trace>::trace;::trace;::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark;::trace;::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark; as gc::trace::Trace>::trace;gc::gc::GcBox::trace_inner;::trace;::trace::mark; as gc::trace::Trace>::trace;::trace;::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark;::trace;::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark; as gc::trace::Trace>::trace;gc::gc::GcBox::trace_inner;::trace;::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark; as gc::trace::Trace>::trace;::trace;::trace::mark;::trace;::trace::mark;::trace;::trace::mark; as gc::trace::Trace>::trace; as gc::trace::Trace>::trace::mark; as gc::trace::Trace>::trace 10101010
2 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/results/single-line-stacks-collapsed.txt:
--------------------------------------------------------------------------------
1 | false;[unknown] 1
2 | false;_dl_start 1
3 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/results/sourcepawn-jitdump-collapsed-jit.txt:
--------------------------------------------------------------------------------
1 | spshell;__libc_start_main;main;Execute;sp::ScriptedInvoker::Invoke;sp::PluginContext::Invoke;sp::Environment::Invoke;_[j];fib.smx::main_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j];fib.smx::fib_[j] 22145531
2 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/results/versioned-vmlinux-collapsed-kernel.txt:
--------------------------------------------------------------------------------
1 | swapper;[vmlinux-5.4.14-cloudflare-2020.1.11]_[k];start_secondary_[k];cpu_startup_entry_[k];do_idle_[k];cpuidle_enter_[k];cpuidle_enter_state_[k];common_interrupt_[k];do_IRQ_[k];irq_exit_[k];__softirqentry_text_start_[k];net_rx_action_[k];mlx5e_napi_poll_[k];mlx5e_poll_rx_cq_[k];mlx5e_handle_rx_cqe_[k];mlx5e_skb_from_cqe_linear_[k];mlx5e_xdp_handle_[k];bpf_prog_2b956549c660136a_uni_l4lb 20834821
2 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/single-line-stacks.txt:
--------------------------------------------------------------------------------
1 | false 39654 19115.489713: 1 cycles:u: ffffffff9b201293 [unknown] ([unknown])
2 | false 39654 19115.489719: 1 cycles: 7fa68b1f2d84 _dl_start+0x4 (/usr/lib/ld-2.31.so)
3 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/sourcepawn-jitdump.txt:
--------------------------------------------------------------------------------
1 | spshell 31714 451945.594655: 22145531 cycles:
2 | f719f4a4 fib.smx::fib+0x3c (/tmp/jitted-31714-4145673320.so)
3 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
4 | f719f50b fib.smx::fib+0xa3 (/tmp/jitted-31714-4145673320.so)
5 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
6 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
7 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
8 | f719f50b fib.smx::fib+0xa3 (/tmp/jitted-31714-4145673320.so)
9 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
10 | f719f50b fib.smx::fib+0xa3 (/tmp/jitted-31714-4145673320.so)
11 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
12 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
13 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
14 | f719f50b fib.smx::fib+0xa3 (/tmp/jitted-31714-4145673320.so)
15 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
16 | f719f50b fib.smx::fib+0xa3 (/tmp/jitted-31714-4145673320.so)
17 | f719f50b fib.smx::fib+0xa3 (/tmp/jitted-31714-4145673320.so)
18 | f719f50b fib.smx::fib+0xa3 (/tmp/jitted-31714-4145673320.so)
19 | f719f50b fib.smx::fib+0xa3 (/tmp/jitted-31714-4145673320.so)
20 | f719f50b fib.smx::fib+0xa3 (/tmp/jitted-31714-4145673320.so)
21 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
22 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
23 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
24 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
25 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
26 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
27 | f719f54c fib.smx::fib+0xe4 (/tmp/jitted-31714-4145673320.so)
28 | f719f119 fib.smx::main+0x91 (/tmp/jitted-31714-4145672328.so)
29 | f719f06f +0x27 (/tmp/jitted-31714-4145672264.so)
30 | 8059187 sp::Environment::Invoke+0x307 (/root/code/sourcepawn/build/vm/spshell/linux-x86/spshell)
31 | 806d5d8 sp::PluginContext::Invoke+0x378 (/root/code/sourcepawn/build/vm/spshell/linux-x86/spshell)
32 | 8078bcc sp::ScriptedInvoker::Invoke+0x60c (/root/code/sourcepawn/build/vm/spshell/linux-x86/spshell)
33 | 804b413 Execute+0x3d3 (/root/code/sourcepawn/build/vm/spshell/linux-x86/spshell)
34 | 804ae7e main+0x61e (/root/code/sourcepawn/build/vm/spshell/linux-x86/spshell)
35 | f7abc8e9 __libc_start_main+0xf9 (/usr/lib/libc-2.29.so)
36 |
37 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/versioned-vmlinux.txt:
--------------------------------------------------------------------------------
1 | swapper 0 [012] 2281339.604067: 20834821 cycles:
2 | ffffffffc09ace93 bpf_prog_2b956549c660136a_uni_l4lb+0xb80 (bpf_prog_2b956549c660136a_uni_l4lb)
3 | ffffffffc087cbc9 mlx5e_xdp_handle+0xa9 (/lib/modules/5.4.14-cloudflare-2020.1.11/kernel/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko)
4 | ffffffffc0878d87 mlx5e_skb_from_cqe_linear+0xc7 (/lib/modules/5.4.14-cloudflare-2020.1.11/kernel/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko)
5 | ffffffffc087a254 mlx5e_handle_rx_cqe+0x64 (/lib/modules/5.4.14-cloudflare-2020.1.11/kernel/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko)
6 | ffffffffc087bb48 mlx5e_poll_rx_cq+0x808 (/lib/modules/5.4.14-cloudflare-2020.1.11/kernel/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko)
7 | ffffffffc087beee mlx5e_napi_poll+0xde (/lib/modules/5.4.14-cloudflare-2020.1.11/kernel/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko)
8 | ffffffffb8f03eaa net_rx_action+0x13a (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
9 | ffffffffb94000e0 __softirqentry_text_start+0xe0 (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
10 | ffffffffb886c8c0 irq_exit+0xa0 (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
11 | ffffffffb9201908 do_IRQ+0x58 (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
12 | ffffffffb9200a0f common_interrupt+0xf (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
13 | ffffffffb8ebc022 cpuidle_enter_state+0xb2 (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
14 | ffffffffb8ebc3c9 cpuidle_enter+0x29 (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
15 | ffffffffb88960f8 do_idle+0x1b8 (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
16 | ffffffffb88962c9 cpu_startup_entry+0x19 (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
17 | ffffffffb8841383 start_secondary+0x143 (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
18 | ffffffffb88000d4 [unknown] (/usr/lib/debug/boot/vmlinux-5.4.14-cloudflare-2020.1.11)
19 |
--------------------------------------------------------------------------------
/tests/data/collapse-perf/weird-stack-line.txt:
--------------------------------------------------------------------------------
1 | inline-counter 26037 8801.193547: 250000 cpu-clock:uhH:
2 | 401b97 main+0x1f (./tests/data/inline-counter/inline-counter)
3 |
4 | inline-counter 26037 8801.194312: 250000 cpu-clock:uhH:
5 | THIS_IS_A_WEIRD_LINE
6 |
--------------------------------------------------------------------------------
/tests/data/collapse-recursive/basic.txt:
--------------------------------------------------------------------------------
1 | main;recursive;recursive;recursive;helper 1
2 | main;recursive;recursive;helper 2
3 | main;not;recursive 4
--------------------------------------------------------------------------------
/tests/data/collapse-recursive/results/basic-collapsed.txt:
--------------------------------------------------------------------------------
1 | main;not;recursive 4
2 | main;recursive;helper 3
--------------------------------------------------------------------------------
/tests/data/collapse-sample/bad-stack-line.txt:
--------------------------------------------------------------------------------
1 | Analysis of sampling rg (pid 64751) every 1 millisecond
2 | Process: rg [64751]
3 | Path: /usr/local/Cellar/ripgrep/11.0.1/bin/rg
4 | Load Address: 0x103746000
5 | Identifier: rg
6 | Version: 0
7 | Code Type: X86-64
8 | Parent Process: zsh [50523]
9 |
10 | Date/Time: 2019-07-04 10:21:28.347 -0600
11 | Launch Time: 2019-07-04 10:21:15.470 -0600
12 | OS Version: Mac OS X 10.14.5 (18F203)
13 | Report Version: 7
14 | Analysis Tool: /usr/bin/sample
15 |
16 | Physical footprint: 227.5M
17 | Physical footprint (peak): 227.5M
18 | ----
19 |
20 | Call graph:
21 | 825 Thread_15758523 DispatchQueue_1: com.apple.main-thread (serial)
22 | + BAD
23 | + 825 main (in rg) + 41 [0x10384b549]
24 | + 825 std::rt::lang_start_internal::hd2693a01169d6aa1 (in rg) + 334 [0x103a0db1e]
25 | + 825 __rust_maybe_catch_panic (in rg) + 31 [0x103a230cf]
26 | + 825 std::panicking::try::do_call::hab896c32750930ec (.llvm.7886897009887049720) (in rg) + 24 [0x103a22258]
27 | + 825 std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h7cd9ec399e9db3f7 (in rg) + 6 [0x10381bb66]
28 | + 825 rg::main::h6909bd3a32e27a08 (in rg) + 34 [0x1038445a2]
29 | + 825 rg::try_main::h1b50b8f6fd4186a2 (in rg) + 13818 [0x103847c3a]
30 | + 825 ignore::walk::WalkParallel::run::h9c94d86e305a5f70 (in rg) + 3616 [0x1037cb520]
31 | + 825 _$LT$std..thread..JoinHandle$LT$T$GT$$GT$::join::hca6aa63e512626da (in rg) + 72 [0x103837e88]
32 | + 825 std::sys::unix::thread::Thread::join::h9bc404ce70591d96 (in rg) + 16 [0x103a10800]
33 | + 825 _pthread_join (in libsystem_pthread.dylib) + 358 [0x7fff739c76de]
34 | + 825 __ulock_wait (in libsystem_kernel.dylib) + 10 [0x7fff739069de]
35 |
36 | Total number in stack (recursive counted multiple, when >=5):
37 | REMOVED EVERYTHING BELOW HERE BECAUSE IT'S NOT USED
38 |
--------------------------------------------------------------------------------
/tests/data/collapse-sample/end-before-call-graph-end.txt:
--------------------------------------------------------------------------------
1 | Analysis of sampling rg (pid 64751) every 1 millisecond
2 | Process: rg [64751]
3 | Path: /usr/local/Cellar/ripgrep/11.0.1/bin/rg
4 | Load Address: 0x103746000
5 | Identifier: rg
6 | Version: 0
7 | Code Type: X86-64
8 | Parent Process: zsh [50523]
9 |
10 | Date/Time: 2019-07-04 10:21:28.347 -0600
11 | Launch Time: 2019-07-04 10:21:15.470 -0600
12 | OS Version: Mac OS X 10.14.5 (18F203)
13 | Report Version: 7
14 | Analysis Tool: /usr/bin/sample
15 |
16 | Physical footprint: 227.5M
17 | Physical footprint (peak): 227.5M
18 | ----
19 |
20 | Call graph:
21 | 825 Thread_15758523 DispatchQueue_1: com.apple.main-thread (serial)
22 | + 825 start (in libdyld.dylib) + 1 [0x7fff737cf3d5]
23 | + 825 main (in rg) + 41 [0x10384b549]
24 | + 825 std::rt::lang_start_internal::hd2693a01169d6aa1 (in rg) + 334 [0x103a0db1e]
25 | + 825 __rust_maybe_catch_panic (in rg) + 31 [0x103a230cf]
26 | + 825 std::panicking::try::do_call::hab896c32750930ec (.llvm.7886897009887049720) (in rg) + 24 [0x103a22258]
27 | + 825 std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h7cd9ec399e9db3f7 (in rg) + 6 [0x10381bb66]
28 | + 825 rg::main::h6909bd3a32e27a08 (in rg) + 34 [0x1038445a2]
29 | + 825 rg::try_main::h1b50b8f6fd4186a2 (in rg) + 13818 [0x103847c3a]
30 | + 825 ignore::walk::WalkParallel::run::h9c94d86e305a5f70 (in rg) + 3616 [0x1037cb520]
31 | + 825 _$LT$std..thread..JoinHandle$LT$T$GT$$GT$::join::hca6aa63e512626da (in rg) + 72 [0x103837e88]
32 | + 825 std::sys::unix::thread::Thread::join::h9bc404ce70591d96 (in rg) + 16 [0x103a10800]
33 | + 825 _pthread_join (in libsystem_pthread.dylib) + 358 [0x7fff739c76de]
34 | + 825 __ulock_wait (in libsystem_kernel.dylib) + 10 [0x7fff739069de]
35 |
--------------------------------------------------------------------------------
/tests/data/collapse-sample/end-before-call-graph-start.txt:
--------------------------------------------------------------------------------
1 | Analysis of sampling rg (pid 64751) every 1 millisecond
2 | Process: rg [64751]
3 | Path: /usr/local/Cellar/ripgrep/11.0.1/bin/rg
4 | Load Address: 0x103746000
5 | Identifier: rg
6 | Version: 0
7 | Code Type: X86-64
8 | Parent Process: zsh [50523]
9 |
10 | Date/Time: 2019-07-04 10:21:28.347 -0600
11 | Launch Time: 2019-07-04 10:21:15.470 -0600
12 | OS Version: Mac OS X 10.14.5 (18F203)
13 | Report Version: 7
14 | Analysis Tool: /usr/bin/sample
15 |
16 | Physical footprint: 227.5M
17 | Physical footprint (peak): 227.5M
18 | ----
19 |
--------------------------------------------------------------------------------
/tests/data/collapse-sample/invalid-samples-field.txt:
--------------------------------------------------------------------------------
1 | Analysis of sampling rg (pid 64751) every 1 millisecond
2 | Process: rg [64751]
3 | Path: /usr/local/Cellar/ripgrep/11.0.1/bin/rg
4 | Load Address: 0x103746000
5 | Identifier: rg
6 | Version: 0
7 | Code Type: X86-64
8 | Parent Process: zsh [50523]
9 |
10 | Date/Time: 2019-07-04 10:21:28.347 -0600
11 | Launch Time: 2019-07-04 10:21:15.470 -0600
12 | OS Version: Mac OS X 10.14.5 (18F203)
13 | Report Version: 7
14 | Analysis Tool: /usr/bin/sample
15 |
16 | Physical footprint: 227.5M
17 | Physical footprint (peak): 227.5M
18 | ----
19 |
20 | Call graph:
21 | 825 Thread_15758523 DispatchQueue_1: com.apple.main-thread (serial)
22 | + start (in libdyld.dylib) + 1 [0x7fff737cf3d5]
23 | + 825 main (in rg) + 41 [0x10384b549]
24 | + 825 std::rt::lang_start_internal::hd2693a01169d6aa1 (in rg) + 334 [0x103a0db1e]
25 | + 825 __rust_maybe_catch_panic (in rg) + 31 [0x103a230cf]
26 | + 825 std::panicking::try::do_call::hab896c32750930ec (.llvm.7886897009887049720) (in rg) + 24 [0x103a22258]
27 | + 825 std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h7cd9ec399e9db3f7 (in rg) + 6 [0x10381bb66]
28 | + 825 rg::main::h6909bd3a32e27a08 (in rg) + 34 [0x1038445a2]
29 | + 825 rg::try_main::h1b50b8f6fd4186a2 (in rg) + 13818 [0x103847c3a]
30 | + 825 ignore::walk::WalkParallel::run::h9c94d86e305a5f70 (in rg) + 3616 [0x1037cb520]
31 | + 825 _$LT$std..thread..JoinHandle$LT$T$GT$$GT$::join::hca6aa63e512626da (in rg) + 72 [0x103837e88]
32 | + 825 std::sys::unix::thread::Thread::join::h9bc404ce70591d96 (in rg) + 16 [0x103a10800]
33 | + 825 _pthread_join (in libsystem_pthread.dylib) + 358 [0x7fff739c76de]
34 | + 825 __ulock_wait (in libsystem_kernel.dylib) + 10 [0x7fff739069de]
35 |
36 | Total number in stack (recursive counted multiple, when >=5):
37 | REMOVED EVERYTHING BELOW HERE BECAUSE IT'S NOT USED
38 |
--------------------------------------------------------------------------------
/tests/data/collapse-sample/large.txt.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonhoo/inferno/5ee7d6bb68ac9627010ef468c81f4f264cd0d399/tests/data/collapse-sample/large.txt.gz
--------------------------------------------------------------------------------
/tests/data/collapse-sample/no-four-spaces.txt:
--------------------------------------------------------------------------------
1 | Analysis of sampling rg (pid 64751) every 1 millisecond
2 | Process: rg [64751]
3 | Path: /usr/local/Cellar/ripgrep/11.0.1/bin/rg
4 | Load Address: 0x103746000
5 | Identifier: rg
6 | Version: 0
7 | Code Type: X86-64
8 | Parent Process: zsh [50523]
9 |
10 | Date/Time: 2019-07-04 10:21:28.347 -0600
11 | Launch Time: 2019-07-04 10:21:15.470 -0600
12 | OS Version: Mac OS X 10.14.5 (18F203)
13 | Report Version: 7
14 | Analysis Tool: /usr/bin/sample
15 |
16 | Physical footprint: 227.5M
17 | Physical footprint (peak): 227.5M
18 | ----
19 |
20 | Call graph:
21 | 825 Thread_15758523 DispatchQueue_1: com.apple.main-thread (serial)
22 | + start (in libdyld.dylib) + 1 [0x7fff737cf3d5]
23 | + 825 main (in rg) + 41 [0x10384b549]
24 | + 825 std::rt::lang_start_internal::hd2693a01169d6aa1 (in rg) + 334 [0x103a0db1e]
25 | + 825 __rust_maybe_catch_panic (in rg) + 31 [0x103a230cf]
26 | + 825 std::panicking::try::do_call::hab896c32750930ec (.llvm.7886897009887049720) (in rg) + 24 [0x103a22258]
27 | + 825 std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h7cd9ec399e9db3f7 (in rg) + 6 [0x10381bb66]
28 | + 825 rg::main::h6909bd3a32e27a08 (in rg) + 34 [0x1038445a2]
29 | + 825 rg::try_main::h1b50b8f6fd4186a2 (in rg) + 13818 [0x103847c3a]
30 | + 825 ignore::walk::WalkParallel::run::h9c94d86e305a5f70 (in rg) + 3616 [0x1037cb520]
31 | + 825 _$LT$std..thread..JoinHandle$LT$T$GT$$GT$::join::hca6aa63e512626da (in rg) + 72 [0x103837e88]
32 | + 825 std::sys::unix::thread::Thread::join::h9bc404ce70591d96 (in rg) + 16 [0x103a10800]
33 | + 825 _pthread_join (in libsystem_pthread.dylib) + 358 [0x7fff739c76de]
34 | + 825 __ulock_wait (in libsystem_kernel.dylib) + 10 [0x7fff739069de]
35 |
36 | Total number in stack (recursive counted multiple, when >=5):
37 | REMOVED EVERYTHING BELOW HERE BECAUSE IT'S NOT USED
38 |
--------------------------------------------------------------------------------
/tests/data/collapse-sample/odd-indentation.txt:
--------------------------------------------------------------------------------
1 | Analysis of sampling rg (pid 64751) every 1 millisecond
2 | Process: rg [64751]
3 | Path: /usr/local/Cellar/ripgrep/11.0.1/bin/rg
4 | Load Address: 0x103746000
5 | Identifier: rg
6 | Version: 0
7 | Code Type: X86-64
8 | Parent Process: zsh [50523]
9 |
10 | Date/Time: 2019-07-04 10:21:28.347 -0600
11 | Launch Time: 2019-07-04 10:21:15.470 -0600
12 | OS Version: Mac OS X 10.14.5 (18F203)
13 | Report Version: 7
14 | Analysis Tool: /usr/bin/sample
15 |
16 | Physical footprint: 227.5M
17 | Physical footprint (peak): 227.5M
18 | ----
19 |
20 | Call graph:
21 | 825 Thread_15758523 DispatchQueue_1: com.apple.main-thread (serial)
22 | + 825 start (in libdyld.dylib) + 1 [0x7fff737cf3d5]
23 | + 825 main (in rg) + 41 [0x10384b549]
24 | + 825 std::rt::lang_start_internal::hd2693a01169d6aa1 (in rg) + 334 [0x103a0db1e]
25 | + 825 __rust_maybe_catch_panic (in rg) + 31 [0x103a230cf]
26 | + 825 std::panicking::try::do_call::hab896c32750930ec (.llvm.7886897009887049720) (in rg) + 24 [0x103a22258]
27 | + 825 std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h7cd9ec399e9db3f7 (in rg) + 6 [0x10381bb66]
28 | + 825 rg::main::h6909bd3a32e27a08 (in rg) + 34 [0x1038445a2]
29 | + 825 rg::try_main::h1b50b8f6fd4186a2 (in rg) + 13818 [0x103847c3a]
30 | + 825 ignore::walk::WalkParallel::run::h9c94d86e305a5f70 (in rg) + 3616 [0x1037cb520]
31 | + 825 _$LT$std..thread..JoinHandle$LT$T$GT$$GT$::join::hca6aa63e512626da (in rg) + 72 [0x103837e88]
32 | + 825 std::sys::unix::thread::Thread::join::h9bc404ce70591d96 (in rg) + 16 [0x103a10800]
33 | + 825 _pthread_join (in libsystem_pthread.dylib) + 358 [0x7fff739c76de]
34 | + 825 __ulock_wait (in libsystem_kernel.dylib) + 10 [0x7fff739069de]
35 |
36 | Total number in stack (recursive counted multiple, when >=5):
37 | REMOVED EVERYTHING BELOW HERE BECAUSE IT'S NOT USED
38 |
--------------------------------------------------------------------------------
/tests/data/collapse-sample/skipped-indentation.txt:
--------------------------------------------------------------------------------
1 | Analysis of sampling rg (pid 64751) every 1 millisecond
2 | Process: rg [64751]
3 | Path: /usr/local/Cellar/ripgrep/11.0.1/bin/rg
4 | Load Address: 0x103746000
5 | Identifier: rg
6 | Version: 0
7 | Code Type: X86-64
8 | Parent Process: zsh [50523]
9 |
10 | Date/Time: 2019-07-04 10:21:28.347 -0600
11 | Launch Time: 2019-07-04 10:21:15.470 -0600
12 | OS Version: Mac OS X 10.14.5 (18F203)
13 | Report Version: 7
14 | Analysis Tool: /usr/bin/sample
15 |
16 | Physical footprint: 227.5M
17 | Physical footprint (peak): 227.5M
18 | ----
19 |
20 | Call graph:
21 | 825 Thread_15758523 DispatchQueue_1: com.apple.main-thread (serial)
22 | + 825 start (in libdyld.dylib) + 1 [0x7fff737cf3d5]
23 | + 825 main (in rg) + 41 [0x10384b549]
24 | + 825 std::rt::lang_start_internal::hd2693a01169d6aa1 (in rg) + 334 [0x103a0db1e]
25 | + 825 __rust_maybe_catch_panic (in rg) + 31 [0x103a230cf]
26 | + 825 std::panicking::try::do_call::hab896c32750930ec (.llvm.7886897009887049720) (in rg) + 24 [0x103a22258]
27 | + 825 std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h7cd9ec399e9db3f7 (in rg) + 6 [0x10381bb66]
28 | + 825 rg::main::h6909bd3a32e27a08 (in rg) + 34 [0x1038445a2]
29 | + 825 rg::try_main::h1b50b8f6fd4186a2 (in rg) + 13818 [0x103847c3a]
30 | + 825 ignore::walk::WalkParallel::run::h9c94d86e305a5f70 (in rg) + 3616 [0x1037cb520]
31 | + 825 _$LT$std..thread..JoinHandle$LT$T$GT$$GT$::join::hca6aa63e512626da (in rg) + 72 [0x103837e88]
32 | + 825 std::sys::unix::thread::Thread::join::h9bc404ce70591d96 (in rg) + 16 [0x103a10800]
33 | + 825 _pthread_join (in libsystem_pthread.dylib) + 358 [0x7fff739c76de]
34 | + 825 __ulock_wait (in libsystem_kernel.dylib) + 10 [0x7fff739069de]
35 |
36 | Total number in stack (recursive counted multiple, when >=5):
37 | REMOVED EVERYTHING BELOW HERE BECAUSE IT'S NOT USED
38 |
--------------------------------------------------------------------------------
/tests/data/collapse-sample/stack-line-only-indent-chars.txt:
--------------------------------------------------------------------------------
1 | Analysis of sampling rg (pid 64751) every 1 millisecond
2 | Process: rg [64751]
3 | Path: /usr/local/Cellar/ripgrep/11.0.1/bin/rg
4 | Load Address: 0x103746000
5 | Identifier: rg
6 | Version: 0
7 | Code Type: X86-64
8 | Parent Process: zsh [50523]
9 |
10 | Date/Time: 2019-07-04 10:21:28.347 -0600
11 | Launch Time: 2019-07-04 10:21:15.470 -0600
12 | OS Version: Mac OS X 10.14.5 (18F203)
13 | Report Version: 7
14 | Analysis Tool: /usr/bin/sample
15 |
16 | Physical footprint: 227.5M
17 | Physical footprint (peak): 227.5M
18 | ----
19 |
20 | Call graph:
21 | 825 Thread_15758523 DispatchQueue_1: com.apple.main-thread (serial)
22 | + |:!
23 | + 825 main (in rg) + 41 [0x10384b549]
24 | + 825 std::rt::lang_start_internal::hd2693a01169d6aa1 (in rg) + 334 [0x103a0db1e]
25 | + 825 __rust_maybe_catch_panic (in rg) + 31 [0x103a230cf]
26 | + 825 std::panicking::try::do_call::hab896c32750930ec (.llvm.7886897009887049720) (in rg) + 24 [0x103a22258]
27 | + 825 std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h7cd9ec399e9db3f7 (in rg) + 6 [0x10381bb66]
28 | + 825 rg::main::h6909bd3a32e27a08 (in rg) + 34 [0x1038445a2]
29 | + 825 rg::try_main::h1b50b8f6fd4186a2 (in rg) + 13818 [0x103847c3a]
30 | + 825 ignore::walk::WalkParallel::run::h9c94d86e305a5f70 (in rg) + 3616 [0x1037cb520]
31 | + 825 _$LT$std..thread..JoinHandle$LT$T$GT$$GT$::join::hca6aa63e512626da (in rg) + 72 [0x103837e88]
32 | + 825 std::sys::unix::thread::Thread::join::h9bc404ce70591d96 (in rg) + 16 [0x103a10800]
33 | + 825 _pthread_join (in libsystem_pthread.dylib) + 358 [0x7fff739c76de]
34 | + 825 __ulock_wait (in libsystem_kernel.dylib) + 10 [0x7fff739069de]
35 |
36 | Total number in stack (recursive counted multiple, when >=5):
37 | REMOVED EVERYTHING BELOW HERE BECAUSE IT'S NOT USED
38 |
--------------------------------------------------------------------------------
/tests/data/collapse-vsprof/empty-file.csv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonhoo/inferno/5ee7d6bb68ac9627010ef468c81f4f264cd0d399/tests/data/collapse-vsprof/empty-file.csv
--------------------------------------------------------------------------------
/tests/data/collapse-vsprof/incorrect-header.csv:
--------------------------------------------------------------------------------
1 | This is not a correct header
2 |
--------------------------------------------------------------------------------
/tests/data/collapse-vsprof/invalid-depth.csv:
--------------------------------------------------------------------------------
1 | Level,Function Name,Number of Calls,Elapsed Inclusive Time %,Elapsed Exclusive Time %,Avg Elapsed Inclusive Time,Avg Elapsed Exclusive Time,Module Name,
2 | 0,"Raytracer.exe",0,100.00,0.00,0.00,0.00,"",
3 | x,"Raytracer.Raytracer.Tracer.b__5_0(int32)",471,91.25,18.39,401.92,81.02,"Raytracer.exe",
4 |
--------------------------------------------------------------------------------
/tests/data/collapse-vsprof/invalid-function-name.csv:
--------------------------------------------------------------------------------
1 | Level,Function Name,Number of Calls,Elapsed Inclusive Time %,Elapsed Exclusive Time %,Avg Elapsed Inclusive Time,Avg Elapsed Exclusive Time,Module Name,
2 | 0,"Raytracer.exe",0,100.00,0.00,0.00,0.00,"",
3 | 1,"Raytracer.Raytracer.Tracer.b__5_0(int32)
4 |
--------------------------------------------------------------------------------
/tests/data/collapse-vsprof/invalid-number-of-calls.csv:
--------------------------------------------------------------------------------
1 | Level,Function Name,Number of Calls,Elapsed Inclusive Time %,Elapsed Exclusive Time %,Avg Elapsed Inclusive Time,Avg Elapsed Exclusive Time,Module Name,
2 | 0,"Raytracer.exe",0,100.00,0.00,0.00,0.00,"",
3 | 1,"Raytracer.Raytracer.Tracer.b__5_0(int32)","4,718.25",91.25,18.39,401.92,81.02,"Raytracer.exe",
4 |
--------------------------------------------------------------------------------
/tests/data/collapse-vsprof/missing-function-name.csv:
--------------------------------------------------------------------------------
1 | Level,Function Name,Number of Calls,Elapsed Inclusive Time %,Elapsed Exclusive Time %,Avg Elapsed Inclusive Time,Avg Elapsed Exclusive Time,Module Name,
2 | 0
3 |
--------------------------------------------------------------------------------
/tests/data/collapse-vtune/bad-stack-line.csv:
--------------------------------------------------------------------------------
1 | Function Stack,CPU Time:Self,Module
2 | Total,0.0,[Unknown]
3 | RtlUserThreadStart,0.0,ntdll.dll
4 | BaseThreadInitThunk,0.0,KERNEL32.DLL
5 | _scrt_common_main_seh,0.0,inferno-collapse-dtrace.exe
6 | main,0.0,inferno-collapse-dtrace.exe
7 | BAD STACK LINE
8 | std::rt::lang_start_internal,0.0,inferno-collapse-dtrace.exe
9 | rust_maybe_catch_panic,0.0,inferno-collapse-dtrace.exe
10 | "std::panicking::try::do_call",0.0,inferno-collapse-dtrace.exe
11 | "std::rt::lang_start::{{closure}}>",0.0,inferno-collapse-dtrace.exe
12 | inferno_collapse_dtrace::main,0.0,inferno-collapse-dtrace.exe
13 | "inferno::collapse::Collapse::collapse_file",0.0,inferno-collapse-dtrace.exe
14 | "inferno::collapse::dtrace::{{impl}}::collapse,std::io::stdio::StdoutLock>",0.0,inferno-collapse-dtrace.exe
15 | inferno::collapse::dtrace::Folder::on_stack_line,0.0,inferno-collapse-dtrace.exe
16 | alloc::string::{{impl}}::to_string,0.0,inferno-collapse-dtrace.exe
17 | alloc::str::{{impl}}::to_owned,0.0,inferno-collapse-dtrace.exe
18 | alloc::slice::{{impl}}::to_owned,0.0,inferno-collapse-dtrace.exe
19 | alloc::slice::{{impl}}::to_vec,0.0,inferno-collapse-dtrace.exe
20 | alloc::slice::hack::to_vec,0.0,inferno-collapse-dtrace.exe
21 | alloc::vec::Vec::extend_from_slice,0.0,inferno-collapse-dtrace.exe
22 | core::slice::{{impl}}::iter,0.0,inferno-collapse-dtrace.exe
23 | core::ptr::{{impl}}::is_null,0.016612,inferno-collapse-dtrace.exe
24 | alloc::vec::Vec::with_capacity,0.0,inferno-collapse-dtrace.exe
25 | "alloc::raw_vec::RawVec::with_capacity",0.0,inferno-collapse-dtrace.exe
26 | "alloc::raw_vec::RawVec::allocate_in",0.0,inferno-collapse-dtrace.exe
27 | alloc::alloc::{{impl}}::alloc,0.0,inferno-collapse-dtrace.exe
28 | alloc::alloc::alloc,0.0,inferno-collapse-dtrace.exe
29 | func@0x180019140,0.014938,ntdll.dll
30 | inferno::collapse::dtrace::Folder::remove_offset,0.0,inferno-collapse-dtrace.exe
31 | core::iter::range::{{impl}}::next,0.014942,inferno-collapse-dtrace.exe
32 | core::iter::range::{{impl}}::add_usize,0.0,inferno-collapse-dtrace.exe
33 | core::num::{{impl}}::checked_add,0.0,inferno-collapse-dtrace.exe
34 | core::num::{{impl}}::overflowing_add,0.015414,inferno-collapse-dtrace.exe
35 | alloc::string::String::clear,0.0,inferno-collapse-dtrace.exe
36 | alloc::vec::Vec::clear,0.0,inferno-collapse-dtrace.exe
37 | alloc::vec::Vec::truncate,0.030580,inferno-collapse-dtrace.exe
38 | core::iter::range::{{impl}}::next,0.0,inferno-collapse-dtrace.exe
39 | core::iter::range::{{impl}}::add_usize,0.0,inferno-collapse-dtrace.exe
40 | "core::convert::{{impl}}::try_from",0.0,inferno-collapse-dtrace.exe
41 | "core::convert::{{impl}}::into",0.015309,inferno-collapse-dtrace.exe
42 | inferno::collapse::dtrace::Folder::on_stack_end,0.0,inferno-collapse-dtrace.exe
43 | alloc::collections::vec_deque::VecDeque::clear,0.0,inferno-collapse-dtrace.exe
44 | core::ptr::real_drop_in_place>,0.0,inferno-collapse-dtrace.exe
45 | alloc::collections::vec_deque::{{impl}}::drop,0.0,inferno-collapse-dtrace.exe
46 | "core::iter::traits::iterator::Iterator::for_each*,fn(alloc::string::String)>",0.016777,inferno-collapse-dtrace.exe
47 | alloc::string::{{impl}}::deref,0.0,inferno-collapse-dtrace.exe
48 | alloc::vec::{{impl}}::deref,0.0,inferno-collapse-dtrace.exe
49 | core::ptr::{{impl}}::is_null,0.015252,inferno-collapse-dtrace.exe
50 | inferno::collapse::dtrace::Folder::finish,0.0,inferno-collapse-dtrace.exe
51 | std::io::Write::write_fmt,0.0,inferno-collapse-dtrace.exe
52 | core::fmt::write,0.0,inferno-collapse-dtrace.exe
53 | std::io::Write::write_fmt::{{impl}}::write_str,0.0,inferno-collapse-dtrace.exe
54 | std::io::Write::write_all,0.0,inferno-collapse-dtrace.exe
55 | std::io::stdio::{{impl}}::write,0.0,inferno-collapse-dtrace.exe
56 | std::io::buffered::{{impl}}::write>,0.0,inferno-collapse-dtrace.exe
57 | std::io::buffered::BufWriter>::flush_buf>,0.0,inferno-collapse-dtrace.exe
58 | std::sys::windows::stdio::write,0.0,inferno-collapse-dtrace.exe
59 | GetConsoleMode,0.0,KERNELBASE.dll
60 | NtDeviceIoControlFile,0.023113,ntdll.dll
61 | WriteConsoleW,0.0,KERNELBASE.dll
62 | func@0x180008ce8,0.0,KERNELBASE.dll
63 | NtDeviceIoControlFile,0.004207,ntdll.dll
64 | memset,0.001428,VCRUNTIME140.dll
65 |
--------------------------------------------------------------------------------
/tests/data/collapse-vtune/end-before-header.csv:
--------------------------------------------------------------------------------
1 | war:Column filter is ON.
2 |
--------------------------------------------------------------------------------
/tests/data/collapse-vtune/invalid-time-field.csv:
--------------------------------------------------------------------------------
1 | Function Stack,CPU Time:Self,Module
2 | Total,INVALID TIME,[Unknown]
3 | RtlUserThreadStart,0.0,ntdll.dll
4 | BaseThreadInitThunk,0.0,KERNEL32.DLL
5 | _scrt_common_main_seh,0.0,inferno-collapse-dtrace.exe
6 | main,0.0,inferno-collapse-dtrace.exe
7 | "std::rt::lang_start>",0.0,inferno-collapse-dtrace.exe
8 | std::rt::lang_start_internal,0.0,inferno-collapse-dtrace.exe
9 | rust_maybe_catch_panic,0.0,inferno-collapse-dtrace.exe
10 | "std::panicking::try::do_call",0.0,inferno-collapse-dtrace.exe
11 | "std::rt::lang_start::{{closure}}