Skip to content

Commit

Permalink
Merge japaric#90
Browse files Browse the repository at this point in the history
90: Add alternative top-like output r=japaric a=Dirbaio

Depends on japaric#89 

Add ability to print a sorted list of functions consuming the most stack, useful for pinpointing and iterating when profiling applications.

Example output:

```
Usage Function
19824 application::main::{{closure}}
2424 embassy_executor::raw::TaskStorage<F>::poll::h6b938d2b456dfec1
2360 application::rpc::server::Server::handle::{{closure}}::{{closure}}
1320 application::config::Config::get::{{closure}}
1040 embassy_executor::raw::TaskStorage<F>::poll::h4780acebd67af819
840 embassy_executor::raw::TaskStorage<F>::poll::h58c2a8bfea77ac49
832 apollo::noise::consume_initiation
832 apollo::stack::Stack::link_received
824 apollo::noise::create_initiation
688 apollo::stack::StackInner::dispatch
680 apollo::noise::decrypt
648 embassy_executor::raw::TaskStorage<F>::poll::h7b94bb28295786aa
616 apollo::noise::encrypt
576 embassy_executor::raw::TaskStorage<F>::poll::h858b811614c343cb
512 application::time::sync::{{closure}}
...
```

Credits go to `@lulf` , all I did is rebase it.

Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Co-authored-by: Ulf Lilleengen <lulf@redhat.com>
  • Loading branch information
3 people authored Feb 27, 2023
2 parents fb3ee76 + d249705 commit 1fb185b
Showing 1 changed file with 63 additions and 3 deletions.
66 changes: 63 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::{
use anyhow::{anyhow, bail};
use ar::Archive;
use cargo_project::{Artifact, Profile, Project};
use clap::Parser;
use clap::{Parser, ValueEnum};
use env_logger::{Builder, Env};
use filetime::FileTime;
use log::{error, warn};
Expand All @@ -41,6 +41,12 @@ mod ir;
mod thumb;
mod wrapper;

#[derive(ValueEnum, PartialEq, Debug, Clone, Copy)]
enum OutputFormat {
Dot,
Top,
}

/// Generate a call graph and perform whole program stack usage analysis
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
Expand Down Expand Up @@ -69,6 +75,10 @@ struct Args {
#[arg(short, long)]
verbose: bool,

/// Output format
#[arg(long, default_value = "dot")]
format: OutputFormat,

/// consider only the call graph that starts from this node
start: Option<String>,
}
Expand Down Expand Up @@ -1193,7 +1203,10 @@ fn run() -> anyhow::Result<i32> {
}
}

dot(g, &cycles)?;
match args.format {
OutputFormat::Dot => dot(g, &cycles)?,
OutputFormat::Top => top(g)?,
}

Ok(0)
}
Expand Down Expand Up @@ -1252,7 +1265,54 @@ fn dot(g: Graph<Node, ()>, cycles: &[Vec<NodeIndex>]) -> io::Result<()> {
writeln!(stdout, "}}")
}

struct Escaper<W>
pub(crate) fn top(g: Graph<Node, ()>) -> io::Result<()> {
let stdout = io::stdout();
let mut stdout = stdout.lock();

assert!(g.is_directed());

let mut nodes: Vec<Node> = Vec::new();
for node in g.raw_nodes().iter() {
nodes.push(node.weight.clone());
}

// Locate max
if let Some(max) = max_of(nodes.iter().map(|n| n.max.unwrap_or(Max::Exact(0)))) {
writeln!(
stdout,
"{} MAX",
match max {
Max::Exact(n) => n,
Max::LowerBound(n) => n,
}
)?;
}

writeln!(stdout, "Usage Function")?;

nodes.sort_by(|a, b| {
let a: u64 = if let Local::Exact(n) = a.local { n } else { 0 };
let b: u64 = if let Local::Exact(n) = b.local { n } else { 0 };
b.cmp(&a)
});

for node in nodes.iter() {
let name = rustc_demangle::demangle(&node.name);
let val: u64 = if let Local::Exact(n) = node.local {
n
} else {
0
};
write!(stdout, "{} ", val)?;

let mut escaper = Escaper::new(&mut stdout);
writeln!(escaper, "{}", name).ok();
escaper.error?;
}
Ok(())
}

pub(crate) struct Escaper<W>
where
W: io::Write,
{
Expand Down

0 comments on commit 1fb185b

Please sign in to comment.