Skip to main content

rival/eval/
profile.rs

1//! Per-instruction profiling for the rival machine.
2//!
3//! Rival's evaluator exposes profiling data via [`Execution`] records,
4//! which can be accessed via [`Machine::execution_records`](crate::Machine::execution_records)
5//! or [`Machine::take_executions`](crate::Machine::take_executions).
6
7/// A single recorded execution of a Rival interval operator.
8///
9/// Each execution corresponds to a single interval operator being executed.
10/// The [`name`](Execution::name) names the operator, except the special
11/// name `"adjust"`, in which case it refers to an internal precision-tuning
12/// pass.
13/// The [`number`](Execution::number) gives its position in the compiled
14/// instruction sequence; this allows disambiguating if an expression contains,
15/// say, multiple addition operations.
16/// The [`precision`](Execution::precision) is the working precision in bits
17/// that the operator was executed at,
18/// the [`time_ms`](Execution::time_ms) is the time, in milliseconds, that
19/// the execution took,
20/// and the [`iteration`](Execution::iteration) records which sampling
21/// iteration triggered the execution.
22///
23/// Note that, because Rival executes the register machine multiple times,
24/// the same operator (with the same name and number) can appear multiple
25/// times for a single point. On the other hand, in some iterations Rival
26/// might skip some operators, if the precision is unchanged from previous
27/// iterations, so not every operator may show up in the executions list
28/// the same number of times.
29#[derive(Clone, Copy, Debug)]
30pub struct Execution {
31    /// The name of the operator, or `"adjust"` for precision-tuning passes.
32    pub name: &'static str,
33    /// Position in the compiled instruction sequence (-1 for adjust passes).
34    pub number: i32,
35    /// Working precision in bits for this execution.
36    pub precision: u32,
37    /// Wall-clock time in milliseconds.
38    pub time_ms: f64,
39    /// The sampling iteration that triggered this execution.
40    pub iteration: usize,
41}
42
43impl Default for Execution {
44    fn default() -> Self {
45        Execution {
46            name: "",
47            number: 0,
48            precision: 0,
49            time_ms: 0.0,
50            iteration: 0,
51        }
52    }
53}
54
55#[derive(Debug)]
56pub(crate) struct Profiler {
57    records: Vec<Execution>,
58    ptr: usize,
59}
60
61impl Profiler {
62    /// Create a profiler with a fixed capacity (number of records)
63    pub(crate) fn with_capacity(capacity: usize) -> Self {
64        Self {
65            records: vec![Execution::default(); capacity],
66            ptr: 0,
67        }
68    }
69
70    /// Reset the profiler write pointer without clearing memory
71    #[inline]
72    pub(crate) fn reset(&mut self) {
73        self.ptr = 0;
74    }
75
76    /// Slice of current execution records
77    #[inline]
78    pub(crate) fn records(&self) -> &[Execution] {
79        &self.records[..self.ptr]
80    }
81
82    /// Record an execution if capacity allows
83    #[inline]
84    pub(crate) fn record(&mut self, exec: Execution) {
85        if self.ptr < self.records.len() {
86            self.records[self.ptr] = exec;
87            self.ptr += 1;
88        }
89    }
90}