aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAria <me@aria.rip>2023-12-14 21:03:51 +0000
committerAria <me@aria.rip>2023-12-14 21:03:51 +0000
commit5545e09290dee3e1b87454741d1070773390dd15 (patch)
treec15fd6d9c11e16087767e26fa97444a73b67be3d /src
parent3f89609f2ec1ac3863fb4b7220e0f0fed3ffd039 (diff)
feat(cli): reimplement cli bits
Diffstat (limited to 'src')
-rw-r--r--src/crates/candelabra/src/profiler.rs22
-rw-r--r--src/crates/cli/Cargo.toml11
-rw-r--r--src/crates/cli/src/candidates.rs30
-rw-r--r--src/crates/cli/src/library.rs21
-rw-r--r--src/crates/cli/src/main.rs125
-rw-r--r--src/crates/cli/src/model.rs25
-rw-r--r--src/crates/cli/src/profile.rs44
7 files changed, 235 insertions, 43 deletions
diff --git a/src/crates/candelabra/src/profiler.rs b/src/crates/candelabra/src/profiler.rs
index 46acd66..056e812 100644
--- a/src/crates/candelabra/src/profiler.rs
+++ b/src/crates/candelabra/src/profiler.rs
@@ -27,21 +27,21 @@ pub(crate) struct CacheEntry {
/// The information we get from profiling.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
-pub struct ProfilerInfo(Vec<CollectionLifetime>);
+pub struct ProfilerInfo(pub Vec<CollectionLifetime>);
/// Profiler info collected from the lifetime of a single collection instance
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CollectionLifetime {
- n: usize,
- contains: usize,
- insert: usize,
- clear: usize,
- remove: usize,
- first: usize,
- last: usize,
- nth: usize,
- push: usize,
- pop: usize,
+ pub n: usize,
+ pub contains: usize,
+ pub insert: usize,
+ pub clear: usize,
+ pub remove: usize,
+ pub first: usize,
+ pub last: usize,
+ pub nth: usize,
+ pub push: usize,
+ pub pop: usize,
}
impl State {
diff --git a/src/crates/cli/Cargo.toml b/src/crates/cli/Cargo.toml
index c0180ee..95fb5cc 100644
--- a/src/crates/cli/Cargo.toml
+++ b/src/crates/cli/Cargo.toml
@@ -1,9 +1,16 @@
[package]
-name = "cli"
+name = "candelabra-cli"
version = "0.1.0"
edition = "2021"
+default-run = "candelabra-cli"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-candelabra = { path = "../candelabra" } \ No newline at end of file
+candelabra = { path = "../candelabra" }
+log = { workspace = true }
+anyhow = { workspace = true }
+env_logger = { workspace = true }
+argh = { version = "0.1.12" }
+cargo_metadata = "0.18.1"
+tabled = "0.14.0"
diff --git a/src/crates/cli/src/candidates.rs b/src/crates/cli/src/candidates.rs
new file mode 100644
index 0000000..764f45f
--- /dev/null
+++ b/src/crates/cli/src/candidates.rs
@@ -0,0 +1,30 @@
+use anyhow::Result;
+use argh::FromArgs;
+use log::info;
+
+use crate::State;
+
+/// List selection sites and their candidates
+#[derive(FromArgs)]
+#[argh(subcommand, name = "candidates")]
+pub struct Args {}
+
+impl State {
+ pub fn cmd_candidates(&self, _: Args) -> Result<()> {
+ for proj in self.projects.iter() {
+ info!("Processing project {}", &proj.name);
+
+ let candidates = self.inner.project_candidate_list(proj)?;
+ for (file, sites) in candidates {
+ info!("{}:", file);
+ for (name, candidates) in sites {
+ info!(" {}:", name);
+ for candidate in candidates {
+ info!(" {}", candidate);
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+}
diff --git a/src/crates/cli/src/library.rs b/src/crates/cli/src/library.rs
new file mode 100644
index 0000000..7859b0f
--- /dev/null
+++ b/src/crates/cli/src/library.rs
@@ -0,0 +1,21 @@
+use anyhow::Result;
+use argh::FromArgs;
+use log::info;
+
+use crate::State;
+
+/// List all implementations in the library
+#[derive(FromArgs)]
+#[argh(subcommand, name = "list-library")]
+pub struct Args {}
+
+impl State {
+ pub fn cmd_library(&self, _: Args) -> Result<()> {
+ info!("Available container implementations:");
+ for name in self.inner.lib_specs().keys() {
+ info!(" {}", name);
+ }
+
+ Ok(())
+ }
+}
diff --git a/src/crates/cli/src/main.rs b/src/crates/cli/src/main.rs
index 5bd0f34..1633105 100644
--- a/src/crates/cli/src/main.rs
+++ b/src/crates/cli/src/main.rs
@@ -1,32 +1,97 @@
-fn main() {
- println!("Hello, world!");
+use anyhow::{anyhow, Context, Result};
+use argh::FromArgs;
+use candelabra::{Paths, Project};
+use log::info;
+
+mod candidates;
+mod library;
+mod model;
+mod profile;
+
+#[derive(FromArgs)]
+/// Find the best performing container type using primrose
+pub struct Args {
+ /// path to Cargo.toml
+ #[argh(option)]
+ pub manifest_path: Option<String>,
+
+ /// project to run on, if in a workspace
+ #[argh(option, short = 'p')]
+ pub project: Option<String>,
+
+ #[argh(subcommand)]
+ pub cmd: Subcommand,
}
-// fn get_projects(args: &Args) -> Result<Vec<Project>> {
-// let mut cmd = cargo_metadata::MetadataCommand::new();
-// if let Some(p) = &args.manifest_path {
-// cmd.manifest_path(p);
-// }
-
-// let metadata = cmd.exec().context("failed to get manifest metadata")?;
-
-// if let Some(p) = &args.project {
-// // Select a specific project
-// Ok(vec![metadata
-// .packages
-// .iter()
-// .find(|pkg| pkg.name == *p)
-// .map(|pkg| Project::new(pkg.clone()))
-// .ok_or_else(|| {
-// anyhow!("specified project does not exist")
-// })?])
-// } else {
-// // Default to all workspace members
-// Ok(metadata
-// .workspace_members
-// .iter()
-// .flat_map(|member| metadata.packages.iter().find(|pkg| pkg.id == *member))
-// .map(|pkg| Project::new(pkg.clone()))
-// .collect())
-// }
-// }
+#[derive(FromArgs)]
+#[argh(subcommand)]
+pub enum Subcommand {
+ Model(model::Args),
+ Library(library::Args),
+ Candidates(candidates::Args),
+ Profile(profile::Args),
+}
+
+fn main() -> Result<()> {
+ env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
+ let args: Args = argh::from_env();
+
+ // Build shared state
+ let paths = Paths::default();
+ info!("Using source dir: {:?}", &paths.base);
+ let state = State {
+ inner: candelabra::State::new(paths)?,
+ projects: get_projects(&args)?,
+ };
+
+ match args.cmd {
+ Subcommand::Model(a) => state.cmd_model(a),
+ Subcommand::Library(a) => state.cmd_library(a),
+ Subcommand::Candidates(a) => state.cmd_candidates(a),
+ Subcommand::Profile(a) => state.cmd_profile(a),
+ }
+}
+
+struct State {
+ inner: candelabra::State,
+ projects: Vec<Project>,
+}
+
+// #[derive(FromArgs)]
+// /// Show the candidate types selected by primrose
+// #[argh(subcommand, name = "candidates")]
+// pub struct CandidatesSubcommand {}
+
+// #[derive(FromArgs)]
+// /// Show the profiling information generated from benchmarks
+// #[argh(subcommand, name = "profile")]
+// pub struct ProfileSubcommand {}
+
+fn get_projects(args: &Args) -> Result<Vec<Project>> {
+ let mut cmd = cargo_metadata::MetadataCommand::new();
+ if let Some(p) = &args.manifest_path {
+ cmd.manifest_path(p);
+ }
+
+ let metadata = cmd.exec().context("failed to get manifest metadata")?;
+
+ if let Some(p) = &args.project {
+ // Select a specific project
+ Ok(vec![metadata
+ .packages
+ .iter()
+ .find(|pkg| pkg.name == *p)
+ .map(|pkg| Project::new(pkg.clone()))
+ .ok_or_else(|| {
+ anyhow!("specified project does not exist")
+ })?])
+ } else {
+ // Default to all workspace members
+ Ok(metadata
+ .workspace_members
+ .iter()
+ .flat_map(|member| metadata.packages.iter().find(|pkg| pkg.id == *member))
+ .map(|pkg| Project::new(pkg.clone()))
+ .collect())
+ }
+}
diff --git a/src/crates/cli/src/model.rs b/src/crates/cli/src/model.rs
new file mode 100644
index 0000000..58f0639
--- /dev/null
+++ b/src/crates/cli/src/model.rs
@@ -0,0 +1,25 @@
+use anyhow::Result;
+use argh::FromArgs;
+use log::info;
+
+use crate::State;
+
+/// Show the cost model for the given implementation
+#[derive(FromArgs)]
+#[argh(subcommand, name = "cost-model")]
+pub struct Args {
+ /// the implementation to get the cost model of.
+ #[argh(positional)]
+ name: String,
+}
+
+impl State {
+ pub fn cmd_model(&self, args: Args) -> Result<()> {
+ info!("Calculating cost model for {}", &args.name);
+ let model = self.inner.cost_model(&args.name)?;
+
+ dbg!(model);
+
+ Ok(())
+ }
+}
diff --git a/src/crates/cli/src/profile.rs b/src/crates/cli/src/profile.rs
new file mode 100644
index 0000000..2f8b21b
--- /dev/null
+++ b/src/crates/cli/src/profile.rs
@@ -0,0 +1,44 @@
+use anyhow::Result;
+use argh::FromArgs;
+use candelabra::profiler::ProfilerInfo;
+use log::info;
+use tabled::{builder::Builder, settings::Style, Table, Tabled};
+
+use crate::State;
+
+/// Profile the selected projects and print the results
+#[derive(FromArgs)]
+#[argh(subcommand, name = "profile")]
+pub struct Args {}
+
+impl State {
+ pub fn cmd_profile(&self, _: Args) -> Result<()> {
+ for proj in self.projects.iter() {
+ info!("Processing project {}", &proj.name);
+
+ let info = self.inner.profiler_info(proj)?;
+
+ let mut builder = Builder::default();
+ builder.set_header([
+ "N (cum.)", "contains", "insert", "clear", "remove", "first", "last", "nth",
+ "push", "pop",
+ ]);
+ for info in info.0.iter() {
+ builder.push_record([
+ info.n.to_string(),
+ info.contains.to_string(),
+ info.insert.to_string(),
+ info.clear.to_string(),
+ info.remove.to_string(),
+ info.first.to_string(),
+ info.last.to_string(),
+ info.nth.to_string(),
+ info.push.to_string(),
+ info.pop.to_string(),
+ ]);
+ }
+ println!("{}", builder.build().with(Style::sharp()));
+ }
+ Ok(())
+ }
+}