Skip to main content

revmc_runtime/runtime/
stats.rs

1//! Runtime statistics.
2
3use std::sync::atomic::{AtomicU64, Ordering};
4
5/// Atomic counters for runtime observability.
6#[derive(Debug, Default)]
7pub(crate) struct RuntimeStats {
8    /// Total lookups that returned a compiled function.
9    pub(crate) lookup_hits: AtomicU64,
10    /// Total lookups that returned interpret (not ready).
11    pub(crate) lookup_misses: AtomicU64,
12    /// Total lookup events dropped due to event-queue overflow.
13    pub(crate) events_dropped: AtomicU64,
14    /// Total number of entries evicted (idle + budget).
15    pub(crate) evictions: AtomicU64,
16    /// Total number of compilations dispatched (JIT promotions + AOT requests).
17    pub(crate) compilations_dispatched: AtomicU64,
18    /// Total number of successful compilations (JIT + AOT).
19    pub(crate) compilations_succeeded: AtomicU64,
20    /// Total number of failed compilations (JIT + AOT).
21    pub(crate) compilations_failed: AtomicU64,
22}
23
24/// Gauge values sampled at snapshot time.
25#[derive(Clone, Copy, Debug, Default)]
26pub(crate) struct RuntimeStatsGauges {
27    pub(crate) resident_entries: u64,
28    pub(crate) events_queued: u64,
29    pub(crate) command_queue_len: u64,
30}
31
32/// A point-in-time snapshot of runtime stats.
33#[derive(Clone, Copy, Debug, Default)]
34pub struct RuntimeStatsSnapshot {
35    /// Total lookups that returned a compiled function.
36    pub lookup_hits: u64,
37    /// Total lookups that returned interpret (not ready).
38    pub lookup_misses: u64,
39    /// Total lookup events dropped due to event-queue overflow.
40    pub events_dropped: u64,
41    /// Number of entries in the resident compiled map.
42    pub resident_entries: u64,
43    /// Number of lookup events currently queued for the backend.
44    pub events_queued: u64,
45    /// Number of pending control commands queued for the backend.
46    pub command_queue_len: u64,
47    /// Number of compilation jobs currently in flight (dispatched but not yet completed).
48    pub pending_jobs: u64,
49    /// Bytes allocated for executable JIT code sections.
50    ///
51    /// Sourced from the LLVM JIT memory usage plugin. Reflects live memory:
52    /// bytes are added on compilation and subtracted when JIT code is freed.
53    /// `0` if the LLVM backend is not initialized.
54    pub jit_code_bytes: u64,
55    /// Bytes allocated for non-executable JIT data sections.
56    ///
57    /// Sourced from the LLVM JIT memory usage plugin. `0` if not initialized.
58    pub jit_data_bytes: u64,
59    /// Total number of entries evicted (idle + budget).
60    pub evictions: u64,
61    /// Total number of compilations dispatched (JIT promotions + AOT requests).
62    pub compilations_dispatched: u64,
63    /// Total number of successful compilations (JIT + AOT).
64    pub compilations_succeeded: u64,
65    /// Total number of failed compilations (JIT + AOT).
66    pub compilations_failed: u64,
67}
68
69impl RuntimeStatsSnapshot {
70    /// Total bytes allocated by the JIT engine (code + data).
71    pub fn jit_total_bytes(&self) -> u64 {
72        self.jit_code_bytes + self.jit_data_bytes
73    }
74}
75
76impl RuntimeStats {
77    pub(crate) fn snapshot(&self, gauges: RuntimeStatsGauges) -> RuntimeStatsSnapshot {
78        #[cfg(feature = "llvm")]
79        let (jit_code_bytes, jit_data_bytes) = crate::llvm::jit_memory_usage()
80            .map(|u| (u.code_bytes as u64, u.data_bytes as u64))
81            .unwrap_or((0, 0));
82        #[cfg(not(feature = "llvm"))]
83        let (jit_code_bytes, jit_data_bytes) = (0, 0);
84
85        let dispatched = self.compilations_dispatched.load(Ordering::Relaxed);
86        let succeeded = self.compilations_succeeded.load(Ordering::Relaxed);
87        let failed = self.compilations_failed.load(Ordering::Relaxed);
88        let pending_jobs = dispatched.saturating_sub(succeeded.saturating_add(failed));
89
90        RuntimeStatsSnapshot {
91            lookup_hits: self.lookup_hits.load(Ordering::Relaxed),
92            lookup_misses: self.lookup_misses.load(Ordering::Relaxed),
93            events_dropped: self.events_dropped.load(Ordering::Relaxed),
94            resident_entries: gauges.resident_entries,
95            events_queued: gauges.events_queued,
96            command_queue_len: gauges.command_queue_len,
97            pending_jobs,
98            jit_code_bytes,
99            jit_data_bytes,
100            evictions: self.evictions.load(Ordering::Relaxed),
101            compilations_dispatched: dispatched,
102            compilations_succeeded: succeeded,
103            compilations_failed: failed,
104        }
105    }
106}