Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a --files option to analyse rustc's --emit=llvm-lines output. #32

Merged
merged 1 commit into from
Oct 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ rustc-demangle = "0.1"
tempdir = "0.3"
structopt = "0.3.8"
clap = { version = "2.32.0", features = ["wrap_help"] }
glob = "0.3.0"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
55 changes: 46 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use std::process::{self, Command, Stdio};
use std::str::FromStr;
use structopt::StructOpt;
use tempdir::TempDir;
use glob::glob;

const ABOUT: &str = "
Print amount of lines of LLVM IR that is generated for the current project.
Expand Down Expand Up @@ -50,6 +51,17 @@ enum Opt {
)]
sort: SortOrder,

/// Analyze .ll files that were produced by eg. `RUSTFLAGS="--emit=llvm-ir" ./x.py build --stage 0 compiler/rustc`.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should mention that it ignores files that don't end in .ll, I would not expect that behavior. Maybe it shouldn't ignore them?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in #33 to not ignore any files.

/// Supports globs, eg `./build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/debug/deps/*.ll`
Comment on lines +54 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably a little more complicated of an example than you need to give in public docs. It's better suited for rustc-dev-guide IMO.

Suggested change
/// Analyze .ll files that were produced by eg. `RUSTFLAGS="--emit=llvm-ir" ./x.py build --stage 0 compiler/rustc`.
/// Supports globs, eg `./build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/debug/deps/*.ll`
/// Analyze .ll files produced by `RUSTFLAGS="--emit=llvm-ir"`.
///
/// Supports globs, e.g. `./build/debug/deps/*.ll`

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in #33.

// zsh substitutes the glob with a list of files, therefore this needs to be a Vec.
Copy link

@jyn514 jyn514 Oct 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to both support globs and multiple files? It seems easier to let the shell expand the glob instead (and means less dependencies for llvm-lines).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in #33 to leave globbing to the shell.

#[structopt(short, long, value_name = "FILES")]
files: Vec<String>,

// Run in a different mode that just filters some Cargo output and does
// nothing else.
#[structopt(long, hidden = true)]
filter_cargo: bool,

// All these options are passed through to the `rustc` invocation.
#[structopt(short, long, value_name = "SPEC")]
package: Option<String>,
Expand All @@ -71,20 +83,28 @@ enum Opt {
no_default_features: bool,
#[structopt(long, value_name = "PATH")]
manifest_path: Option<String>,

// Run in a different mode that just filters some Cargo output and does
// nothing else.
#[structopt(long, hidden = true)]
filter_cargo: bool,
},
}

fn main() {
let Opt::LLVMLines {
filter_cargo, sort, ..
filter_cargo, sort, files, ..
} = Opt::from_args();

let result = cargo_llvm_lines(filter_cargo, sort);
let result = if files.len() > 0 {
// read llvm-lines from files
let content = read_llvm_ir_from_glob(&files);
match content {
Ok(ir) => {
count_lines(ir, sort);
Ok(0)
},
Err(err) => Err(err)
}
} else {
// run cargo to get llvm-lines
cargo_llvm_lines(filter_cargo, sort)
};

process::exit(match result {
Ok(code) => code,
Expand All @@ -110,7 +130,7 @@ fn cargo_llvm_lines(filter_cargo: bool, sort_order: SortOrder) -> io::Result<i32
return Ok(exit);
}

let ir = read_llvm_ir(outdir)?;
let ir = read_llvm_ir_from_dir(outdir)?;
count_lines(ir, sort_order);

Ok(0)
Expand Down Expand Up @@ -157,7 +177,7 @@ fn run_cargo_rustc(outfile: PathBuf) -> io::Result<i32> {
child.wait().map(|status| status.code().unwrap_or(1))
}

fn read_llvm_ir(outdir: TempDir) -> io::Result<String> {
fn read_llvm_ir_from_dir(outdir: TempDir) -> io::Result<String> {
for file in fs::read_dir(&outdir)? {
let path = file?.path();
if let Some(ext) = path.extension() {
Expand All @@ -173,6 +193,23 @@ fn read_llvm_ir(outdir: TempDir) -> io::Result<String> {
Err(io::Error::new(ErrorKind::Other, msg))
}

fn read_llvm_ir_from_glob(globs: &Vec<String>) -> io::Result<String> {
// This loads all files into RAM (4.1GB in the case of rustc),
// but it only takes seconds, so no need to optimize that.
let mut content = String::new();
for file_glob in globs {
for entry in glob(file_glob).expect(&format!("Failed to read glob pattern '{}'", file_glob)) {
let path = entry.map_err(|err| io::Error::new(ErrorKind::Other, err))?;
if let Some(ext) = path.extension() {
if ext == "ll" {
File::open(&path)?.read_to_string(&mut content)?;
}
}
}
}
Ok(content)
}

#[derive(Default)]
struct Instantiations {
copies: usize,
Expand Down