use std::collections::BTreeMap;
use crate::expr::{Context, Expr};
use crate::rules::Rule;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct Stats {
pub node_visits: u64,
pub memo_hits: u64,
pub candidates: u64,
pub match_steps: u64,
pub no_match: u64,
pub guard_false: u64,
pub degraded: u64,
pub no_change: u64,
pub rewrites: u64,
pub hook_vetoes: u64,
pub rejected: u64,
pub cycles_cut: u64,
pub quarantined: u64,
pub new_nodes: u64,
pub fact_work: u64,
pub pass_work: u64,
pub rounds: u32,
pub passes: BTreeMap<&'static str, PassCounts>,
pub host: PassCounts,
pub mba: MbaStats,
pub completed: [u64; 2],
pub budget_terminated: [u64; 2],
pub declined: u64,
}
impl Stats {
pub fn absorb(&mut self, o: &Stats) {
let Stats {
node_visits,
memo_hits,
candidates,
match_steps,
no_match,
guard_false,
degraded,
no_change,
rewrites,
hook_vetoes,
rejected,
cycles_cut,
quarantined,
new_nodes,
fact_work,
pass_work,
rounds,
passes,
host,
mba,
completed,
budget_terminated,
declined,
} = o;
self.node_visits += node_visits;
self.memo_hits += memo_hits;
self.candidates += candidates;
self.match_steps += match_steps;
self.no_match += no_match;
self.guard_false += guard_false;
self.degraded += degraded;
self.no_change += no_change;
self.rewrites += rewrites;
self.hook_vetoes += hook_vetoes;
self.rejected += rejected;
self.cycles_cut += cycles_cut;
self.quarantined += quarantined;
self.new_nodes += new_nodes;
self.fact_work += fact_work;
self.pass_work += pass_work;
self.rounds = self.rounds.max(*rounds);
for (name, c) in passes {
self.passes.entry(name).or_default().absorb(c);
}
self.host.absorb(host);
self.mba.absorb(mba);
for k in 0..2 {
self.completed[k] += completed[k];
self.budget_terminated[k] += budget_terminated[k];
}
self.declined += declined;
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct MbaStats {
pub calls: u64,
pub cache_hits: u64,
pub simplified: u64,
pub no_simpler: u64,
pub unsupported: u64,
pub exhausted: u64,
pub refuted: u64,
pub proof_unknown: u64,
pub not_smaller: u64,
pub too_many_vars: u64,
pub too_large: u64,
pub too_wide: u64,
pub too_small: u64,
pub certificates: CertStats,
}
impl MbaStats {
pub fn absorb(&mut self, o: &MbaStats) {
let MbaStats {
calls,
cache_hits,
simplified,
no_simpler,
unsupported,
exhausted,
refuted,
proof_unknown,
not_smaller,
too_many_vars,
too_large,
too_wide,
too_small,
certificates,
} = o;
self.calls += calls;
self.cache_hits += cache_hits;
self.simplified += simplified;
self.no_simpler += no_simpler;
self.unsupported += unsupported;
self.exhausted += exhausted;
self.refuted += refuted;
self.proof_unknown += proof_unknown;
self.not_smaller += not_smaller;
self.too_many_vars += too_many_vars;
self.too_large += too_large;
self.too_wide += too_wide;
self.too_small += too_small;
self.certificates.absorb(certificates);
}
#[cfg(feature = "mba")]
pub(crate) fn refused(&mut self, why: &crate::mba::Refusal) {
use crate::mba::Refusal;
match why {
Refusal::TooManyVars => self.too_many_vars += 1,
Refusal::TooLarge => self.too_large += 1,
Refusal::TooWide => self.too_wide += 1,
Refusal::TooSmall => self.too_small += 1,
_ => self.unsupported += 1,
}
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct CertStats {
pub calls: u64,
pub proved: u64,
pub refuted: u64,
pub unknown: u64,
pub signature: u64,
pub single_bit: u64,
pub sparse: u64,
pub grid: u64,
pub exhaustive: u64,
pub symbolic: u64,
pub carries: u64,
pub compositional: u64,
pub split: u64,
pub known_bits: u64,
pub points: u64,
pub over_budget: u64,
pub internal: u64,
}
impl CertStats {
pub fn absorb(&mut self, o: &CertStats) {
let CertStats {
calls,
proved,
refuted,
unknown,
signature,
single_bit,
sparse,
grid,
exhaustive,
symbolic,
carries,
compositional,
split,
known_bits,
points,
over_budget,
internal,
} = o;
self.calls += calls;
self.proved += proved;
self.refuted += refuted;
self.unknown += unknown;
self.signature += signature;
self.single_bit += single_bit;
self.sparse += sparse;
self.grid += grid;
self.exhaustive += exhaustive;
self.symbolic += symbolic;
self.carries += carries;
self.compositional += compositional;
self.split += split;
self.known_bits += known_bits;
self.points += points;
self.over_budget += over_budget;
self.internal += internal;
}
#[cfg(feature = "mba")]
pub(crate) fn record(&mut self, r: &crate::mba::certify::Report) {
use crate::mba::Verdict;
use crate::mba::certify::Cert;
self.calls += 1;
match r.verdict {
Verdict::Proved => self.proved += 1,
Verdict::Refuted => self.refuted += 1,
Verdict::Unknown => self.unknown += 1,
}
if r.verdict != Verdict::Unknown {
match r.cert {
Some(Cert::Signature) => self.signature += 1,
Some(Cert::SingleBit) => self.single_bit += 1,
Some(Cert::Sparse) => self.sparse += 1,
Some(Cert::Grid) => self.grid += 1,
Some(Cert::Exhaustive) => self.exhaustive += 1,
Some(Cert::Symbolic) => self.symbolic += 1,
Some(Cert::Carries) => self.carries += 1,
None => {}
}
if r.compositional {
self.compositional += 1;
}
if r.split {
self.split += 1;
}
if r.known_bits {
self.known_bits += 1;
}
}
self.points += r.points;
self.over_budget += u64::from(r.over_budget);
self.internal += r.internal;
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct PassCounts {
pub calls: u64,
pub noop: u64,
pub changed: u64,
pub rejected_cost: u64,
pub rejected: u64,
pub atomized: u64,
}
impl PassCounts {
pub fn absorb(&mut self, o: &PassCounts) {
let PassCounts {
calls,
noop,
changed,
rejected_cost,
rejected,
atomized,
} = o;
self.calls += calls;
self.noop += noop;
self.changed += changed;
self.rejected_cost += rejected_cost;
self.rejected += rejected;
self.atomized += atomized;
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Reject {
Width,
Verify,
Tripwire,
Termination,
}
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum By<'a> {
Rule(&'a Rule),
Pass(&'static str),
Rewrite(&'a str),
}
impl By<'_> {
pub fn name(&self) -> &str {
match self {
By::Rule(r) => &r.name,
By::Pass(p) => p,
By::Rewrite(r) => r,
}
}
}
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum Event<'a> {
Candidate {
rule: &'a Rule,
node: Expr,
},
NoMatch {
rule: &'a Rule,
},
GuardFalse {
rule: &'a Rule,
},
Degraded {
rule: &'a Rule,
},
NoChange {
rule: &'a Rule,
},
Applied {
by: By<'a>,
before: Expr,
after: Expr,
},
Vetoed {
by: By<'a>,
},
Rejected {
by: By<'a>,
reason: Reject,
},
}
pub trait Observer {
fn event(&mut self, event: Event<'_>);
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct RuleCensus {
pub rules: BTreeMap<String, RuleCounts>,
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct RuleCounts {
pub candidates: u64,
pub no_match: u64,
pub guard_false: u64,
pub degraded: u64,
pub no_change: u64,
pub applied: u64,
pub rejected: u64,
}
impl Observer for RuleCensus {
fn event(&mut self, event: Event<'_>) {
let (rule, f): (&Rule, fn(&mut RuleCounts)) = match event {
Event::Candidate { rule, .. } => (rule, |c| c.candidates += 1),
Event::NoMatch { rule } => (rule, |c| c.no_match += 1),
Event::GuardFalse { rule } => (rule, |c| c.guard_false += 1),
Event::Degraded { rule } => (rule, |c| c.degraded += 1),
Event::NoChange { rule } => (rule, |c| c.no_change += 1),
Event::Applied {
by: By::Rule(rule), ..
} => (rule, |c| c.applied += 1),
Event::Vetoed { by: By::Rule(rule) }
| Event::Rejected {
by: By::Rule(rule), ..
} => (rule, |c| c.rejected += 1),
_ => return,
};
f(self.rules.entry(rule.name.clone()).or_default());
}
}
pub trait Hooks {
fn admit(&self, cx: &Context, before: Expr, after: Expr, by: By<'_>) -> bool {
let _ = (cx, before, after, by);
true
}
fn fold_known(&self, cx: &Context, e: Expr) -> bool {
let _ = (cx, e);
true
}
fn revision(&self) -> u64 {
0
}
}