From 2066625ff3c88597ed6c2c4e2a15b5e4853066a4 Mon Sep 17 00:00:00 2001 From: data-pup Date: Wed, 23 May 2018 08:51:55 -0700 Subject: [PATCH] Added regex functionality to the dominators sub-command. Solves #59. --- analyze/analyze.rs | 65 ++++++++++++------- opt/definitions.rs | 38 ++++++----- .../expectations/dominators_regex_any_func | 14 ++++ twiggy/tests/tests.rs | 8 +++ 4 files changed, 86 insertions(+), 39 deletions(-) create mode 100644 twiggy/tests/expectations/dominators_regex_any_func diff --git a/analyze/analyze.rs b/analyze/analyze.rs index 7157f27a..d1692308 100644 --- a/analyze/analyze.rs +++ b/analyze/analyze.rs @@ -263,7 +263,7 @@ pub fn top(items: &mut ir::Items, opts: &opt::Top) -> Result, struct DominatorTree { tree: BTreeMap>, - root_id: ir::Id, + items: Vec, opts: opt::Dominators, } @@ -277,11 +277,6 @@ impl traits::Emit for DominatorTree { let opts = &self.opts; let mut row = 0 as u32; - let start_depth = if self.root_id == items.meta_root() { - 0 - } else { - 1 - }; fn recursive_add_rows( table: &mut Table, @@ -343,15 +338,19 @@ impl traits::Emit for DominatorTree { } } - recursive_add_rows( - &mut table, - items, - &self.tree, - start_depth, - &mut row, - &opts, - self.root_id, - ); + for id in &self.items { + let start_depth = if *id == items.meta_root() { 0 } else { 1 }; + recursive_add_rows( + &mut table, + items, + &self.tree, + start_depth, + &mut row, + &opts, + *id, + ); + } + write!(dest, "{}", &table)?; Ok(()) } @@ -396,7 +395,11 @@ impl traits::Emit for DominatorTree { } let mut obj = json::object(dest)?; - recursive_add_children(items, &self.opts, &self.tree, self.root_id, &mut obj) + for curr_id in &self.items { + recursive_add_children(items, &self.opts, &self.tree, *curr_id, &mut obj)?; + } + + Ok(()) } fn emit_csv(&self, items: &ir::Items, dest: &mut io::Write) -> Result<(), traits::Error> { @@ -472,18 +475,32 @@ pub fn dominators( items.compute_retained_sizes(); items.compute_predecessors(); - let subtree = opts.subtree(); - let root_id = match subtree.is_empty() { - true => items.meta_root(), - false => items - .get_item_by_name(&subtree) - .map(|item| item.id()) - .unwrap_or(items.meta_root()), + let arguments = opts.items(); + let dominator_items = match arguments.is_empty() { + true => vec![items.meta_root()], + false => { + if opts.using_regexps() { + let regexps = regex::RegexSet::new(arguments)?; + let mut sorted_items: Vec<_> = items + .iter() + .filter(|item| regexps.is_match(&item.name())) + .map(|item| item.id()) + .collect(); + sorted_items.sort_by_key(|id| items.retained_size(*id) as i32 * -1); + sorted_items + } else { + arguments + .iter() + .filter_map(|name| items.get_item_by_name(name)) + .map(|item| item.id()) + .collect() + } + } }; let tree = DominatorTree { tree: items.dominator_tree().clone(), - root_id, + items: dominator_items, opts: opts.clone(), }; diff --git a/opt/definitions.rs b/opt/definitions.rs index 0efa9fe0..de5096a9 100644 --- a/opt/definitions.rs +++ b/opt/definitions.rs @@ -134,7 +134,7 @@ pub struct Dominators { output_format: traits::OutputFormat, /// The name of the function whose dominator subtree should be printed. - subtree: Option, + items: Vec, /// The maximum depth to print the dominators tree. #[structopt(short = "d")] @@ -143,6 +143,20 @@ pub struct Dominators { /// The maximum number of rows, regardless of depth in the tree, to display. #[structopt(short = "r")] max_rows: Option, + + /// Whether or not `items` should be treated as regular expressions. + #[structopt(long = "regex")] + using_regexps: bool, +} + +impl Dominators { + // TODO: wasm-bindgen does not support sending Vec across + // the wasm ABI boundary yet. + + /// The items whose dominators subtree should be printed. + pub fn items(&self) -> &[String] { + &self.items + } } #[wasm_bindgen] @@ -162,6 +176,11 @@ impl Dominators { self.max_rows.unwrap_or(u32::MAX) } + /// Whether or not `items` should be treated as regular expressions. + pub fn using_regexps(&self) -> bool { + self.using_regexps + } + /// Set the maximum depth to print the dominators tree. pub fn set_max_depth(&mut self, max_depth: u32) { self.max_depth = Some(max_depth); @@ -172,20 +191,9 @@ impl Dominators { self.max_rows = Some(max_rows); } - // TODO: wasm-bindgen does not support sending Option across - // the wasm ABI boundary, return an empty string if `subtree` is None. - - /// The function whose subtree should be printed. - pub fn subtree(&self) -> String { - match &self.subtree { - Some(s) => s.clone(), - None => String::new(), - } - } - - /// Set the function whose subtree should be printed. - pub fn set_subtree(&mut self, subtree: &str) { - self.subtree = Some(subtree.to_string()); + /// Set whether or not `items` should be treated as regular expressions. + pub fn set_using_regexps(&mut self, using_regexps: bool) { + self.using_regexps = using_regexps; } } diff --git a/twiggy/tests/expectations/dominators_regex_any_func b/twiggy/tests/expectations/dominators_regex_any_func new file mode 100644 index 00000000..2c8be7e2 --- /dev/null +++ b/twiggy/tests/expectations/dominators_regex_any_func @@ -0,0 +1,14 @@ + Retained Bytes │ Retained % │ Dominator Tree +────────────────┼────────────┼───────────────────────── + 15 ┊ 10.42% ┊ func[3] + 14 ┊ 9.72% ┊ ⤷ woof + 6 ┊ 4.17% ┊ ⤷ func[0] + 5 ┊ 3.47% ┊ ⤷ calledOnce + 6 ┊ 4.17% ┊ func[0] + 5 ┊ 3.47% ┊ ⤷ calledOnce + 6 ┊ 4.17% ┊ func[1] + 5 ┊ 3.47% ┊ ⤷ calledTwice + 6 ┊ 4.17% ┊ func[2] + 5 ┊ 3.47% ┊ ⤷ bark + 6 ┊ 4.17% ┊ func[4] + 5 ┊ 3.47% ┊ ⤷ awoo diff --git a/twiggy/tests/tests.rs b/twiggy/tests/tests.rs index d0a06c6e..fb009c3f 100644 --- a/twiggy/tests/tests.rs +++ b/twiggy/tests/tests.rs @@ -148,6 +148,14 @@ test!( "hello" ); +test!( + dominators_regex_any_func, + "dominators", + "./fixtures/paths_test.wasm", + "--regex", + "func\\[[0-9]+\\]" +); + test!( paths_test_called_once, "paths",