miri/
clock.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use std::cell::Cell;
use std::time::{Duration, Instant as StdInstant};

/// When using a virtual clock, this defines how many nanoseconds we pretend are passing for each
/// basic block.
/// This number is pretty random, but it has been shown to approximately cause
/// some sample programs to run within an order of magnitude of real time on desktop CPUs.
/// (See `tests/pass/shims/time-with-isolation*.rs`.)
const NANOSECONDS_PER_BASIC_BLOCK: u128 = 5000;

#[derive(Debug)]
pub struct Instant {
    kind: InstantKind,
}

#[derive(Debug)]
enum InstantKind {
    Host(StdInstant),
    Virtual { nanoseconds: u128 },
}

impl Instant {
    /// Will try to add `duration`, but if that overflows it may add less.
    pub fn add_lossy(&self, duration: Duration) -> Instant {
        match self.kind {
            InstantKind::Host(instant) => {
                // If this overflows, try adding just 1h and assume that will not overflow.
                let i = instant
                    .checked_add(duration)
                    .unwrap_or_else(|| instant.checked_add(Duration::from_secs(3600)).unwrap());
                Instant { kind: InstantKind::Host(i) }
            }
            InstantKind::Virtual { nanoseconds } => {
                let n = nanoseconds.saturating_add(duration.as_nanos());
                Instant { kind: InstantKind::Virtual { nanoseconds: n } }
            }
        }
    }

    pub fn duration_since(&self, earlier: Instant) -> Duration {
        match (&self.kind, earlier.kind) {
            (InstantKind::Host(instant), InstantKind::Host(earlier)) =>
                instant.duration_since(earlier),
            (
                InstantKind::Virtual { nanoseconds },
                InstantKind::Virtual { nanoseconds: earlier },
            ) => {
                let duration = nanoseconds.saturating_sub(earlier);
                // `Duration` does not provide a nice constructor from a `u128` of nanoseconds,
                // so we have to implement this ourselves.
                // It is possible for second to overflow because u64::MAX < (u128::MAX / 1e9).
                // It will be saturated to u64::MAX seconds if the value after division exceeds u64::MAX.
                let seconds = u64::try_from(duration / 1_000_000_000).unwrap_or(u64::MAX);
                // It is impossible for nanosecond to overflow because u32::MAX > 1e9.
                let nanosecond = u32::try_from(duration.wrapping_rem(1_000_000_000)).unwrap();
                Duration::new(seconds, nanosecond)
            }
            _ => panic!("all `Instant` must be of the same kind"),
        }
    }
}

/// A monotone clock used for `Instant` simulation.
#[derive(Debug)]
pub struct Clock {
    kind: ClockKind,
}

#[derive(Debug)]
enum ClockKind {
    Host {
        /// The "epoch" for this machine's monotone clock:
        /// the moment we consider to be time = 0.
        epoch: StdInstant,
    },
    Virtual {
        /// The "current virtual time".
        nanoseconds: Cell<u128>,
    },
}

impl Clock {
    /// Create a new clock based on the availability of communication with the host.
    pub fn new(communicate: bool) -> Self {
        let kind = if communicate {
            ClockKind::Host { epoch: StdInstant::now() }
        } else {
            ClockKind::Virtual { nanoseconds: 0.into() }
        };

        Self { kind }
    }

    /// Let the time pass for a small interval.
    pub fn tick(&self) {
        match &self.kind {
            ClockKind::Host { .. } => {
                // Time will pass without us doing anything.
            }
            ClockKind::Virtual { nanoseconds } => {
                nanoseconds.update(|x| x + NANOSECONDS_PER_BASIC_BLOCK);
            }
        }
    }

    /// Sleep for the desired duration.
    pub fn sleep(&self, duration: Duration) {
        match &self.kind {
            ClockKind::Host { .. } => std::thread::sleep(duration),
            ClockKind::Virtual { nanoseconds } => {
                // Just pretend that we have slept for some time.
                let nanos: u128 = duration.as_nanos();
                nanoseconds.update(|x| {
                    x.checked_add(nanos)
                        .expect("Miri's virtual clock cannot represent an execution this long")
                });
            }
        }
    }

    /// Return the `epoch` instant (time = 0), to convert between monotone instants and absolute durations.
    pub fn epoch(&self) -> Instant {
        match &self.kind {
            ClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) },
            ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
        }
    }

    pub fn now(&self) -> Instant {
        match &self.kind {
            ClockKind::Host { .. } => Instant { kind: InstantKind::Host(StdInstant::now()) },
            ClockKind::Virtual { nanoseconds } =>
                Instant { kind: InstantKind::Virtual { nanoseconds: nanoseconds.get() } },
        }
    }
}