sql_cli/benchmarks/
metrics.rs1use std::time::{Duration, Instant};
2
3#[derive(Debug, Clone)]
4pub struct BenchmarkMetrics {
5 pub query_parse_time: Duration,
6 pub query_plan_time: Duration,
7 pub query_execute_time: Duration,
8 pub total_time: Duration,
9
10 pub rows_processed: usize,
11 pub rows_returned: usize,
12 pub rows_per_second: f64,
13
14 pub peak_memory_bytes: Option<usize>,
15 pub allocations_count: Option<usize>,
16
17 pub table_scans: usize,
18 pub expressions_evaluated: usize,
19 pub functions_called: usize,
20}
21
22impl BenchmarkMetrics {
23 pub fn new() -> Self {
24 BenchmarkMetrics {
25 query_parse_time: Duration::ZERO,
26 query_plan_time: Duration::ZERO,
27 query_execute_time: Duration::ZERO,
28 total_time: Duration::ZERO,
29 rows_processed: 0,
30 rows_returned: 0,
31 rows_per_second: 0.0,
32 peak_memory_bytes: None,
33 allocations_count: None,
34 table_scans: 0,
35 expressions_evaluated: 0,
36 functions_called: 0,
37 }
38 }
39
40 pub fn calculate_throughput(&mut self) {
41 if self.total_time.as_secs_f64() > 0.0 {
42 self.rows_per_second = self.rows_processed as f64 / self.total_time.as_secs_f64();
43 }
44 }
45
46 pub fn to_csv_row(&self) -> String {
47 format!(
48 "{:.3},{:.3},{:.3},{:.3},{},{},{:.0}",
49 self.query_parse_time.as_secs_f64() * 1000.0,
50 self.query_plan_time.as_secs_f64() * 1000.0,
51 self.query_execute_time.as_secs_f64() * 1000.0,
52 self.total_time.as_secs_f64() * 1000.0,
53 self.rows_processed,
54 self.rows_returned,
55 self.rows_per_second
56 )
57 }
58}
59
60#[derive(Debug)]
61pub struct BenchmarkResult {
62 pub query_name: String,
63 pub query_category: String,
64 pub table_name: String,
65 pub row_count: usize,
66 pub metrics: BenchmarkMetrics,
67 pub error: Option<String>,
68}
69
70impl BenchmarkResult {
71 pub fn new(
72 query_name: String,
73 query_category: String,
74 table_name: String,
75 row_count: usize,
76 ) -> Self {
77 BenchmarkResult {
78 query_name,
79 query_category,
80 table_name,
81 row_count,
82 metrics: BenchmarkMetrics::new(),
83 error: None,
84 }
85 }
86
87 pub fn to_csv_row(&self) -> String {
88 format!(
89 "{},{},{},{},{}",
90 self.query_name,
91 self.table_name,
92 self.row_count,
93 self.metrics.to_csv_row(),
94 self.error.as_ref().unwrap_or(&"OK".to_string())
95 )
96 }
97}
98
99pub struct MetricsCollector {
100 start: Option<Instant>,
101 phase_start: Option<Instant>,
102 current_metrics: BenchmarkMetrics,
103}
104
105impl MetricsCollector {
106 pub fn new() -> Self {
107 MetricsCollector {
108 start: None,
109 phase_start: None,
110 current_metrics: BenchmarkMetrics::new(),
111 }
112 }
113
114 pub fn start_total(&mut self) {
115 self.start = Some(Instant::now());
116 }
117
118 pub fn start_phase(&mut self) {
119 self.phase_start = Some(Instant::now());
120 }
121
122 pub fn end_parse_phase(&mut self) {
123 if let Some(start) = self.phase_start {
124 self.current_metrics.query_parse_time = start.elapsed();
125 }
126 }
127
128 pub fn end_plan_phase(&mut self) {
129 if let Some(start) = self.phase_start {
130 self.current_metrics.query_plan_time = start.elapsed();
131 }
132 }
133
134 pub fn end_execute_phase(&mut self) {
135 if let Some(start) = self.phase_start {
136 self.current_metrics.query_execute_time = start.elapsed();
137 }
138 }
139
140 pub fn end_total(&mut self) {
141 if let Some(start) = self.start {
142 self.current_metrics.total_time = start.elapsed();
143 }
144 }
145
146 pub fn set_rows(&mut self, processed: usize, returned: usize) {
147 self.current_metrics.rows_processed = processed;
148 self.current_metrics.rows_returned = returned;
149 self.current_metrics.calculate_throughput();
150 }
151
152 pub fn get_metrics(&self) -> BenchmarkMetrics {
153 self.current_metrics.clone()
154 }
155}