diff --git a/Cargo.toml b/Cargo.toml index 4c0e70c9..2bd21635 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,16 +21,17 @@ cirrus-ci = { repository = "jonhoo/inferno" } codecov = { repository = "jonhoo/inferno", branch = "master", service = "github" } [features] -default = ["cli", "multithreaded"] +default = ["cli", "multithreaded", "nameattr"] cli = ["structopt", "env_logger"] multithreaded = ["chashmap", "crossbeam", "num_cpus"] +nameattr = ["indexmap"] [dependencies] chashmap = { version = "2.2", optional = true } crossbeam = { version = "0.7", optional = true } env_logger = { version = "0.6.0", optional = true } fnv = "1.0.3" -indexmap = "1.0" +indexmap = { version = "1.0", optional = true } itoa = "0.4.3" lazy_static = "1.3.0" log = "0.4" diff --git a/src/bin/flamegraph.rs b/src/bin/flamegraph.rs index fe5c3e6c..0d895db4 100644 --- a/src/bin/flamegraph.rs +++ b/src/bin/flamegraph.rs @@ -3,7 +3,11 @@ use std::path::{Path, PathBuf}; use env_logger::Env; use inferno::flamegraph::color::{BackgroundColor, PaletteMap, SearchColor}; -use inferno::flamegraph::{self, defaults, Direction, FuncFrameAttrsMap, Options, Palette}; +use inferno::flamegraph::{self, defaults, Direction, Options, Palette}; + +#[cfg(feature = "nameattr")] +use inferno::flamegraph::FuncFrameAttrsMap; + use structopt::StructOpt; #[derive(Debug, StructOpt)] @@ -133,6 +137,7 @@ struct Opt { /// File containing attributes to use for the SVG frames of particular functions. /// Each line in the file should be a function name followed by a tab, /// then a sequence of tab separated name=value pairs + #[cfg(feature = "nameattr")] #[structopt(long = "nameattr", value_name = "PATH")] nameattr: Option, @@ -187,14 +192,9 @@ impl<'a> Opt { options.colors = self.colors; options.bgcolors = self.bgcolors; options.hash = self.hash; - if let Some(file) = self.nameattr { - match FuncFrameAttrsMap::from_file(&file) { - Ok(m) => { - options.func_frameattrs = m; - } - Err(e) => panic!("Error reading {}: {:?}", file.display(), e), - } - }; + + self.set_func_frameattrs(&mut options); + if self.inverted { options.direction = Direction::Inverted; if self.title == defaults::TITLE { @@ -226,6 +226,21 @@ impl<'a> Opt { options.search_color = self.search_color; (self.infiles, options) } + + #[cfg(feature = "nameattr")] + fn set_func_frameattrs(&self, options: &mut Options) { + if let Some(file) = &self.nameattr { + match FuncFrameAttrsMap::from_file(&file) { + Ok(m) => { + options.func_frameattrs = m; + } + Err(e) => panic!("Error reading {}: {:?}", file.display(), e), + } + }; + } + + #[cfg(not(feature = "nameattr"))] + fn set_func_frameattrs(&self, _: &mut Options) {} } const PALETTE_MAP_FILE: &str = "palette.map"; // default name for the palette map file diff --git a/src/flamegraph/mod.rs b/src/flamegraph/mod.rs index 0821b1d9..6c848fae 100644 --- a/src/flamegraph/mod.rs +++ b/src/flamegraph/mod.rs @@ -4,7 +4,9 @@ macro_rules! args { }}; } +#[cfg(feature = "nameattr")] mod attrs; + pub mod color; mod merge; mod rand; @@ -23,8 +25,12 @@ use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::Writer; use str_stack::StrStack; +#[cfg(feature = "nameattr")] use self::attrs::FrameAttrs; + +#[cfg(feature = "nameattr")] pub use self::attrs::FuncFrameAttrsMap; + pub use self::color::Palette; use self::color::{Color, SearchColor}; use self::svg::{Dimension, StyleOptions}; @@ -115,6 +121,7 @@ pub struct Options<'a> { /// /// In particular, if a function appears in the given map, it will have extra attributes set in /// the resulting SVG based on its value in the map. + #[cfg(feature = "nameattr")] pub func_frameattrs: FuncFrameAttrsMap, /// Whether to plot a plot that grows top-to-bottom or bottom-up (the default). @@ -254,13 +261,15 @@ impl<'a> Default for Options<'a> { bgcolors: Default::default(), hash: Default::default(), palette_map: Default::default(), - func_frameattrs: Default::default(), direction: Default::default(), negate_differentials: Default::default(), pretty_xml: Default::default(), no_sort: Default::default(), reverse_stack_order: Default::default(), no_javascript: Default::default(), + + #[cfg(feature = "nameattr")] + func_frameattrs: Default::default(), } } } @@ -521,28 +530,14 @@ where } }; - let frame_attributes = opt - .func_frameattrs - .frameattrs_for_func(frame.location.function); - - let mut has_href = false; - let mut title = &buffer[info]; - if let Some(frame_attributes) = frame_attributes { - if frame_attributes.attrs.contains_key("xlink:href") { - write_container_attributes(&mut cache_a, &frame_attributes); - svg.write_event(&cache_a)?; - has_href = true; - } else { - write_container_attributes(&mut cache_g, &frame_attributes); - svg.write_event(&cache_g)?; - } - if let Some(ref t) = frame_attributes.title { - title = t.as_str(); - } - } else if let Event::Start(ref mut c) = cache_g { - c.clear_attributes(); - svg.write_event(&cache_g)?; - } + let (has_href, title) = write_container_start( + opt, + &mut svg, + &mut cache_a, + &mut cache_g, + &frame, + &buffer[info], + )?; svg.write_event(Event::Start(BytesStart::borrowed_name(b"title")))?; svg.write_event(Event::Text(BytesText::from_plain_str(title)))?; @@ -627,7 +622,59 @@ where Ok(()) } +#[cfg(feature = "nameattr")] +fn write_container_start<'a, W: Write>( + opt: &'a Options<'a>, + svg: &mut Writer, + cache_a: &mut Event<'_>, + cache_g: &mut Event<'_>, + frame: &merge::TimedFrame<'_>, + mut title: &'a str, +) -> quick_xml::Result<(bool, &'a str)> { + let frame_attributes = opt + .func_frameattrs + .frameattrs_for_func(frame.location.function); + + let mut has_href = false; + if let Some(frame_attributes) = frame_attributes { + if frame_attributes.attrs.contains_key("xlink:href") { + write_container_attributes(cache_a, &frame_attributes); + svg.write_event(&cache_a)?; + has_href = true; + } else { + write_container_attributes(cache_g, &frame_attributes); + svg.write_event(&cache_g)?; + } + if let Some(ref t) = frame_attributes.title { + title = t.as_str(); + } + } else if let Event::Start(ref mut c) = cache_g { + c.clear_attributes(); + svg.write_event(&cache_g)?; + } + + Ok((has_href, title)) +} + +#[cfg(not(feature = "nameattr"))] +fn write_container_start<'a, W: Write>( + _opt: &Options<'_>, + svg: &mut Writer, + _cache_a: &mut Event<'_>, + cache_g: &mut Event<'_>, + _frame: &merge::TimedFrame<'_>, + title: &'a str, +) -> quick_xml::Result<(bool, &'a str)> { + if let Event::Start(ref mut c) = cache_g { + c.clear_attributes(); + svg.write_event(&cache_g)?; + } + + Ok((false, title)) +} + /// Writes atributes to the container, container could be g or a +#[cfg(feature = "nameattr")] fn write_container_attributes(event: &mut Event<'_>, frame_attributes: &FrameAttrs) { if let Event::Start(ref mut c) = event { c.clear_attributes(); diff --git a/tests/flamegraph.rs b/tests/flamegraph.rs index 624ae602..e53d73c7 100644 --- a/tests/flamegraph.rs +++ b/tests/flamegraph.rs @@ -185,6 +185,7 @@ fn flamegraph_factor() { } #[test] +#[cfg(feature = "nameattr")] fn flamegraph_nameattr() { let input_file = "./flamegraph/test/results/perf-cycles-instructions-01-collapsed-all.txt"; let expected_result_file = "./tests/data/flamegraph/nameattr/nameattr.svg"; @@ -201,6 +202,7 @@ fn flamegraph_nameattr() { } #[test] +#[cfg(feature = "nameattr")] fn flamegraph_nameattr_empty_line() { let input_file = "./flamegraph/test/results/perf-cycles-instructions-01-collapsed-all.txt"; let expected_result_file = "./tests/data/flamegraph/nameattr/nameattr.svg"; @@ -217,6 +219,7 @@ fn flamegraph_nameattr_empty_line() { } #[test] +#[cfg(feature = "nameattr")] fn flamegraph_nameattr_empty_attribute() { let input_file = "./flamegraph/test/results/perf-cycles-instructions-01-collapsed-all.txt"; let expected_result_file = "./tests/data/flamegraph/nameattr/nameattr.svg"; @@ -233,6 +236,7 @@ fn flamegraph_nameattr_empty_attribute() { } #[test] +#[cfg(feature = "nameattr")] fn flamegraph_nameattr_duplicate_attributes() { let input_file = "./flamegraph/test/results/perf-cycles-instructions-01-collapsed-all.txt"; let expected_result_file = "./tests/data/flamegraph/nameattr/nameattr_duplicate_attributes.svg"; @@ -249,6 +253,7 @@ fn flamegraph_nameattr_duplicate_attributes() { } #[test] +#[cfg(feature = "nameattr")] fn flamegraph_nameattr_should_warn_about_duplicate_attributes() { test_logger::init(); let nameattr_file = "./tests/data/flamegraph/nameattr/nameattr_duplicate_attributes.txt"; @@ -267,6 +272,7 @@ fn flamegraph_nameattr_should_warn_about_duplicate_attributes() { } #[test] +#[cfg(feature = "nameattr")] fn flamegraph_nameattr_should_warn_about_invalid_attribute() { test_logger::init(); let nameattr_file = "./tests/data/flamegraph/nameattr/nameattr_invalid_attribute.txt";