#[macro_use]
extern crate lazy_static;
extern crate clap;
extern crate regex;
pub mod profiler;
pub mod parse;
pub mod display;
pub mod err;
pub mod argparse;
pub mod cargo;
use clap::{Arg, App, SubCommand, AppSettings};
use profiler::Profiler;
use parse::callgrind::CallGrindParser;
use parse::cachegrind::CacheGrindParser;
use std::process::Command;
use err::ProfError;
use argparse::{get_profiler, get_binary, get_num, get_sort_metric};
use cargo::build_binary;
use std::process;
use std::ffi::OsStr;
macro_rules! try_or_exit {
($e:expr) => (match $e { Ok(e) => e, Err(e) => {println!("{}",e); process::exit(1);} })
}
fn main() {
let _ = real_main();
}
#[cfg(unix)]
fn real_main() -> Result<(), ProfError> {
let binary_arg = Arg::with_name("binary")
.long("bin")
.value_name("BINARY")
.required(false)
.help("binary you want to profile");
let binargs_arg = Arg::with_name("binargs")
.multiple(true)
.value_name("BIN_ARGS")
.required(false)
.help("arguments to the binary when executed");
let release = Arg::with_name("release")
.long("release")
.required(false)
.help("whether binary should be built in release mode");
let fn_count_arg = Arg::with_name("n")
.short("n")
.value_name("NUMBER")
.takes_value(true)
.help("number of functions you want");
let sort_arg = Arg::with_name("sort")
.long("sort")
.value_name("SORT")
.takes_value(true)
.help("metric you want to sort by");
let callgrind = SubCommand::with_name("callgrind")
.about("gets callgrind features")
.version("1.0")
.author("Suchin Gururangan")
.arg(release.clone())
.arg(binary_arg.clone())
.arg(binargs_arg.clone())
.arg(fn_count_arg.clone());
let cachegrind = SubCommand::with_name("cachegrind")
.about("gets cachegrind features")
.version("1.0")
.author("Suchin Gururangan")
.arg(release)
.arg(binary_arg)
.arg(binargs_arg.clone())
.arg(fn_count_arg)
.arg(sort_arg);
let profiler = SubCommand::with_name("profiler")
.about("gets callgrind features")
.version("1.0")
.author("Suchin Gururangan")
.subcommand(callgrind)
.subcommand(cachegrind);
let matches = App::new("cargo-profiler")
.bin_name("cargo")
.settings(&[AppSettings::SubcommandRequired])
.version("1.0")
.author("Suchin Gururangan")
.about("Profile your binaries")
.subcommand(profiler)
.get_matches();
let (m, profiler) = try_or_exit!(get_profiler(&matches));
let binary = {
if m.is_present("binary") {
try_or_exit!(get_binary(&m)).to_string()
} else {
if m.is_present("release") {
try_or_exit!(build_binary(true))
} else {
try_or_exit!(build_binary(false))
}
}
};
let binary_name = binary.split("/").collect::<Vec<&str>>().pop().unwrap_or("");
let binargs: Vec<&OsStr> = match matches.values_of_os("binargs") {
None => vec!(),
Some(raw) => raw.collect(),
};
let num = try_or_exit!(get_num(&m));
let sort_metric = try_or_exit!(get_sort_metric(&m));
match profiler {
Profiler::CallGrind { .. } => {
println!("\n\x1b[1;33mProfiling \x1b[1;0m{} \x1b[0mwith callgrind\x1b[0m...",
binary_name)
}
Profiler::CacheGrind { .. } => {
println!("\n\x1b[1;33mProfiling \x1b[1;0m{} \x1b[0mwith cachegrind\x1b[0m...",
binary_name)
}
};
let output = match profiler {
Profiler::CallGrind { .. } => try!(profiler.callgrind_cli(&binary, &binargs)),
Profiler::CacheGrind { .. } => try!(profiler.cachegrind_cli(&binary, &binargs)),
};
let parsed = match profiler {
Profiler::CallGrind { .. } => try_or_exit!(profiler.callgrind_parse(&output, num)),
Profiler::CacheGrind { .. } => {
try_or_exit!(profiler.cachegrind_parse(&output, num, sort_metric))
}
};
println!("{}", parsed);
try!(Command::new("rm")
.arg("cachegrind.out")
.output());
try!(Command::new("rm")
.arg("callgrind.out")
.output());
Ok(())
}