Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/bin/collapse-perf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::io;
use std::path::PathBuf;
use structopt::StructOpt;

use inferno::collapse::perf::{Options, Perf};
use inferno::collapse::Frontend;
use inferno::collapse::perf::{Folder, Options};
use inferno::collapse::Collapse;

#[derive(Debug, StructOpt)]
#[structopt(
Expand Down Expand Up @@ -77,5 +77,5 @@ impl Opt {

fn main() -> io::Result<()> {
let (infile, options) = Opt::from_args().into_parts();
Perf::from_options(options).collapse_file(infile.as_ref())
Folder::from(options).collapse_file(infile.as_ref())
}
45 changes: 20 additions & 25 deletions src/collapse/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Tools for collapsing the output of various profilers (e.g. [perf]) into the
//! format expected by flamegraph.
//!
//! [perf]: https://en.wikipedia.org/wiki/Perf_(Linux)

/// Stack collapsing for the output of [`perf script`](https://linux.die.net/man/1/perf-script).
///
/// See the [crate-level documentation] for details.
///
/// [crate-level documentation]: ../../index.html
pub mod perf;

use std::fs::File;
Expand All @@ -11,32 +11,27 @@ use std::path::Path;

const READER_CAPACITY: usize = 128 * 1024;

/// This trait represents the ability to collapse the output of various profilers, such as
/// [perf], into the format expected by flamegraph.
/// The abstract behavior of stack collapsing.
///
/// Implementors of this trait are providing a way to take the stack traces produced by a
/// particular profiler's output (like `perf script`) and produce lines in the folded stack format
/// expected by [`crate::flamegraph::from_sorted_lines`].
///
/// See also the [crate-level documentation] for details.
///
/// [perf]: https://en.wikipedia.org/wiki/Perf_(Linux)
pub trait Frontend {
/// Collapses the contents of the provided `reader` into the format expected by flamegraph.
/// Writes the output to the provided `writer`.
///
/// # Errors
///
/// Return an [`io::Error`] if unsuccessful.
///
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
/// [crate-level documentation]: ../index.html
// https://github.com/rust-lang/rust/issues/45040
// #[doc(spotlight)]
pub trait Collapse {
/// Collapses the contents of the provided `reader` and writes folded stack lines to the
/// provided `writer`.
fn collapse<R, W>(&mut self, reader: R, writer: W) -> io::Result<()>
where
R: io::BufRead,
W: io::Write;

/// Collapses the contents of a file (or of STDIN if `infile` is `None`) into the
/// format expected by flamegraph. Writes the output to STDOUT.
///
/// # Errors
///
/// Return an [`io::Error`] if unsuccessful.
///
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
/// Collapses the contents of a file (or of STDIN if `infile` is `None`) and writes folded
/// stack lines to `STDOUT`.
fn collapse_file<P>(&mut self, infile: Option<P>) -> io::Result<()>
where
P: AsRef<Path>,
Expand Down
58 changes: 41 additions & 17 deletions src/collapse/perf.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,58 @@
use super::Collapse;
use smallvec::SmallVec;
use std::borrow::Cow;
use std::collections::{HashMap, VecDeque};
use std::fs::File;
use std::io;
use std::io::prelude::*;

use super::Frontend;

const TIDY_GENERIC: bool = true;
const TIDY_JAVA: bool = true;

/// Settings one may pass during the construction of a `Perf` (via its `from_options` method).
/// Settings that change how frames are named from the incoming stack traces.
///
/// All options default to off.
#[derive(Clone, Debug, Default)]
pub struct Options {
/// include PID with process names [1]
/// Include PID in the root frame.
///
/// If disabled, the root frame is given the name of the profiled process.
pub include_pid: bool,

/// include TID and PID with process names [1]
/// Include TID and PID in the root frame.
///
/// Implies `include_pid`.
pub include_tid: bool,

/// include raw addresses where symbols can't be found
/// Include raw addresses (e.g., `0xbfff0836`) where symbols can't be found.
pub include_addrs: bool,

/// annotate jit functions with a _[j]
/// Annotate JIT functions with a `_[j]` suffix.
pub annotate_jit: bool,

/// annotate kernel functions with a _[k]
/// Annotate kernel functions with a `_[k]` suffix.
pub annotate_kernel: bool,

/// un-inline using addr2line
/// Resolve function names (including inlined ones) using `addr2line`.
///
/// When this option is disabled, only the function name observed by `perf` is included, which
/// may not include inlined functions in the call stack.
///
/// When this option is enabled, the function names observed by `perf` are ignored, and each
/// observed function address is instead resolved using
/// [`addr2line`](https://docs.rs/addr2line/). This is slower, but will use binary debug info
/// to resolve even inline call-chains.
pub show_inline: bool,

/// adds source context to inline
/// If enabled, each frame name is also annoted with the file name and line number of the
/// sampled source line.
///
/// Implies `show_inline`.
pub show_context: bool,

/// event type filter, defaults to first encountered event
/// Only consider samples of the given event type (see `perf list`).
///
/// If this option is set to `None`, it will be set to the first encountered event type.
pub event_filter: Option<String>,
}

Expand All @@ -51,9 +69,12 @@ impl Default for EventFilterState {
}
}

/// The perf implementation of `Frontend`.
/// A stack collapser for the output of `perf script`.
///
/// To construct one, either use `perf::Folder::default()` or create an [`Options`] and use
/// `perf::Folder::from(options)`.
#[derive(Default)]
pub struct Perf {
pub struct Folder {
/// All lines until the next empty line are stack lines.
in_event: bool,

Expand All @@ -79,7 +100,7 @@ pub struct Perf {
opt: Options,
}

impl Frontend for Perf {
impl Collapse for Folder {
fn collapse<R, W>(&mut self, mut reader: R, writer: W) -> io::Result<()>
where
R: BufRead,
Expand Down Expand Up @@ -108,9 +129,10 @@ impl Frontend for Perf {
}
}

impl Perf {
/// Constructs a `Perf` with the provided `Options`.
pub fn from_options(opt: Options) -> Self {
impl From<Options> for Folder {
fn from(mut opt: Options) -> Self {
opt.include_pid = opt.include_pid || opt.include_tid;
opt.show_inline = opt.show_inline || opt.show_context;
Self {
in_event: false,
skip_stack: false,
Expand All @@ -122,7 +144,9 @@ impl Perf {
opt,
}
}
}

impl Folder {
fn on_line(&mut self, line: &str) {
if !self.in_event {
self.on_event_line(line)
Expand Down
46 changes: 24 additions & 22 deletions src/flamegraph/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@ macro_rules! unwrap_or_continue {
pub struct FuncFrameAttrsMap(HashMap<String, FrameAttrs>);

impl FuncFrameAttrsMap {
/// Parse a FuncFrameAttrsMap from a file.
/// Each line should be a function name followed by a tab,
/// then a sequence of tab separated name=value pairs.
/// Parse frame attributes from a file.
///
/// Each line should consist of a function name, a tab (`\t`), and then a sequence of
/// tab-separated `name=value` pairs.
pub fn from_file(path: &PathBuf) -> io::Result<FuncFrameAttrsMap> {
let file = BufReader::new(File::open(path)?);
FuncFrameAttrsMap::from_reader(file)
}

/// Parse a FuncFrameAttrsMap from a reader.
/// Each line should be a function name followed by a tab,
/// then a sequence of tab separated name=value pairs.
/// Parse frame attributes from a `BufRead`.
///
/// Each line should consist of a function name, a tab (`\t`), and then a sequence of
/// tab-separated `name=value` pairs.
pub fn from_reader<R: BufRead>(mut reader: R) -> io::Result<FuncFrameAttrsMap> {
let mut funcattr_map = FuncFrameAttrsMap::default();
let mut line = String::new();
Expand Down Expand Up @@ -77,56 +79,56 @@ impl FuncFrameAttrsMap {
}

/// Return FrameAttrs for the given function name if it exists
pub fn frameattrs_for_func(&self, func: &str) -> Option<&FrameAttrs> {
pub(super) fn frameattrs_for_func(&self, func: &str) -> Option<&FrameAttrs> {
self.0.get(func)
}
}

/// Attributes to set on the SVG elements of a frame
#[derive(PartialEq, Eq, Debug, Default)]
pub struct FrameAttrs {
pub(super) struct FrameAttrs {
/// The text to include in the `title` element.
/// If set to None, the title is dynamically generated based on the function name.
pub title: Option<String>,
pub(super) title: Option<String>,

pub g: GElementAttrs,
pub a: AElementAttrs,
pub(super) g: GElementAttrs,
pub(super) a: AElementAttrs,
}

/// Attributes to set on the SVG `g` element.
/// Any of them set to `None` will get the default value.
#[derive(PartialEq, Eq, Debug, Default)]
pub struct GElementAttrs {
pub(super) struct GElementAttrs {
/// Defaults to "func_g"
pub class: Option<String>,
pub(super) class: Option<String>,

/// Will not be included if None
pub style: Option<String>,
pub(super) style: Option<String>,

/// Defaults to "s(this)"
pub onmouseover: Option<String>,
pub(super) onmouseover: Option<String>,

/// Defaults to "c()"
pub onmouseout: Option<String>,
pub(super) onmouseout: Option<String>,

/// Defaults to "zoom(this)"
pub onclick: Option<String>,
pub(super) onclick: Option<String>,

/// Extra attributes to include
pub extra: Vec<(String, String)>,
pub(super) extra: Vec<(String, String)>,
}

/// Attributes to set on the SVG `a` element
#[derive(PartialEq, Eq, Debug, Default)]
pub struct AElementAttrs {
pub(super) struct AElementAttrs {
/// If set to None the `a` tag will not be added
pub href: Option<String>,
pub(super) href: Option<String>,

/// Defaults to "_top"
pub target: Option<String>,
pub(super) target: Option<String>,

/// Extra attributes to include
pub extra: Vec<(String, String)>,
pub(super) extra: Vec<(String, String)>,
}

fn parse_extra_attrs(attrs: &mut Vec<(String, String)>, s: &str) {
Expand Down
Loading