Skip to content

Commit

Permalink
This commit solves #57. The twiggy paths will now print all paths if
Browse files Browse the repository at this point in the history
no arguments are given. In adittion, there is now a descending flag that
can be used to move down rather than up the retaining paths.
  • Loading branch information
data-pup committed May 17, 2018
1 parent 0c08a7c commit 1cbd59f
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 29 deletions.
64 changes: 48 additions & 16 deletions analyze/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,11 @@ impl traits::Emit for Paths {
label.push_str(" ");
}
if depth > 0 {
label.push_str(" ⬑ ");
if opts.descending() {
label.push_str(" ↳ ");
} else {
label.push_str(" ⬑ ");
}
}
label.push_str(item.name());

Expand All @@ -432,12 +436,21 @@ impl traits::Emit for Paths {
]);

seen.insert(id);
for (i, caller) in items.predecessors(id).enumerate() {
if i > 0 {
*paths += 1;

if opts.descending() {
for callee in items.neighbors(id) {
*paths += 1; // FIXUP: Should this be wrapped in a conditional as above?
recursive_callers(items, seen, table, depth + 1, &mut paths, &opts, callee);
}
} else {
for (i, caller) in items.predecessors(id).enumerate() {
if i > 0 {
*paths += 1;
}
recursive_callers(items, seen, table, depth + 1, &mut paths, &opts, caller);
}
recursive_callers(items, seen, table, depth + 1, &mut paths, &opts, caller);
}

seen.remove(&id);
}

Expand Down Expand Up @@ -518,20 +531,39 @@ impl traits::Emit for Paths {

/// Find all retaining paths for the given items.
pub fn paths(items: &mut ir::Items, opts: &opt::Paths) -> Result<Box<traits::Emit>, traits::Error> {
items.compute_predecessors();
if !opts.descending() {
items.compute_predecessors();
}

let mut paths = Paths {
items: Vec::with_capacity(opts.functions().len()),
opts: opts.clone(),
let functions: Vec<ir::Id> = match opts.functions().is_empty() {
true => {
if opts.descending() {
let mut roots: Vec<_> = items
.neighbors(items.meta_root())
.map(|id| &items[id])
.collect();
roots.sort_by(|a, b| b.size().cmp(&a.size()));
roots.into_iter().map(|item| item.id()).collect()
} else {
let mut sorted_items: Vec<_> = items
.iter()
.filter(|item| item.id() != items.meta_root())
.collect();
sorted_items.sort_by(|a, b| b.size().cmp(&a.size()));
sorted_items.iter().map(|item| item.id()).collect()
}
}
false => opts.functions()
.iter()
.filter_map(|s| items.get_item_by_name(s))
.map(|item| item.id())
.collect(),
};

let functions: BTreeSet<_> = opts.functions().iter().map(|s| s.as_str()).collect();

for item in items.iter() {
if functions.contains(item.name()) {
paths.items.push(item.id());
}
}
let paths = Paths {
items: functions,
opts: opts.clone(),
};

Ok(Box::new(paths) as Box<traits::Emit>)
}
Expand Down
16 changes: 16 additions & 0 deletions opt/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ pub struct Paths {
/// The maximum number of paths, regardless of depth in the tree, to display.
#[structopt(short = "r", default_value = "10")]
max_paths: u32,

/// This direction of the path traversal.
#[structopt(long = "descending")]
descending: bool,
}

impl Default for Paths {
Expand All @@ -235,6 +239,7 @@ impl Default for Paths {
functions: Default::default(),
max_depth: 10,
max_paths: 10,
descending: false,
}
}
}
Expand Down Expand Up @@ -271,6 +276,11 @@ impl Paths {
self.max_paths
}

/// The direction in which the call paths are traversed.
pub fn descending(&self) -> bool {
self.descending
}

/// Set the maximum depth to print the paths.
pub fn set_max_depth(&mut self, max_depth: u32) {
self.max_depth = max_depth;
Expand All @@ -280,6 +290,12 @@ impl Paths {
pub fn set_max_paths(&mut self, max_paths: u32) {
self.max_paths = max_paths;
}

/// Set the call path traversal direction.
pub fn set_descending(&mut self, descending: bool) {
self.descending = descending;
}

}

/// List the generic function monomorphizations that are contributing to
Expand Down
7 changes: 7 additions & 0 deletions twiggy/tests/expectations/paths_test_called_once
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Shallow Bytes │ Shallow % │ Retaining Paths
───────────────┼───────────┼────────────────────────────────
5 ┊ 3.47% ┊ calledOnce
┊ ┊ ⬑ func[0]
┊ ┊ ⬑ woof
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
13 changes: 13 additions & 0 deletions twiggy/tests/expectations/paths_test_called_twice
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Shallow Bytes │ Shallow % │ Retaining Paths
───────────────┼───────────┼────────────────────────────────────────
5 ┊ 3.47% ┊ calledTwice
┊ ┊ ⬑ func[1]
┊ ┊ ⬑ bark
┊ ┊ ⬑ func[2]
┊ ┊ ⬑ export "bark"
┊ ┊ ⬑ awoo
┊ ┊ ⬑ func[4]
┊ ┊ ⬑ export "awoo"
┊ ┊ ⬑ woof
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
81 changes: 81 additions & 0 deletions twiggy/tests/expectations/paths_test_default_output
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
Shallow Bytes │ Shallow % │ Retaining Paths
───────────────┼───────────┼────────────────────────────────────────
44 ┊ 30.56% ┊ "function names" subsection
8 ┊ 5.56% ┊ woof
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
7 ┊ 4.86% ┊ export "awoo"
7 ┊ 4.86% ┊ export "bark"
7 ┊ 4.86% ┊ export "woof"
5 ┊ 3.47% ┊ calledOnce
┊ ┊ ⬑ func[0]
┊ ┊ ⬑ woof
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
5 ┊ 3.47% ┊ calledTwice
┊ ┊ ⬑ func[1]
┊ ┊ ⬑ bark
┊ ┊ ⬑ func[2]
┊ ┊ ⬑ export "bark"
┊ ┊ ⬑ awoo
┊ ┊ ⬑ func[4]
┊ ┊ ⬑ export "awoo"
┊ ┊ ⬑ woof
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
5 ┊ 3.47% ┊ bark
┊ ┊ ⬑ func[2]
┊ ┊ ⬑ export "bark"
┊ ┊ ⬑ awoo
┊ ┊ ⬑ func[4]
┊ ┊ ⬑ export "awoo"
5 ┊ 3.47% ┊ awoo
┊ ┊ ⬑ func[4]
┊ ┊ ⬑ export "awoo"
4 ┊ 2.78% ┊ type[0]
┊ ┊ ⬑ func[0]
┊ ┊ ⬑ woof
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
┊ ┊ ⬑ func[1]
┊ ┊ ⬑ bark
┊ ┊ ⬑ func[2]
┊ ┊ ⬑ export "bark"
┊ ┊ ⬑ awoo
┊ ┊ ⬑ func[4]
┊ ┊ ⬑ export "awoo"
┊ ┊ ⬑ woof
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
┊ ┊ ⬑ func[2]
┊ ┊ ⬑ export "bark"
┊ ┊ ⬑ awoo
┊ ┊ ⬑ func[4]
┊ ┊ ⬑ export "awoo"
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
┊ ┊ ⬑ func[4]
┊ ┊ ⬑ export "awoo"
1 ┊ 0.69% ┊ func[0]
┊ ┊ ⬑ woof
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
1 ┊ 0.69% ┊ func[1]
┊ ┊ ⬑ bark
┊ ┊ ⬑ func[2]
┊ ┊ ⬑ export "bark"
┊ ┊ ⬑ awoo
┊ ┊ ⬑ func[4]
┊ ┊ ⬑ export "awoo"
┊ ┊ ⬑ woof
┊ ┊ ⬑ func[3]
┊ ┊ ⬑ export "woof"
1 ┊ 0.69% ┊ func[2]
┊ ┊ ⬑ export "bark"
┊ ┊ ⬑ awoo
┊ ┊ ⬑ func[4]
┊ ┊ ⬑ export "awoo"
1 ┊ 0.69% ┊ func[3]
┊ ┊ ⬑ export "woof"
1 ┊ 0.69% ┊ func[4]
┊ ┊ ⬑ export "awoo"
30 changes: 30 additions & 0 deletions twiggy/tests/expectations/paths_test_default_output_desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Shallow Bytes │ Shallow % │ Retaining Paths
───────────────┼───────────┼──────────────────────────────────────
44 ┊ 30.56% ┊ "function names" subsection
7 ┊ 4.86% ┊ export "awoo"
┊ ┊ ↳ func[4]
┊ ┊ ↳ type[0]
┊ ┊ ↳ awoo
┊ ┊ ↳ func[2]
┊ ┊ ↳ type[0]
┊ ┊ ↳ bark
┊ ┊ ↳ func[1]
┊ ┊ ↳ type[0]
┊ ┊ ↳ calledTwice
7 ┊ 4.86% ┊ export "bark"
┊ ┊ ↳ func[2]
┊ ┊ ↳ type[0]
┊ ┊ ↳ bark
┊ ┊ ↳ func[1]
┊ ┊ ↳ type[0]
┊ ┊ ↳ calledTwice
7 ┊ 4.86% ┊ export "woof"
┊ ┊ ↳ func[3]
┊ ┊ ↳ type[0]
┊ ┊ ↳ woof
┊ ┊ ↳ func[0]
┊ ┊ ↳ type[0]
┊ ┊ ↳ calledOnce
┊ ┊ ↳ func[1]
┊ ┊ ↳ type[0]
┊ ┊ ↳ calledTwice
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Shallow Bytes │ Shallow % │ Retaining Paths
───────────────┼───────────┼────────────────────────────
44 ┊ 30.56% ┊ "function names" subsection
7 ┊ 4.86% ┊ export "awoo"
┊ ┊ ↳ func[4]
┊ ┊ ↳ type[0]
┊ ┊ ↳ awoo
7 ┊ 4.86% ┊ export "bark"
┊ ┊ ↳ func[2]
┊ ┊ ↳ type[0]
┊ ┊ ↳ bark
7 ┊ 4.86% ┊ export "woof"
┊ ┊ ↳ func[3]
┊ ┊ ↳ type[0]
┊ ┊ ↳ woof
File renamed without changes.
Binary file added twiggy/tests/fixtures/paths_test.wasm
Binary file not shown.
50 changes: 50 additions & 0 deletions twiggy/tests/fixtures/paths_test.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
(module
;; ------------------------------------------------------------------------
;; This is a WebAssembly text file that can be compiled in a wasm module to
;; test the `twiggy paths` command. This intends to provide a non-trivial
;; structure of call paths for testing purposes.
;;
;; The call path is shown in the ascii diagram below with exported
;; functions enclosed in braces, and unexported functions in quotes.
;;
;; [awoo]
;; |
;; v
;; [woof] [bark]
;; | | |
;; | -------- |
;; | | |
;; v v v
;; 'calledOnce' 'calledTwice'
;; ------------------------------------------------------------------------
;; NOTE: The test cases expect that this module is compiled with debug
;; names written to the binary file, which affects the size percentages.
;; Compile this file using the following command:
;;
;; wat2wasm --debug-names paths_test.wat -o paths_test.wasm
;; -------------------------------------------------------------------------


;; This function is called once, by 'woof'.
(func $calledOnce (result i32)
i32.const 1)

;; This function is called twice, by 'bark' and 'woof'.
(func $calledTwice (result i32)
i32.const 2)

(func $bark (result i32)
call $calledTwice)

(func $woof (result i32)
call $calledOnce
call $calledTwice
i32.add)

(func $awoo (result i32)
call $bark)

(export "awoo" (func $awoo))
(export "bark" (func $bark))
(export "woof" (func $woof))
)
Loading

0 comments on commit 1cbd59f

Please sign in to comment.