aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAria <me@aria.rip>2023-12-14 18:42:24 +0000
committerAria <me@aria.rip>2023-12-14 18:42:24 +0000
commit9da1961a33b20cc64d920ae82f6cc49c42d0c728 (patch)
tree6429afb84eaa09e2029fea1e161e64378cf7db74
parent965e64e8436b24c8523b738ceac84c5a5599d100 (diff)
refactor(candelabra): split cli, reduce duplication
introduce an invalidation function to the cache helper to get rid of repetitive code split cli and candelabra out to separate crates move most top-level operations into the State struct
-rw-r--r--src/Cargo.toml5
-rw-r--r--src/crates/candelabra/Cargo.toml19
-rw-r--r--src/crates/candelabra/src/cache.rs (renamed from src/crates/cli/src/cache.rs)29
-rw-r--r--src/crates/candelabra/src/candidates.rs116
-rw-r--r--src/crates/candelabra/src/cost/benchmark.rs (renamed from src/crates/cli/src/cost/benchmark.rs)0
-rw-r--r--src/crates/candelabra/src/cost/fit.rs (renamed from src/crates/cli/src/cost/fit.rs)2
-rw-r--r--src/crates/candelabra/src/cost/mod.rs (renamed from src/crates/cli/src/cost/mod.rs)80
-rw-r--r--src/crates/candelabra/src/lib.rs41
-rw-r--r--src/crates/candelabra/src/paths.rs (renamed from src/crates/cli/src/paths.rs)6
-rw-r--r--src/crates/candelabra/src/profiler.rs (renamed from src/crates/cli/src/profiler/mod.rs)25
-rw-r--r--src/crates/candelabra/src/project.rs (renamed from src/crates/cli/src/project.rs)0
-rw-r--r--src/crates/cli/Cargo.toml17
-rw-r--r--src/crates/cli/src/candidates.rs136
-rw-r--r--src/crates/cli/src/cmd.rs39
-rw-r--r--src/crates/cli/src/main.rs143
15 files changed, 293 insertions, 365 deletions
diff --git a/src/Cargo.toml b/src/Cargo.toml
index d3658ac..3b0a7ba 100644
--- a/src/Cargo.toml
+++ b/src/Cargo.toml
@@ -3,8 +3,9 @@ resolver = "2"
members = [
"crates/primrose",
"crates/library",
- "crates/cli",
- "crates/benchmarker"
+ "crates/benchmarker",
+ "crates/candelabra",
+ "crates/cli"
]
[workspace.dependencies]
diff --git a/src/crates/candelabra/Cargo.toml b/src/crates/candelabra/Cargo.toml
new file mode 100644
index 0000000..909e577
--- /dev/null
+++ b/src/crates/candelabra/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "candelabra"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+log = { workspace = true }
+primrose = { path = "../primrose" }
+anyhow = { workspace = true }
+serde = { workspace = true }
+serde_json = { workspace = true }
+camino = "1.1.6"
+cargo_metadata = "0.18.1"
+glob = "0.3.1"
+tempfile = "3"
+nalgebra = "0.32.3"
+polars = { version = "0.35.4", features = ["describe"] }
diff --git a/src/crates/cli/src/cache.rs b/src/crates/candelabra/src/cache.rs
index 4775a0f..424b2e7 100644
--- a/src/crates/cli/src/cache.rs
+++ b/src/crates/candelabra/src/cache.rs
@@ -1,12 +1,13 @@
//! Common utilities for caching results
use std::{
+ cell::RefCell,
collections::hash_map::DefaultHasher,
fs::{create_dir_all, metadata, remove_file, File},
hash::{Hash, Hasher},
marker::PhantomData,
};
-use anyhow::{Context, Result};
+use anyhow::{anyhow, Context, Result};
use camino::{Utf8Path, Utf8PathBuf};
use glob::glob;
use log::{debug, warn};
@@ -15,23 +16,28 @@ use serde_json::{from_reader, to_writer};
/// A filesystem-based K/V cache
/// This doesn't deal with key invalidation or anything, just the filesystem/serialisation stuff
-pub struct FileCache<K: 'static + ?Sized, V, VR = V> {
+pub struct FileCache<K: 'static + ?Sized, V> {
base_dir: Utf8PathBuf,
- _data: PhantomData<(&'static K, V, VR)>,
+ validator: RefCell<Box<dyn FnMut(&K, &V) -> bool>>,
+ _data: PhantomData<(&'static K, V, V)>,
}
-impl<K: ?Sized + ToString, V: for<'a> Deserialize<'a>, VR: Serialize> FileCache<K, V, VR> {
+impl<K: ?Sized + ToString, V: Serialize + for<'a> Deserialize<'a>> FileCache<K, V> {
/// Create a new file store in the given directory.
- pub fn new(base_dir: Utf8PathBuf) -> Result<Self> {
+ pub fn new(
+ base_dir: Utf8PathBuf,
+ validator: impl FnMut(&K, &V) -> bool + 'static,
+ ) -> Result<Self> {
create_dir_all(base_dir.as_std_path()).context("Error creating cache directory")?;
Ok(Self {
base_dir,
+ validator: RefCell::new(Box::new(validator)),
_data: PhantomData,
})
}
/// Store the given value with the given `key`
- pub fn put(&self, key: &K, value: &VR) -> Result<()> {
+ pub fn put(&self, key: &K, value: &V) -> Result<()> {
let path = self.path_for(key);
let mut file = File::create(path)?;
to_writer(&mut file, value)?;
@@ -49,7 +55,7 @@ impl<K: ?Sized + ToString, V: for<'a> Deserialize<'a>, VR: Serialize> FileCache<
}
let file = File::open(&path).context("Error opening cache entry")?;
- let contents: V = match from_reader(file) {
+ let contents: V = match self.attempt_load(key, &file) {
Ok(x) => x,
Err(e) => {
debug!("Invalid cache entry: {}", e);
@@ -64,6 +70,15 @@ impl<K: ?Sized + ToString, V: for<'a> Deserialize<'a>, VR: Serialize> FileCache<
Ok(Some(contents))
}
+ fn attempt_load(&self, key: &K, f: &File) -> Result<V> {
+ let c = from_reader(f)?;
+ if (self.validator.borrow_mut())(key, &c) {
+ Ok(c)
+ } else {
+ Err(anyhow!("validation function said no"))
+ }
+ }
+
/// Remove value for the given key
pub fn remove(&self, key: &K) -> Result<()> {
Ok(remove_file(self.path_for(key))?)
diff --git a/src/crates/candelabra/src/candidates.rs b/src/crates/candelabra/src/candidates.rs
new file mode 100644
index 0000000..0d76862
--- /dev/null
+++ b/src/crates/candelabra/src/candidates.rs
@@ -0,0 +1,116 @@
+//! Generating and caching primrose candidate results
+
+use std::{collections::HashMap, fs::metadata, time::SystemTime};
+
+use anyhow::{Context, Result};
+use camino::{Utf8Path, Utf8PathBuf};
+use log::{debug, warn};
+use primrose::ContainerSelector;
+use serde::{Deserialize, Serialize};
+
+use crate::{
+ cache::{gen_tree_hash, FileCache},
+ paths::Paths,
+ project::Project,
+ State,
+};
+
+/// Names a container type we want to select.
+pub type ConTypeName = String;
+
+/// Name of a container implementation we are considering
+pub type ImplName = String;
+
+/// A list of candidate container types
+pub type Candidates = HashMap<ConTypeName, Vec<ImplName>>;
+
+/// A list of candidates for each selection site, and each file in a given project
+pub type ProjectCandidateList = Vec<(Utf8PathBuf, Vec<(ConTypeName, Vec<ImplName>)>)>;
+
+/// Info for getting & caching candidate types
+pub struct CandidatesStore {
+ pub store: FileCache<Utf8Path, CacheEntry>,
+ pub lib_hash: u64,
+}
+
+/// Entry in the benchmark cache
+#[derive(Serialize, Deserialize, Debug)]
+pub struct CacheEntry {
+ lib_hash: u64,
+ mod_time: SystemTime,
+ value: Candidates,
+}
+
+impl CandidatesStore {
+ /// Create a new store, using the given paths.
+ /// Benchmarks are cached in `paths.target_dir / candelabra / primrose_results`
+ pub fn new(paths: &Paths) -> Result<Self> {
+ let base_dir = paths.target_dir.join("candelabra").join("primrose_results");
+
+ let lib_hash =
+ gen_tree_hash(&paths.library_crate).context("Error generating library hash")?;
+ debug!("Initialised candidate cacher with hash {}", lib_hash);
+
+ Ok(Self {
+ store: FileCache::new(base_dir, move |k, v: &CacheEntry| {
+ let mod_time = metadata(k)
+ .map(|m| m.modified())
+ .unwrap_or(Ok(SystemTime::UNIX_EPOCH))
+ .unwrap();
+ v.lib_hash == lib_hash && v.mod_time == mod_time
+ })?,
+ lib_hash,
+ })
+ }
+}
+
+impl State {
+ /// Run primrose on all files in the given project.
+ /// Returns a list of all candidates for each container type in each file.
+ pub fn project_candidate_list(&self, project: &Project) -> Result<ProjectCandidateList> {
+ let mut all_candidates = Vec::new();
+ for file in project.find_primrose_files()? {
+ let result = match self.candidates.store.find(&file)? {
+ Some(x) => x.value,
+ None => self.calc_candidates(&file)?,
+ };
+
+ let mut typs = Vec::new();
+ for (con_type_id, candidates) in result {
+ typs.push((con_type_id.clone(), candidates));
+ }
+ all_candidates.push((file, typs));
+ }
+
+ Ok(all_candidates)
+ }
+
+ /// Find candidate types for every selection site in a given path
+ fn calc_candidates(&self, path: &Utf8Path) -> Result<Candidates> {
+ let selector = ContainerSelector::from_path(
+ path.as_std_path(),
+ self.paths.library_src.as_std_path(),
+ self.model_size,
+ )
+ .with_context(|| format!("error getting container selector for {}", path))?;
+
+ let candidates: Candidates = selector
+ .find_all_candidates()?
+ .into_iter()
+ .map(|(k, v)| (k.to_string(), v))
+ .collect();
+
+ let mod_time = metadata(path)?.modified()?;
+ if let Err(e) = self.candidates.store.put(
+ path,
+ &CacheEntry {
+ lib_hash: self.candidates.lib_hash,
+ value: candidates.clone(),
+ mod_time,
+ },
+ ) {
+ warn!("Error caching candidates for {}: {}", path, e);
+ }
+ Ok(candidates)
+ }
+}
diff --git a/src/crates/cli/src/cost/benchmark.rs b/src/crates/candelabra/src/cost/benchmark.rs
index a1e0e18..a1e0e18 100644
--- a/src/crates/cli/src/cost/benchmark.rs
+++ b/src/crates/candelabra/src/cost/benchmark.rs
diff --git a/src/crates/cli/src/cost/fit.rs b/src/crates/candelabra/src/cost/fit.rs
index f4372f1..ace3634 100644
--- a/src/crates/cli/src/cost/fit.rs
+++ b/src/crates/candelabra/src/cost/fit.rs
@@ -1,5 +1,5 @@
//! Fitting a 3rd-order polynomial to benchmark results
-//! Based on code from al-jshen: https://github.com/al-jshen/compute/tree/master
+//! Based on code from al-jshen: <https://github.com/al-jshen/compute/tree/master>
use super::benchmark::Observation;
use na::{Dyn, MatrixXx4, OVector};
diff --git a/src/crates/cli/src/cost/mod.rs b/src/crates/candelabra/src/cost/mod.rs
index f3cad13..18bcb79 100644
--- a/src/crates/cli/src/cost/mod.rs
+++ b/src/crates/candelabra/src/cost/mod.rs
@@ -1,6 +1,9 @@
//! Generating, caching, and using cost models
-pub mod benchmark;
-pub mod fit;
+mod benchmark;
+mod fit;
+
+pub use benchmark::{BenchmarkResult, Results as BenchmarkResults};
+pub use fit::Estimator;
use std::collections::HashMap;
@@ -11,11 +14,11 @@ use log::{debug, warn};
use primrose::{LibSpec, LibSpecs};
use serde::{Deserialize, Serialize};
-use self::fit::Estimator;
use crate::{
cache::{gen_tree_hash, FileCache},
cost::benchmark::run_benchmarks,
paths::Paths,
+ State,
};
/// Cost model for a container, capable of estimating cost of each supported operation.
@@ -24,21 +27,24 @@ pub struct CostModel {
by_op: HashMap<String, Estimator>,
}
-/// Entry in the benchmark cache
+/// Information for getting & caching cost information for container implementations.
+pub struct ResultsStore {
+ store: FileCache<str, CacheEntry>,
+ lib_specs: LibSpecs,
+ lib_hash: u64,
+}
+
+/// Entry in the cost info cache
#[derive(Serialize, Deserialize)]
struct CacheEntry {
+ /// Hash of the primrose library at the time measurements were taken
lib_hash: u64,
+
+ /// The resulting cost model
model: CostModel,
- results: Results,
-}
-/// Gets/retrieves benchmark results for container implementations.
-/// This caches results, and invalidates them when the library or parameters change.
-pub struct ResultsStore {
- paths: Paths,
- store: FileCache<str, CacheEntry>,
- lib_specs: LibSpecs,
- lib_hash: u64,
+ /// The raw benchmark results
+ results: Results,
}
impl ResultsStore {
@@ -61,49 +67,39 @@ impl ResultsStore {
debug!("Initialised benchmark cacher with hash {}", lib_hash);
Ok(Self {
- store: FileCache::new(base_dir)?,
- paths: paths.clone(),
+ store: FileCache::new(base_dir, move |_, v: &CacheEntry| v.lib_hash == lib_hash)?,
lib_specs,
lib_hash,
})
}
+}
- /// Get benchmark results for the given type, using cached results if possible and persisting the results for later.
+impl State {
+ /// Get or calculate the cost model for the given type.
/// Will panic if `name` is not in library specs.
- pub fn get(&self, name: &str) -> Result<CostModel> {
- if let Some(results) = self.find(name)? {
- debug!("Cache hit for {} benchmarks", name);
- Ok(results)
- } else {
- debug!("Cache miss for {} benchmarks", name);
- let results = run_benchmarks(name, &self.paths, &self.lib_specs)?;
- let model = build_cost_model(results.clone())?;
- if let Err(e) = self.put(name, &model, &results) {
- warn!("Error caching benchmark outputs for {}: {}", name, e);
- }
- Ok(model)
+ pub fn cost_model(&self, name: &str) -> Result<CostModel> {
+ match self.results.store.find(&name)? {
+ Some(x) => Ok(x.model),
+ None => self.calc_cost_model(&name),
}
}
- /// Attempt to find an up-to-date set of results with the given key
- fn find(&self, name: &str) -> Result<Option<CostModel>> {
- Ok(self
- .store
- .find(name)?
- .filter(|e| e.lib_hash == self.lib_hash)
- .map(|e| e.model))
- }
-
- /// Store a new set of results with the given key
- fn put(&self, name: &str, model: &CostModel, results: &Results) -> Result<()> {
- self.store.put(
+ /// Calculate cost information for the given type
+ /// Will panic if `name` is not in library specs.
+ fn calc_cost_model(&self, name: &str) -> Result<CostModel> {
+ let results = run_benchmarks(name, &self.paths, &self.results.lib_specs)?;
+ let model = build_cost_model(results.clone())?;
+ if let Err(e) = self.results.store.put(
name,
&CacheEntry {
- lib_hash: self.lib_hash,
+ lib_hash: self.results.lib_hash,
model: model.clone(),
results: results.clone(),
},
- )
+ ) {
+ warn!("Error caching benchmark outputs for {}: {}", name, e);
+ }
+ Ok(model)
}
}
diff --git a/src/crates/candelabra/src/lib.rs b/src/crates/candelabra/src/lib.rs
new file mode 100644
index 0000000..2836e78
--- /dev/null
+++ b/src/crates/candelabra/src/lib.rs
@@ -0,0 +1,41 @@
+use anyhow::Result;
+
+use crate::{candidates::CandidatesStore, cost::ResultsStore};
+
+extern crate nalgebra as na;
+
+mod cache;
+pub mod candidates;
+pub mod cost;
+pub mod profiler;
+
+mod paths;
+mod project;
+pub use paths::Paths;
+pub use project::Project;
+
+/// Shared state for program execution
+pub struct State {
+ /// Paths used throughout execution
+ paths: Paths,
+
+ /// Cache for candidate types for primrose files & annotations
+ candidates: CandidatesStore,
+
+ /// Results and cost models
+ results: ResultsStore,
+
+ /// The model size used for primrose operations
+ model_size: usize,
+}
+
+impl State {
+ pub fn new(paths: Paths) -> Result<Self> {
+ Ok(Self {
+ candidates: CandidatesStore::new(&paths)?,
+ results: ResultsStore::new(&paths)?,
+ model_size: 3, // TODO
+ paths,
+ })
+ }
+}
diff --git a/src/crates/cli/src/paths.rs b/src/crates/candelabra/src/paths.rs
index 2b44400..d25c174 100644
--- a/src/crates/cli/src/paths.rs
+++ b/src/crates/candelabra/src/paths.rs
@@ -1,7 +1,7 @@
-use std::{env, path::PathBuf};
-
use camino::Utf8PathBuf;
+use std::{env, path::PathBuf};
+/// Paths used throughout execution
#[derive(Debug, Clone)]
pub struct Paths {
pub base: Utf8PathBuf,
@@ -12,7 +12,7 @@ pub struct Paths {
}
impl Paths {
- fn from_base(base: Utf8PathBuf) -> Self {
+ pub fn from_base(base: Utf8PathBuf) -> Self {
Paths {
library_crate: base.join("crates").join("library"),
library_src: base.join("crates").join("library").join("src"),
diff --git a/src/crates/cli/src/profiler/mod.rs b/src/crates/candelabra/src/profiler.rs
index 24ae544..b240258 100644
--- a/src/crates/cli/src/profiler/mod.rs
+++ b/src/crates/candelabra/src/profiler.rs
@@ -1,3 +1,5 @@
+//! Profiling applications for info about container usage
+
use anyhow::{anyhow, bail, Context, Result};
use camino::Utf8Path;
use log::{debug, trace};
@@ -15,12 +17,13 @@ use tempfile::tempdir;
use crate::project::Project;
use crate::State;
+/// The information we get from profiling.
pub type ProfilerInfo = DataFrame;
impl State {
- /// Profile all benchmarks for the given project
- pub fn profile_all(&self, project: &Project) -> Result<ProfilerInfo> {
- self.prepare_for_profiling(project)?;
+ /// Get/calculate profiler info for the given project.
+ pub fn calc_profiler_info(&self, project: &Project) -> Result<ProfilerInfo> {
+ self.project_profiling_prep(project)?;
project
.benchmarks
.iter()
@@ -32,16 +35,22 @@ impl State {
.ok_or(anyhow!("nothing to run or types are not used"))?
}
- fn prepare_for_profiling(&self, project: &Project) -> Result<()> {
- for (file, candidates) in self.get_all_candidates(project)? {
- self.prepare_file(&file, &candidates)
+ /// Prepare the given project to be profiled, by replacing all candidate types with the profiler wrapper.
+ fn project_profiling_prep(&self, project: &Project) -> Result<()> {
+ for (file, candidates) in self.project_candidate_list(project)? {
+ self.file_profiling_prep(&file, &candidates)
.with_context(|| format!("error preparing {} for profiling", file))?;
}
Ok(())
}
- fn prepare_file(&self, file: &Utf8Path, candidates: &[(String, Vec<String>)]) -> Result<()> {
+ /// Prepare the given file to be profiled, by replacing all candidate types with the profiler wrapper.
+ fn file_profiling_prep(
+ &self,
+ file: &Utf8Path,
+ candidates: &[(String, Vec<String>)],
+ ) -> Result<()> {
debug!("Setting up {} for profiling", file);
let selector = ContainerSelector::from_path(
@@ -70,6 +79,7 @@ impl State {
Ok(())
}
+ /// Run the given benchmark on the project, and parse the resulting profiling information.
fn profile_benchmark(&self, project: &Project, name: &str) -> Result<DataFrame> {
let profiler_out_dir = tempdir()?;
debug!(
@@ -102,6 +112,7 @@ impl State {
}
}
+/// Parse the output of the profiler
fn parse_output(contents: &str) -> Result<DataFrame> {
let mut lines = contents.lines().map(i32::from_str);
let missing_line_err = || anyhow!("wrong number of lines in ");
diff --git a/src/crates/cli/src/project.rs b/src/crates/candelabra/src/project.rs
index cc8b4a2..cc8b4a2 100644
--- a/src/crates/cli/src/project.rs
+++ b/src/crates/candelabra/src/project.rs
diff --git a/src/crates/cli/Cargo.toml b/src/crates/cli/Cargo.toml
index 0a3a643..c0180ee 100644
--- a/src/crates/cli/Cargo.toml
+++ b/src/crates/cli/Cargo.toml
@@ -1,22 +1,9 @@
[package]
-name = "candelabra-cli"
+name = "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]
-log = { workspace = true }
-env_logger = { workspace = true }
-primrose = { path = "../primrose" }
-anyhow = { workspace = true }
-serde = { workspace = true }
-serde_json = { workspace = true }
-camino = "1.1.6"
-cargo_metadata = "0.18.1"
-argh = "0.1.12"
-glob = "0.3.1"
-tempfile = "3"
-nalgebra = "0.32.3"
-polars = { version = "0.35.4", features = ["describe"] }
+candelabra = { path = "../candelabra" } \ No newline at end of file
diff --git a/src/crates/cli/src/candidates.rs b/src/crates/cli/src/candidates.rs
deleted file mode 100644
index ab713d7..0000000
--- a/src/crates/cli/src/candidates.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-//! Generating and caching primrose candidate results
-
-use std::{collections::HashMap, fs::metadata, time::SystemTime};
-
-use anyhow::{Context, Result};
-use camino::{Utf8Path, Utf8PathBuf};
-use log::{debug, warn};
-use primrose::ContainerSelector;
-use serde::{Deserialize, Serialize};
-
-use crate::{
- cache::{gen_tree_hash, FileCache},
- paths::Paths,
- project::Project,
- State,
-};
-
-// TODO: Make this adjustable
-/// The size of the model used by primrose
-const MODEL_SIZE: usize = 3;
-
-/// Names a container type we want to select.
-pub type ConTypeName = String;
-
-/// Name of a container implementation we are considering
-pub type ImplName = String;
-
-/// A list of candidate container types
-pub type Candidates = HashMap<ConTypeName, Vec<ImplName>>;
-
-/// Entry in the benchmark cache
-#[derive(Serialize, Deserialize, Debug)]
-struct CacheEntry {
- lib_hash: u64,
- mod_time: SystemTime,
- value: Candidates,
-}
-
-/// Gets/retrieves candidate container types for primrose files.
-/// This caches results, and invalidates them when the file changes.
-pub struct CandidatesStore {
- paths: Paths,
- store: FileCache<Utf8Path, CacheEntry>,
- lib_hash: u64,
-}
-
-impl CandidatesStore {
- /// Create a new store, using the given paths.
- /// Benchmarks are cached in `paths.target_dir / candelabra / primrose_results`
- pub fn new(paths: &Paths) -> Result<Self> {
- let base_dir = paths.target_dir.join("candelabra").join("primrose_results");
-
- let lib_hash =
- gen_tree_hash(&paths.library_crate).context("Error generating library hash")?;
-
- debug!("Initialised candidate cacher with hash {}", lib_hash);
-
- Ok(Self {
- store: FileCache::new(base_dir)?,
- paths: paths.clone(),
- lib_hash,
- })
- }
-
- /// Get benchmark results for the given type, using cached results if possible and persisting the results for later.
- /// Will panic if `name` is not in library specs.
- pub fn get(&self, src: &Utf8Path) -> Result<Candidates> {
- if let Some(results) = self.find(src)? {
- debug!("Cache hit for {} candidates", src);
- Ok(results)
- } else {
- debug!("Cache miss for {} candidates", src);
- let selector = ContainerSelector::from_path(
- src.as_std_path(),
- self.paths.library_src.as_std_path(),
- MODEL_SIZE,
- )
- .with_context(|| format!("error getting container selector for {}", src))?;
-
- let candidates = selector
- .find_all_candidates()?
- .into_iter()
- .map(|(k, v)| (k.to_string(), v))
- .collect();
-
- if let Err(e) = self.put(src, &candidates) {
- warn!("Error caching candidates for {}: {}", src, e);
- }
- Ok(candidates)
- }
- }
-
- /// Attempt to find an up-to-date set of results with the given key
- fn find(&self, src: &Utf8Path) -> Result<Option<Candidates>> {
- let mod_time = metadata(src)?.modified()?;
- Ok(self
- .store
- .find(src)?
- .filter(|e| e.lib_hash == self.lib_hash && e.mod_time == mod_time)
- .map(|e| e.value))
- }
-
- /// Store a new set of results with the given key
- fn put(&self, src: &Utf8Path, results: &Candidates) -> Result<()> {
- let mod_time = metadata(src)?.modified()?;
- self.store.put(
- src,
- &CacheEntry {
- lib_hash: self.lib_hash,
- value: results.clone(),
- mod_time,
- },
- )
- }
-}
-
-pub type ProjectCandidateList = Vec<(Utf8PathBuf, Vec<(ConTypeName, Vec<ImplName>)>)>;
-
-impl State {
- /// Run primrose on all files in the given project.
- /// Returns a list of all candidates for each container type in each file.
- pub fn get_all_candidates(&self, project: &Project) -> Result<ProjectCandidateList> {
- let mut all_candidates = Vec::new();
- for file in project.find_primrose_files()? {
- let result = self.candidates.get(&file)?;
-
- let mut typs = Vec::new();
- for (con_type_id, candidates) in result {
- typs.push((con_type_id.clone(), candidates));
- }
- all_candidates.push((file, typs));
- }
-
- Ok(all_candidates)
- }
-}
diff --git a/src/crates/cli/src/cmd.rs b/src/crates/cli/src/cmd.rs
deleted file mode 100644
index 7f9857d..0000000
--- a/src/crates/cli/src/cmd.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-use argh::FromArgs;
-
-#[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,
-}
-
-#[derive(FromArgs)]
-#[argh(subcommand)]
-pub enum Subcommand {
- Model(ModelSubcommand),
- Candidates(CandidatesSubcommand),
- Profile(ProfileSubcommand),
-}
-
-#[derive(FromArgs)]
-/// Show the cost model for the given implementation
-#[argh(subcommand, name = "cost-model")]
-pub struct ModelSubcommand {}
-
-#[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 {}
diff --git a/src/crates/cli/src/main.rs b/src/crates/cli/src/main.rs
index 8827084..5bd0f34 100644
--- a/src/crates/cli/src/main.rs
+++ b/src/crates/cli/src/main.rs
@@ -1,115 +1,32 @@
-use anyhow::{anyhow, Context, Result};
-use candidates::CandidatesStore;
-use cmd::{CandidatesSubcommand, ModelSubcommand, ProfileSubcommand};
-use cost::ResultsStore;
-use log::info;
-use polars::prelude::*;
-use project::Project;
-
-use crate::{
- cmd::{Args, Subcommand},
- paths::Paths,
-};
-
-extern crate nalgebra as na;
-
-mod cache;
-mod candidates;
-mod cmd;
-mod cost;
-mod paths;
-mod profiler;
-mod project;
-
-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 {
- candidates: CandidatesStore::new(&paths).context("error creating candidate store")?,
- results: ResultsStore::new(&paths).context("error creating result store")?,
- paths,
- model_size: 3, // TODO
- };
-
- let projects = get_projects(&args).context("failed to find project paths")?;
- match args.cmd {
- Subcommand::Model(c) => state.cmd_model(projects, c),
- Subcommand::Candidates(c) => state.cmd_candidates(projects, c),
- Subcommand::Profile(c) => state.cmd_profile(projects, c),
- }
+fn main() {
+ println!("Hello, world!");
}
-/// Shared state for program execution
-pub struct State {
- /// Paths used throughout execution
- paths: Paths,
-
- /// Candidate types for primrose files & annotations
- candidates: CandidatesStore,
-
- /// Results and cost models
- results: ResultsStore,
-
- /// The model size used for primrose operations
- model_size: usize,
-}
-
-impl State {
- pub fn cmd_model(&self, projects: Vec<Project>, c: ModelSubcommand) -> Result<()> {
- todo!()
- }
-
- pub fn cmd_candidates(&self, projects: Vec<Project>, c: CandidatesSubcommand) -> Result<()> {
- todo!()
- }
-
- pub fn cmd_profile(&self, projects: Vec<Project>, c: ProfileSubcommand) -> Result<()> {
- for project in projects {
- info!("Profiling project {}", project.name);
- let inf = self
- .profile_all(&project)
- .with_context(|| format!("Error profiling project {}", project.name))?;
-
- // TODO: More useful output
- info!("{:?}", inf);
- info!("{} samples", inf.shape().0);
- info!("{:?}", inf.describe(None));
- }
-
- Ok(())
- }
-}
-
-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())
- }
-}
+// 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())
+// }
+// }