diff options
Diffstat (limited to 'src/crates')
-rw-r--r-- | src/crates/candelabra/src/lib.rs | 1 | ||||
-rw-r--r-- | src/crates/candelabra/src/profiler.rs | 49 | ||||
-rw-r--r-- | src/crates/candelabra/src/select.rs | 64 | ||||
-rw-r--r-- | src/crates/cli/src/main.rs | 3 | ||||
-rw-r--r-- | src/crates/cli/src/select.rs | 21 |
5 files changed, 138 insertions, 0 deletions
diff --git a/src/crates/candelabra/src/lib.rs b/src/crates/candelabra/src/lib.rs index 6e6af86..1aa62d1 100644 --- a/src/crates/candelabra/src/lib.rs +++ b/src/crates/candelabra/src/lib.rs @@ -9,6 +9,7 @@ mod cache; pub mod candidates; pub mod cost; pub mod profiler; +mod select; mod paths; mod project; diff --git a/src/crates/candelabra/src/profiler.rs b/src/crates/candelabra/src/profiler.rs index 9f56f54..6984297 100644 --- a/src/crates/candelabra/src/profiler.rs +++ b/src/crates/candelabra/src/profiler.rs @@ -17,6 +17,7 @@ use tempfile::tempdir; use crate::cache::{gen_tree_hash, FileCache}; use crate::candidates::ConTypeName; +use crate::cost::CostModel; use crate::project::Project; use crate::{Paths, State}; @@ -46,6 +47,54 @@ pub struct CollectionLifetime { pub pop: usize, } +impl ProfilerInfo { + pub fn estimate_cost(&self, cost_model: &CostModel) -> f64 { + let sum: f64 = self.0.iter().map(|cl| cl.estimate_cost(cost_model)).sum(); + + sum / self.0.len() as f64 + } +} + +impl CollectionLifetime { + pub fn avg_n(&self) -> f64 { + self.n as f64 + / (self.contains + + self.insert + + self.clear + + self.remove + + self.first + + self.last + + self.nth + + self.push + + self.pop) as f64 + } + + pub fn op_count(&self, op: &str) -> usize { + match op { + "contains" => self.contains, + "insert" => self.insert, + "clear" => self.clear, + "remove" => self.remove, + "first" => self.first, + "last" => self.last, + "nth" => self.nth, + "push" => self.push, + "pop" => self.pop, + _ => panic!("invalid op passed to op_count: {}", op), + } + } + + pub fn estimate_cost(&self, cost_model: &CostModel) -> f64 { + let avg_n = self.avg_n(); + let mut acc = 0.0; + for (op, estimator) in cost_model.by_op.iter() { + acc += estimator.estimatef(avg_n) * self.op_count(op) as f64; + } + + acc + } +} + impl State { pub(crate) fn profiler_info_cache(paths: &Paths) -> Result<FileCache<String, CacheEntry>> { FileCache::new( diff --git a/src/crates/candelabra/src/select.rs b/src/crates/candelabra/src/select.rs new file mode 100644 index 0000000..28bea1e --- /dev/null +++ b/src/crates/candelabra/src/select.rs @@ -0,0 +1,64 @@ +use std::collections::HashMap; + +use crate::{ + candidates::{ConTypeName, ImplName}, + Project, State, +}; + +use anyhow::Result; +use log::debug; + +impl State { + /// Select a container implementation for each container type in the given project + pub fn select(&self, project: &Project) -> Result<HashMap<ConTypeName, ImplName>> { + // get all candidates + let all_candidates = self.project_candidate_list(project)?; + + // get profiling information + let profiles = self.profiler_info(project)?; + + // generate estimates + // TODO: hacky stuff that panics too easy! + Ok(profiles + .iter() + .map(|(con_type, profile)| { + let candidates = &all_candidates + .iter() + .flat_map(|(_, cs)| cs.iter()) + .find(|(name, _)| name == con_type) + .unwrap() + .1; + + ( + con_type, + candidates.iter().map(move |candidate| -> (&str, f64) { + let cost_model = self.cost_model(candidate).unwrap(); + let cost = profile.estimate_cost(&cost_model); + + debug!("cost of {} being {} = {}", con_type, candidate, cost); + + (candidate, cost) + }), + ) + }) + .map(|(con_type, costs)| { + ( + con_type.to_string(), + costs + .reduce( + |acc @ (_, lowest_cost), new @ (_, cost)| { + if lowest_cost < cost { + acc + } else { + new + } + }, + ) + .unwrap() + .0 + .to_string(), + ) + }) + .collect()) + } +} diff --git a/src/crates/cli/src/main.rs b/src/crates/cli/src/main.rs index f0577aa..1b926a7 100644 --- a/src/crates/cli/src/main.rs +++ b/src/crates/cli/src/main.rs @@ -7,6 +7,7 @@ mod candidates; mod library; mod model; mod profile; +mod select; #[derive(FromArgs)] /// Find the best performing container type using primrose @@ -30,6 +31,7 @@ pub enum Subcommand { Library(library::Args), Candidates(candidates::Args), Profile(profile::Args), + Select(select::Args), } fn main() -> Result<()> { @@ -49,6 +51,7 @@ fn main() -> Result<()> { Subcommand::Library(a) => state.cmd_library(a), Subcommand::Candidates(a) => state.cmd_candidates(a), Subcommand::Profile(a) => state.cmd_profile(a), + Subcommand::Select(a) => state.cmd_select(a), } } diff --git a/src/crates/cli/src/select.rs b/src/crates/cli/src/select.rs new file mode 100644 index 0000000..ab3e4aa --- /dev/null +++ b/src/crates/cli/src/select.rs @@ -0,0 +1,21 @@ +use anyhow::Result; +use argh::FromArgs; +use log::info; + +use crate::State; + +/// Select an implementation for each container type and project +#[derive(FromArgs)] +#[argh(subcommand, name = "select")] +pub struct Args {} + +impl State { + pub fn cmd_select(&self, _: Args) -> Result<()> { + for proj in self.projects.iter() { + info!("Processing project {}", &proj.name); + + dbg!(self.inner.select(proj).unwrap()); + } + Ok(()) + } +} |