Skip to main content

fast_telemetry/metric/
gauge_f64.rs

1//! Atomic gauge for floating-point values.
2
3use crossbeam_utils::CachePadded;
4use std::sync::atomic::{AtomicU64, Ordering};
5
6/// A cache-padded atomic gauge for floating-point point-in-time measurements.
7///
8/// Uses `AtomicU64` to store the bit representation of an `f64`, enabling
9/// atomic operations on floating-point values.
10///
11/// # Usage
12///
13/// Use this for metrics that require decimal precision, such as:
14/// - Memory usage in MB/GB
15/// - CPU utilization percentages
16/// - Ratios and rates
17///
18/// For integer values, prefer [`Gauge`] which uses `i64` directly.
19///
20/// [`Gauge`]: crate::Gauge
21pub struct GaugeF64 {
22    bits: CachePadded<AtomicU64>,
23}
24
25impl GaugeF64 {
26    /// Create a new gauge initialized to zero.
27    pub fn new() -> Self {
28        Self {
29            bits: CachePadded::new(AtomicU64::new(0.0_f64.to_bits())),
30        }
31    }
32
33    /// Set the gauge to a value.
34    #[inline]
35    pub fn set(&self, value: f64) {
36        self.bits.store(value.to_bits(), Ordering::Relaxed);
37    }
38
39    /// Get the current value.
40    #[inline]
41    pub fn get(&self) -> f64 {
42        f64::from_bits(self.bits.load(Ordering::Relaxed))
43    }
44}
45
46impl Default for GaugeF64 {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn test_basic_operations() {
58        let gauge = GaugeF64::new();
59        assert_eq!(gauge.get(), 0.0);
60
61        gauge.set(44331.8);
62        assert!((gauge.get() - 44331.8).abs() < f64::EPSILON);
63
64        gauge.set(-273.15);
65        assert!((gauge.get() - (-273.15)).abs() < f64::EPSILON);
66    }
67
68    #[test]
69    fn test_small_decimals() {
70        let gauge = GaugeF64::new();
71        gauge.set(0.00001);
72        assert!((gauge.get() - 0.00001).abs() < f64::EPSILON);
73    }
74}