Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 attribtues 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 attribtues 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