1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum BenchPath {
11 QueryBuild,
13 Pool,
15 Cache,
17 Transaction,
19 Serialization,
21 Stream,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct BaselinePoint {
28 pub path: BenchPath,
30 pub name: String,
32 pub mean_ns: f64,
34 pub stddev_ns: f64,
36 pub p99_ns: f64,
38 pub timestamp: u64,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct RegressionPoint {
45 pub path: BenchPath,
47 pub name: String,
49 pub current_mean_ns: f64,
51 pub baseline_mean_ns: f64,
53 pub change_percent: f64,
55 pub is_regression: bool,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct RegressionReport {
62 pub timestamp: u64,
64 pub points: Vec<RegressionPoint>,
66 pub regression_count: usize,
68 pub improvement_count: usize,
70}
71
72impl RegressionReport {
73 pub fn from_points(points: Vec<RegressionPoint>) -> Self {
75 let regression_count = points
76 .iter()
77 .filter(|p| p.is_regression && p.change_percent > 0.0)
78 .count();
79 let improvement_count = points.iter().filter(|p| p.change_percent < 0.0).count();
80 Self {
81 timestamp: std::time::SystemTime::now()
82 .duration_since(std::time::UNIX_EPOCH)
83 .unwrap_or_default()
84 .as_secs(),
85 points,
86 regression_count,
87 improvement_count,
88 }
89 }
90}
91
92pub fn compute_change(current: f64, baseline: f64) -> (f64, bool) {
94 if baseline == 0.0 {
95 return (0.0, false);
96 }
97 let change_percent = ((current - baseline) / baseline) * 100.0;
98 let is_regression = change_percent.abs() >= 10.0;
99 (change_percent, is_regression)
100}