aiken/crates/aiken-project/src/telemetry.rs

162 lines
4.2 KiB
Rust

use aiken_lang::{
expr::UntypedExpr,
test_framework::{BenchmarkResult, PropertyTestResult, TestResult, UnitTestResult},
};
pub use json::{json_schema, Json};
use std::{
collections::BTreeMap,
fmt::Display,
io::{self, IsTerminal},
path::PathBuf,
};
pub use terminal::Terminal;
use uplc::machine::cost_model::ExBudget;
mod json;
mod terminal;
pub trait EventListener {
fn handle_event(&self, _event: Event) {}
}
pub enum Event {
StartingCompilation {
name: String,
version: String,
root: PathBuf,
},
BuildingDocumentation {
name: String,
version: String,
root: PathBuf,
},
GeneratingDocFiles {
output_path: PathBuf,
},
GeneratingBlueprint {
path: PathBuf,
},
DumpingUPLC {
path: PathBuf,
},
GeneratingUPLCFor {
name: String,
path: PathBuf,
},
CollectingTests {
matching_module: Option<String>,
matching_names: Vec<String>,
},
RunningTests,
RunningBenchmarks,
FinishedTests {
seed: u32,
tests: Vec<TestResult<UntypedExpr, UntypedExpr>>,
},
FinishedBenchmarks {
seed: u32,
benchmarks: Vec<TestResult<UntypedExpr, UntypedExpr>>,
},
WaitingForBuildDirLock,
ResolvingPackages {
name: String,
},
PackageResolveFallback {
name: String,
},
PackagesDownloaded {
start: tokio::time::Instant,
count: usize,
source: DownloadSource,
},
ResolvingVersions,
}
pub enum EventTarget {
Json(Json),
Terminal(Terminal),
}
impl Default for EventTarget {
fn default() -> Self {
if io::stdout().is_terminal() {
EventTarget::Terminal(Terminal)
} else {
EventTarget::Json(Json)
}
}
}
impl EventListener for EventTarget {
fn handle_event(&self, event: Event) {
match self {
EventTarget::Terminal(term) => term.handle_event(event),
EventTarget::Json(json) => json.handle_event(event),
}
}
}
pub enum DownloadSource {
Network,
Cache,
}
impl Display for DownloadSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DownloadSource::Network => write!(f, "network"),
DownloadSource::Cache => write!(f, "cache"),
}
}
}
pub(crate) fn group_by_module(
results: &[TestResult<UntypedExpr, UntypedExpr>],
) -> BTreeMap<String, Vec<&TestResult<UntypedExpr, UntypedExpr>>> {
let mut modules = BTreeMap::new();
for r in results {
let xs: &mut Vec<&TestResult<_, _>> = modules.entry(r.module().to_string()).or_default();
xs.push(r);
}
modules
}
pub(crate) fn find_max_execution_units<T>(xs: &[TestResult<T, T>]) -> (usize, usize, usize) {
fn max_execution_units(max_mem: i64, max_cpu: i64, cost: &ExBudget) -> (i64, i64) {
if cost.mem >= max_mem && cost.cpu >= max_cpu {
(cost.mem, cost.cpu)
} else if cost.mem > max_mem {
(cost.mem, max_cpu)
} else if cost.cpu > max_cpu {
(max_mem, cost.cpu)
} else {
(max_mem, max_cpu)
}
}
let (max_mem, max_cpu, max_iter) =
xs.iter()
.fold((0, 0, 0), |(max_mem, max_cpu, max_iter), test| match test {
TestResult::PropertyTestResult(PropertyTestResult { iterations, .. }) => {
(max_mem, max_cpu, std::cmp::max(max_iter, *iterations))
}
TestResult::UnitTestResult(UnitTestResult { spent_budget, .. }) => {
let (max_mem, max_cpu) = max_execution_units(max_mem, max_cpu, spent_budget);
(max_mem, max_cpu, max_iter)
}
TestResult::BenchmarkResult(BenchmarkResult { measures, .. }) => {
let (mut max_mem, mut max_cpu) = (max_mem, max_cpu);
for (_, measure) in measures {
(max_mem, max_cpu) = max_execution_units(max_mem, max_cpu, measure);
}
(max_mem, max_cpu, max_iter)
}
});
(
max_mem.to_string().len(),
max_cpu.to_string().len(),
max_iter.to_string().len(),
)
}