Skip to content

Commit

Permalink
Merge pull request #94 from data-pup/add-top-summary
Browse files Browse the repository at this point in the history
Added summary and total rows to top command.
  • Loading branch information
fitzgen authored Jul 24, 2018
2 parents 8773b06 + 4ef7532 commit a74b58a
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 27 deletions.
129 changes: 109 additions & 20 deletions analyze/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,35 +126,120 @@ struct Top {
impl traits::Emit for Top {
#[cfg(feature = "emit_text")]
fn emit_text(&self, items: &ir::Items, dest: &mut io::Write) -> Result<(), traits::Error> {
let sort_label = if self.opts.retained() {
"Retained"
} else {
"Shallow"
// A struct used to represent a row in the table that will be emitted.
struct TableRow {
size: u32,
size_percent: f64,
name: String,
};

// Helper function used to process an item, and return a struct
// representing a row containing its size and name.
fn process_item(id: ir::Id, items: &ir::Items, retained: bool) -> TableRow {
let item = &items[id];
let size = if retained {
items.retained_size(id)
} else {
item.size()
};
let size_percent = (f64::from(size)) / (f64::from(items.size())) * 100.0;
let name = item.name().to_string();
TableRow {
size,
size_percent,
name,
}
};

// Helper function used to summnarize a sequence of table rows. This is
// used to generate the remaining summary and total rows. Returns a tuple
// containing the total size, total size percentage, and number of items.
fn summarize_rows(rows: impl Iterator<Item = TableRow>) -> (u32, f64, u32) {
rows.fold(
(0, 0.0, 0),
|(total_size, total_percent, remaining_count),
TableRow {
size,
size_percent,
name: _,
}| {
(
total_size + size,
total_percent + size_percent,
remaining_count + 1,
)
},
)
}

// Access the options that are relevant to emitting the correct output.
let max_items = self.opts.max_items() as usize;
let retained = self.opts.retained();
let sort_label = if retained { "Retained" } else { "Shallow" };

// Initialize a new table.
let mut table = Table::with_header(vec![
(Align::Right, format!("{} Bytes", sort_label)),
(Align::Right, format!("{} %", sort_label)),
(Align::Left, "Item".to_string()),
]);

for &id in &self.items {
let item = &items[id];
// Process the number of items specified, and add them to the table.
self.items
.iter()
.take(max_items)
.map(|&id| process_item(id, items, retained))
.for_each(
|TableRow {
size,
size_percent,
name,
}| {
table.add_row(vec![
size.to_string(),
format!("{:.2}%", size_percent),
name,
])
},
);

let size = if self.opts.retained() {
items.retained_size(id)
// Find the summary statistics by processing the remaining items.
let remaining_rows = self
.items
.iter()
.skip(max_items)
.map(|&id| process_item(id, items, retained));
let (rem_size, rem_size_percent, rem_count) = summarize_rows(remaining_rows);

// If there were items remaining, add a summary row to the table.
if rem_count > 0 {
let rem_name_col = format!("... and {} more.", rem_count);
let (rem_size_col, rem_size_percent_col) = if retained {
("...".to_string(), "...".to_string())
} else {
item.size()
(rem_size.to_string(), format!("{:.2}%", rem_size_percent))
};

let size_percent = (f64::from(size)) / (f64::from(items.size())) * 100.0;
table.add_row(vec![
size.to_string(),
format!("{:.2}%", size_percent),
item.name().to_string(),
]);
table.add_row(vec![rem_size_col, rem_size_percent_col, rem_name_col]);
}

// Add a row containing the totals to the table.
let all_rows = self
.items
.iter()
.map(|&id| process_item(id, items, retained));
let (total_size, total_size_percent, total_count) = summarize_rows(all_rows);
let total_name_col = format!("Ξ£ [{} Total Rows]", total_count);
let (total_size_col, total_size_percent_col) = if retained {
("...".to_string(), "...".to_string())
} else {
(
total_size.to_string(),
format!("{:.2}%", total_size_percent),
)
};
table.add_row(vec![total_size_col, total_size_percent_col, total_name_col]);

// Write the generated table out to the destination and return.
write!(dest, "{}", &table)?;
Ok(())
}
Expand All @@ -163,7 +248,10 @@ impl traits::Emit for Top {
fn emit_json(&self, items: &ir::Items, dest: &mut io::Write) -> Result<(), traits::Error> {
let mut arr = json::array(dest)?;

for &id in &self.items {
let max_items = self.opts.max_items() as usize;
let items_iter = self.items.iter();

for &id in items_iter.take(max_items) {
let item = &items[id];

let mut obj = arr.object()?;
Expand Down Expand Up @@ -199,7 +287,10 @@ impl traits::Emit for Top {
retained_size_percent: Option<f64>,
}

for &id in &self.items {
let max_items = self.opts.max_items() as usize;
let items_iter = self.items.iter();

for &id in items_iter.take(max_items) {
let item = &items[id];

let (shallow_size, shallow_size_percent) = {
Expand Down Expand Up @@ -252,8 +343,6 @@ pub fn top(items: &mut ir::Items, opts: &opt::Top) -> Result<Box<traits::Emit>,
.cmp(&items.retained_size(a.id())),
});

top_items.truncate(opts.number() as usize);

let top_items: Vec<_> = top_items.into_iter().map(|i| i.id()).collect();

let top = Top {
Expand Down
31 changes: 24 additions & 7 deletions opt/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub enum Options {
}

/// List the top code size offenders in a binary.
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
#[derive(StructOpt)]
#[wasm_bindgen]
pub struct Top {
Expand All @@ -63,8 +63,8 @@ pub struct Top {
output_format: traits::OutputFormat,

/// The maximum number of items to display.
#[structopt(short = "n")]
number: Option<u32>,
#[structopt(short = "n", default_value = "4294967295")]
max_items: u32,

/// Display retaining paths.
#[structopt(short = "r", long = "retaining-paths")]
Expand All @@ -75,6 +75,23 @@ pub struct Top {
retained: bool,
}

impl Default for Top {
fn default() -> Top {
Top {
#[cfg(feature = "cli")]
input: Default::default(),
#[cfg(feature = "cli")]
output_destination: Default::default(),
#[cfg(feature = "cli")]
output_format: Default::default(),

max_items: 4294967295,
retaining_paths: false,
retained: false,
}
}
}

#[wasm_bindgen]
impl Top {
/// Construct a new, default `Top`.
Expand All @@ -83,8 +100,8 @@ impl Top {
}

/// The maximum number of items to display.
pub fn number(&self) -> u32 {
self.number.unwrap_or(u32::MAX)
pub fn max_items(&self) -> u32 {
self.max_items
}

/// Display retaining paths.
Expand All @@ -98,8 +115,8 @@ impl Top {
}

/// Set the maximum number of items to display.
pub fn set_number(&mut self, n: u32) {
self.number = Some(n);
pub fn set_max_items(&mut self, n: u32) {
self.max_items = n;
}

/// Set whether to display and compute retaining paths.
Expand Down
2 changes: 2 additions & 0 deletions twiggy/tests/expectations/elf_top_25_hello_world_rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@
2158 β”Š 0.10% β”Š prof_tdata_destroy_locked
2041 β”Š 0.10% β”Š stats_print_helper
1897 β”Š 0.09% β”Š imemalign
150168 β”Š 7.15% β”Š ... and 753 more.
256639 β”Š 12.23% β”Š Ξ£ [778 Total Rows]
1 change: 1 addition & 0 deletions twiggy/tests/expectations/elf_top_hello_world_rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,3 +778,4 @@
0 β”Š 0.00% β”Š je_prof_boot1
0 β”Š 0.00% β”Š je_prof_boot2
0 β”Š 0.00% β”Š je_malloc_tsd_no_cleanup
256639 β”Š 12.23% β”Š Ξ£ [778 Total Rows]
2 changes: 2 additions & 0 deletions twiggy/tests/expectations/top_mappings
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@
1219 β”Š 2.69% β”Š memset
1217 β”Š 2.69% β”Š __powidf2
1142 β”Š 2.52% β”Š __udivsi3
23762 β”Š 52.53% β”Š ... and 338 more.
45181 β”Š 99.89% β”Š Ξ£ [348 Total Rows]
2 changes: 2 additions & 0 deletions twiggy/tests/expectations/top_retained_mappings
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@
3149 β”Š 6.96% β”Š __powidf2
2722 β”Š 6.02% β”Š func[78]
2721 β”Š 6.02% β”Š __divsf3
... β”Š ... β”Š ... and 338 more.
... β”Š ... β”Š Ξ£ [348 Total Rows]
2 changes: 2 additions & 0 deletions twiggy/tests/expectations/top_retained_wee_alloc
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@
226 β”Š 8.02% β”Š func[3]
225 β”Š 7.99% β”Š wee_alloc::alloc_first_fit::h9a72de3af77ef93f
136 β”Š 4.83% β”Š <wee_alloc::size_classes::SizeClassAllocPolicy<'a> as wee_alloc::AllocPolicy>::new_cell_for_free_list::h3987e3054b8224e6
... β”Š ... β”Š ... and 29 more.
... β”Š ... β”Š Ξ£ [39 Total Rows]
2 changes: 2 additions & 0 deletions twiggy/tests/expectations/top_wee_alloc
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@
44 β”Š 1.56% β”Š goodbye
25 β”Š 0.89% β”Š data[1]
25 β”Š 0.89% β”Š data[2]
117 β”Š 4.15% β”Š ... and 29 more.
2772 β”Š 98.40% β”Š Ξ£ [39 Total Rows]

0 comments on commit a74b58a

Please sign in to comment.