1pub mod envelope;
20pub mod motifs;
21pub mod replay;
22
23use crate::residual::{ResidualClass, ResidualStream};
24use serde::{Deserialize, Serialize};
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
28pub enum MotifClass {
29 PlanRegressionOnset,
30 CardinalityMismatchRegime,
31 ContentionRamp,
32 CacheCollapse,
33 WorkloadPhaseTransition,
34}
35
36impl MotifClass {
37 pub const ALL: [MotifClass; 5] = [
38 Self::PlanRegressionOnset,
39 Self::CardinalityMismatchRegime,
40 Self::ContentionRamp,
41 Self::CacheCollapse,
42 Self::WorkloadPhaseTransition,
43 ];
44
45 pub fn name(&self) -> &'static str {
46 match self {
47 Self::PlanRegressionOnset => "plan_regression_onset",
48 Self::CardinalityMismatchRegime => "cardinality_mismatch_regime",
49 Self::ContentionRamp => "contention_ramp",
50 Self::CacheCollapse => "cache_collapse",
51 Self::WorkloadPhaseTransition => "workload_phase_transition",
52 }
53 }
54
55 pub fn residual_class(&self) -> ResidualClass {
56 match self {
57 Self::PlanRegressionOnset => ResidualClass::PlanRegression,
58 Self::CardinalityMismatchRegime => ResidualClass::Cardinality,
59 Self::ContentionRamp => ResidualClass::Contention,
60 Self::CacheCollapse => ResidualClass::CacheIo,
61 Self::WorkloadPhaseTransition => ResidualClass::WorkloadPhase,
62 }
63 }
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct Episode {
70 pub motif: MotifClass,
71 pub channel: Option<String>,
72 pub t_start: f64,
73 pub t_end: f64,
74 pub peak: f64,
76 pub ema_at_boundary: f64,
79 pub trust_sum: f64,
82}
83
84#[derive(Debug, Clone, Deserialize, Serialize)]
86pub struct MotifParams {
87 pub rho: f64,
89 pub sigma0: f64,
91 pub drift_threshold: f64,
93 pub slew_threshold: f64,
96 pub min_dwell_seconds: f64,
99}
100
101impl MotifParams {
102 pub fn default_for(class: MotifClass) -> Self {
106 match class {
107 MotifClass::PlanRegressionOnset => Self {
108 rho: 0.9,
109 sigma0: 0.05,
110 drift_threshold: 0.20,
111 slew_threshold: 0.50,
112 min_dwell_seconds: 5.0,
113 },
114 MotifClass::CardinalityMismatchRegime => Self {
115 rho: 0.9,
116 sigma0: 0.05,
117 drift_threshold: 0.5, slew_threshold: 1.0, min_dwell_seconds: 2.0,
120 },
121 MotifClass::ContentionRamp => Self {
122 rho: 0.85,
123 sigma0: 0.01,
124 drift_threshold: 0.05,
125 slew_threshold: 0.5,
126 min_dwell_seconds: 1.0,
127 },
128 MotifClass::CacheCollapse => Self {
129 rho: 0.9,
130 sigma0: 0.02,
131 drift_threshold: 0.10,
132 slew_threshold: 0.30,
133 min_dwell_seconds: 5.0,
134 },
135 MotifClass::WorkloadPhaseTransition => Self {
136 rho: 0.9,
137 sigma0: 0.02,
138 drift_threshold: 0.15,
139 slew_threshold: 0.35,
140 min_dwell_seconds: 30.0,
141 },
142 }
143 }
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct MotifGrammar {
149 pub plan_regression_onset: MotifParams,
150 pub cardinality_mismatch_regime: MotifParams,
151 pub contention_ramp: MotifParams,
152 pub cache_collapse: MotifParams,
153 pub workload_phase_transition: MotifParams,
154}
155
156impl Default for MotifGrammar {
157 fn default() -> Self {
158 Self {
159 plan_regression_onset: MotifParams::default_for(MotifClass::PlanRegressionOnset),
160 cardinality_mismatch_regime: MotifParams::default_for(
161 MotifClass::CardinalityMismatchRegime,
162 ),
163 contention_ramp: MotifParams::default_for(MotifClass::ContentionRamp),
164 cache_collapse: MotifParams::default_for(MotifClass::CacheCollapse),
165 workload_phase_transition: MotifParams::default_for(
166 MotifClass::WorkloadPhaseTransition,
167 ),
168 }
169 }
170}
171
172impl MotifGrammar {
173 pub fn params(&self, class: MotifClass) -> &MotifParams {
174 match class {
175 MotifClass::PlanRegressionOnset => &self.plan_regression_onset,
176 MotifClass::CardinalityMismatchRegime => &self.cardinality_mismatch_regime,
177 MotifClass::ContentionRamp => &self.contention_ramp,
178 MotifClass::CacheCollapse => &self.cache_collapse,
179 MotifClass::WorkloadPhaseTransition => &self.workload_phase_transition,
180 }
181 }
182
183 pub fn from_yaml(yaml: &str) -> anyhow::Result<Self> {
184 Ok(serde_yaml::from_str(yaml)?)
185 }
186}
187
188pub struct MotifEngine {
190 grammar: MotifGrammar,
191}
192
193impl MotifEngine {
194 pub fn new(grammar: MotifGrammar) -> Self {
195 Self { grammar }
196 }
197
198 pub fn run(&self, stream: &ResidualStream) -> Vec<Episode> {
201 let mut all = Vec::new();
202 for class in MotifClass::ALL {
203 let params = self.grammar.params(class).clone();
204 let eps = motifs::run_motif(class, ¶ms, stream);
205 all.extend(eps);
206 }
207 all.sort_by(|a, b| {
208 a.t_start
209 .partial_cmp(&b.t_start)
210 .unwrap_or(std::cmp::Ordering::Equal)
211 });
212 all
213 }
214}