miri/
clock.rs

1use std::cell::Cell;
2use std::time::{Duration, Instant as StdInstant};
3
4/// When using a virtual clock, this defines how many nanoseconds we pretend are passing for each
5/// basic block.
6/// This number is pretty random, but it has been shown to approximately cause
7/// some sample programs to run within an order of magnitude of real time on desktop CPUs.
8/// (See `tests/pass/shims/time-with-isolation*.rs`.)
9const NANOSECONDS_PER_BASIC_BLOCK: u128 = 5000;
10
11#[derive(Debug)]
12pub struct Instant {
13    kind: InstantKind,
14}
15
16#[derive(Debug)]
17enum InstantKind {
18    Host(StdInstant),
19    Virtual { nanoseconds: u128 },
20}
21
22impl Instant {
23    /// Will try to add `duration`, but if that overflows it may add less.
24    pub fn add_lossy(&self, duration: Duration) -> Instant {
25        match self.kind {
26            InstantKind::Host(instant) => {
27                // If this overflows, try adding just 1h and assume that will not overflow.
28                let i = instant
29                    .checked_add(duration)
30                    .unwrap_or_else(|| instant.checked_add(Duration::from_secs(3600)).unwrap());
31                Instant { kind: InstantKind::Host(i) }
32            }
33            InstantKind::Virtual { nanoseconds } => {
34                let n = nanoseconds.saturating_add(duration.as_nanos());
35                Instant { kind: InstantKind::Virtual { nanoseconds: n } }
36            }
37        }
38    }
39
40    pub fn duration_since(&self, earlier: Instant) -> Duration {
41        match (&self.kind, earlier.kind) {
42            (InstantKind::Host(instant), InstantKind::Host(earlier)) =>
43                instant.duration_since(earlier),
44            (
45                InstantKind::Virtual { nanoseconds },
46                InstantKind::Virtual { nanoseconds: earlier },
47            ) => {
48                let duration = nanoseconds.saturating_sub(earlier);
49                cfg_select! {
50                    bootstrap => {
51                         // `Duration` does not provide a nice constructor from a `u128` of nanoseconds,
52                        // so we have to implement this ourselves.
53                        // It is possible for second to overflow because u64::MAX < (u128::MAX / 1e9).
54                        // It will be saturated to u64::MAX seconds if the value after division exceeds u64::MAX.
55                        let seconds = u64::try_from(duration / 1_000_000_000).unwrap_or(u64::MAX);
56                        // It is impossible for nanosecond to overflow because u32::MAX > 1e9.
57                        let nanosecond = u32::try_from(duration.wrapping_rem(1_000_000_000)).unwrap();
58                        Duration::new(seconds, nanosecond)
59                    }
60                    _ => {
61                        Duration::from_nanos_u128(duration)
62                    }
63                }
64            }
65            _ => panic!("all `Instant` must be of the same kind"),
66        }
67    }
68}
69
70/// A monotone clock used for `Instant` simulation.
71#[derive(Debug)]
72pub struct MonotonicClock {
73    kind: MonotonicClockKind,
74}
75
76#[derive(Debug)]
77enum MonotonicClockKind {
78    Host {
79        /// The "epoch" for this machine's monotone clock:
80        /// the moment we consider to be time = 0.
81        epoch: StdInstant,
82    },
83    Virtual {
84        /// The "current virtual time".
85        nanoseconds: Cell<u128>,
86    },
87}
88
89impl MonotonicClock {
90    /// Create a new clock based on the availability of communication with the host.
91    pub fn new(communicate: bool) -> Self {
92        let kind = if communicate {
93            MonotonicClockKind::Host { epoch: StdInstant::now() }
94        } else {
95            MonotonicClockKind::Virtual { nanoseconds: 0.into() }
96        };
97
98        Self { kind }
99    }
100
101    /// Let the time pass for a small interval.
102    pub fn tick(&self) {
103        match &self.kind {
104            MonotonicClockKind::Host { .. } => {
105                // Time will pass without us doing anything.
106            }
107            MonotonicClockKind::Virtual { nanoseconds } => {
108                nanoseconds.update(|x| x + NANOSECONDS_PER_BASIC_BLOCK);
109            }
110        }
111    }
112
113    /// Sleep for the desired duration.
114    pub fn sleep(&self, duration: Duration) {
115        match &self.kind {
116            MonotonicClockKind::Host { .. } => std::thread::sleep(duration),
117            MonotonicClockKind::Virtual { nanoseconds } => {
118                // Just pretend that we have slept for some time.
119                let nanos: u128 = duration.as_nanos();
120                nanoseconds.update(|x| {
121                    x.checked_add(nanos)
122                        .expect("Miri's virtual clock cannot represent an execution this long")
123                });
124            }
125        }
126    }
127
128    /// Return the `epoch` instant (time = 0), to convert between monotone instants and absolute durations.
129    pub fn epoch(&self) -> Instant {
130        match &self.kind {
131            MonotonicClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) },
132            MonotonicClockKind::Virtual { .. } =>
133                Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
134        }
135    }
136
137    pub fn now(&self) -> Instant {
138        match &self.kind {
139            MonotonicClockKind::Host { .. } =>
140                Instant { kind: InstantKind::Host(StdInstant::now()) },
141            MonotonicClockKind::Virtual { nanoseconds } =>
142                Instant { kind: InstantKind::Virtual { nanoseconds: nanoseconds.get() } },
143        }
144    }
145}