aboutsummaryrefslogtreecommitdiff
path: root/src/crates
diff options
context:
space:
mode:
Diffstat (limited to 'src/crates')
-rw-r--r--src/crates/candelabra/src/lib.rs1
-rw-r--r--src/crates/candelabra/src/profiler.rs49
-rw-r--r--src/crates/candelabra/src/select.rs64
-rw-r--r--src/crates/cli/src/main.rs3
-rw-r--r--src/crates/cli/src/select.rs21
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(())
+ }
+}