Skip to main content

react_compiler/
timing.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6//! Simple timing accumulator for profiling compiler passes.
7//!
8//! Uses `std::time::Instant` unconditionally (cheap when not storing results).
9//! Controlled by the `__profiling` flag in plugin options.
10
11use serde::Serialize;
12use std::time::{Duration, Instant};
13
14/// A single timing entry recording how long a named phase took.
15#[derive(Debug, Clone, Serialize)]
16pub struct TimingEntry {
17    pub name: String,
18    pub duration_us: u64,
19}
20
21/// Accumulates timing data for compiler passes.
22pub struct TimingData {
23    enabled: bool,
24    entries: Vec<(String, Duration)>,
25    current_name: Option<String>,
26    current_start: Option<Instant>,
27}
28
29impl TimingData {
30    /// Create a new TimingData. If `enabled` is false, all operations are no-ops.
31    pub fn new(enabled: bool) -> Self {
32        Self {
33            enabled,
34            entries: Vec::new(),
35            current_name: None,
36            current_start: None,
37        }
38    }
39
40    /// Start timing a named phase. Stops any currently running phase first.
41    pub fn start(&mut self, name: &str) {
42        if !self.enabled {
43            return;
44        }
45        // Stop any currently running phase
46        if self.current_start.is_some() {
47            self.stop();
48        }
49        self.current_name = Some(name.to_string());
50        self.current_start = Some(Instant::now());
51    }
52
53    /// Stop the currently running phase and record its duration.
54    pub fn stop(&mut self) {
55        if !self.enabled {
56            return;
57        }
58        if let (Some(name), Some(start)) = (self.current_name.take(), self.current_start.take()) {
59            self.entries.push((name, start.elapsed()));
60        }
61    }
62
63    /// Consume this TimingData and return the collected entries.
64    pub fn into_entries(mut self) -> Vec<TimingEntry> {
65        // Stop any still-running phase
66        self.stop();
67        self.entries
68            .into_iter()
69            .map(|(name, duration)| TimingEntry {
70                name,
71                duration_us: duration.as_micros() as u64,
72            })
73            .collect()
74    }
75}