Skip to main content

cbtop/bricks/analyzers/
throughput.rs

1//! Throughput analyzer using Little's Law
2
3use crate::brick::{Brick, BrickAssertion, BrickBudget, BrickVerification};
4use std::any::Any;
5
6/// Little's Law: L = λW
7/// L = average number in system
8/// λ = arrival rate
9/// W = average time in system
10pub struct ThroughputAnalyzerBrick {
11    samples: Vec<f64>,
12    arrival_rate: f64,
13    avg_latency_ms: f64,
14}
15
16impl ThroughputAnalyzerBrick {
17    pub fn new() -> Self {
18        Self {
19            samples: Vec::new(),
20            arrival_rate: 0.0,
21            avg_latency_ms: 0.0,
22        }
23    }
24
25    pub fn analyze(&mut self, ops_per_sec: f64, latency_ms: f64) -> ThroughputResult {
26        self.arrival_rate = ops_per_sec;
27        self.avg_latency_ms = latency_ms;
28
29        // Little's Law: L = λW
30        let items_in_system = ops_per_sec * (latency_ms / 1000.0);
31
32        ThroughputResult {
33            ops_per_sec,
34            latency_ms,
35            items_in_system,
36            is_saturated: items_in_system > 1.0,
37        }
38    }
39
40    pub fn reset(&mut self) {
41        self.samples.clear();
42        self.arrival_rate = 0.0;
43        self.avg_latency_ms = 0.0;
44    }
45}
46
47#[derive(Debug, Clone)]
48pub struct ThroughputResult {
49    pub ops_per_sec: f64,
50    pub latency_ms: f64,
51    pub items_in_system: f64,
52    pub is_saturated: bool,
53}
54
55impl Default for ThroughputAnalyzerBrick {
56    fn default() -> Self {
57        Self::new()
58    }
59}
60
61impl Brick for ThroughputAnalyzerBrick {
62    fn brick_name(&self) -> &'static str {
63        "throughput_analyzer"
64    }
65
66    fn assertions(&self) -> Vec<BrickAssertion> {
67        vec![
68            BrickAssertion::custom("littles_law_valid", |_| true),
69            BrickAssertion::max_latency_ms(1),
70        ]
71    }
72
73    fn budget(&self) -> BrickBudget {
74        BrickBudget {
75            collect_ms: 1,
76            layout_ms: 0,
77            render_ms: 0,
78        }
79    }
80
81    fn verify(&self) -> BrickVerification {
82        let mut v = BrickVerification::new();
83        for assertion in self.assertions() {
84            v.check(&assertion);
85        }
86        v
87    }
88
89    fn as_any(&self) -> &dyn Any {
90        self
91    }
92}