Skip to content

Commit a7bcb84

Browse files
committed
Fully encapsulate trace as RREvents for new record/replay embedders
1 parent 569b098 commit a7bcb84

File tree

5 files changed

+109
-88
lines changed

5 files changed

+109
-88
lines changed

crates/rr/src/events.rs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -172,30 +172,6 @@ macro_rules! event_error_types {
172172
);
173173
}
174174

175-
/// Events used as markers for debugging/testing in traces
176-
///
177-
/// Marker events should be injectable at any point in a record
178-
/// trace without impacting functional correctness of replay
179-
pub mod marker_events {
180-
use serde::{Deserialize, Serialize};
181-
182-
/// A Nop event
183-
#[derive(Debug, Clone, Serialize, Deserialize)]
184-
pub struct NopEvent;
185-
186-
/// An event for custom String messages
187-
#[derive(Debug, Clone, Serialize, Deserialize)]
188-
pub struct CustomMessageEvent(pub String);
189-
impl<T> From<T> for CustomMessageEvent
190-
where
191-
T: Into<String>,
192-
{
193-
fn from(v: T) -> Self {
194-
Self(v.into())
195-
}
196-
}
197-
}
198-
199175
pub mod common_events;
200176
pub mod component_events;
201177
pub mod core_events;

crates/rr/src/events/common_events.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! or [`core_events`]
55
66
use super::*;
7+
use crate::RecordSettings;
78
use serde::{Deserialize, Serialize};
89

910
/// A call event from Wasm (core or component) into the host
@@ -40,3 +41,37 @@ impl Validate<&Result<RRFuncArgVals>> for WasmFuncReturnEvent {
4041
event_error_types! {
4142
pub struct WasmFuncReturnError(..)
4243
}
44+
45+
/// Signature of recorded trace.
46+
#[derive(Debug, Clone, Serialize, Deserialize)]
47+
pub struct TraceSignatureEvent {
48+
/// Checksum of the trace contents.
49+
///
50+
/// This can be used to verify integrity of the trace during replay.
51+
pub checksum: String,
52+
/// Settings used during trace recording.
53+
pub settings: RecordSettings,
54+
}
55+
56+
impl Validate<str> for TraceSignatureEvent {
57+
fn validate(&self, expect: &str) -> Result<(), ReplayError> {
58+
self.log();
59+
if self.checksum == expect {
60+
Ok(())
61+
} else {
62+
Err(ReplayError::FailedValidation)
63+
}
64+
}
65+
}
66+
67+
/// A diagnostic event for custom String messages.
68+
#[derive(Debug, Clone, Serialize, Deserialize)]
69+
pub struct CustomMessageEvent(pub String);
70+
impl<T> From<T> for CustomMessageEvent
71+
where
72+
T: Into<String>,
73+
{
74+
fn from(v: T) -> Self {
75+
Self(v.into())
76+
}
77+
}

crates/rr/src/io.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
use super::RREvent;
12
use anyhow::Result;
23
use core::any::Any;
34
use postcard;
4-
use serde::{Deserialize, Serialize};
55

66
cfg_if::cfg_if! {
77
if #[cfg(feature = "std")] {
@@ -130,12 +130,12 @@ cfg_if::cfg_if! {
130130
}
131131
}
132132

133-
/// Serialize and write `value` to a `RecordWriter`
133+
/// Serialize and write an `RREvent` to a `RecordWriter`
134134
///
135-
/// Currently uses `postcard` serializer
136-
pub fn to_record_writer<T, W>(value: &T, writer: &mut W) -> Result<()>
135+
/// This is the lowest-level underlying writer function for RR events,
136+
/// helpful for implementing `Recorder`s. Currently uses [`postcard`] serializer.
137+
pub fn to_record_writer<W>(value: &RREvent, writer: &mut W) -> Result<()>
137138
where
138-
T: Serialize + ?Sized,
139139
W: RecordWriter + ?Sized,
140140
{
141141
#[cfg(feature = "std")]
@@ -150,13 +150,12 @@ where
150150
Ok(())
151151
}
152152

153-
/// Read and deserialize a `value` from a `ReplayReader`.
153+
/// Read and deserialize an `RREvent` from a `ReplayReader`.
154154
///
155-
/// Currently uses `postcard` deserializer, with optional scratch
156-
/// buffer to deserialize into
157-
pub fn from_replay_reader<'a, T, R>(reader: &'a mut R, scratch: &'a mut [u8]) -> Result<T>
155+
/// This is the lowest-level underlying reader function for RR events,
156+
/// helpful for implementing `Replayer`s. Currently uses [`postcard`] deserializer.
157+
pub fn from_replay_reader<'a, R>(reader: &'a mut R, scratch: &'a mut [u8]) -> Result<RREvent>
158158
where
159-
T: Deserialize<'a>,
160159
R: ReplayReader + ?Sized,
161160
{
162161
#[cfg(feature = "std")]
@@ -167,7 +166,7 @@ where
167166
{
168167
let flavor = ReplayReaderFlavor { reader, scratch };
169168
let mut deserializer = postcard::Deserializer::from_flavor(flavor);
170-
let t = T::deserialize(&mut deserializer)?;
169+
let t = serde::Deserialize::deserialize(&mut deserializer)?;
171170
deserializer.finalize()?;
172171
Ok(t)
173172
}

crates/rr/src/lib.rs

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use anyhow::Result;
22
use core::fmt;
33
pub use events::{
44
EventError, RRFuncArgVals, ResultEvent, Validate, common_events, component_events, core_events,
5-
marker_events,
65
};
76
pub use io::{RecordWriter, ReplayReader, from_replay_reader, to_record_writer};
87
use serde::{Deserialize, Serialize};
@@ -54,21 +53,28 @@ mod io;
5453
/// Macro template for [`RREvent`] and its conversion to/from specific
5554
/// event types
5655
macro_rules! rr_event {
57-
(
58-
$(
59-
$(#[doc = $doc:literal])*
60-
$variant:ident($event:ty)
61-
),*
62-
) => (
56+
(
57+
$(
58+
$(#[doc = $doc_np:literal])*
59+
$variant_no_payload:ident
60+
),*
61+
;
62+
$(
63+
$(#[doc = $doc:literal])*
64+
$variant:ident($event:ty)
65+
),*
66+
) => (
6367
/// A single, unified, low-level recording/replay event
6468
///
6569
/// This type is the narrow waist for serialization/deserialization.
6670
/// Higher-level events (e.g. import calls consisting of lifts and lowers
6771
/// of parameter/return types) may drop down to one or more [`RREvent`]s
6872
#[derive(Debug, Clone, Serialize, Deserialize)]
6973
pub enum RREvent {
70-
/// Event signalling the end of a trace
71-
Eof,
74+
$(
75+
$(#[doc = $doc_np])*
76+
$variant_no_payload,
77+
)*
7278
$(
7379
$(#[doc = $doc])*
7480
$variant($event),
@@ -78,9 +84,11 @@ macro_rules! rr_event {
7884
impl fmt::Display for RREvent {
7985
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8086
match self {
81-
Self::Eof => write!(f, "Eof event"),
8287
$(
83-
Self::$variant(e) => write!(f, "{:?}", e),
88+
Self::$variant_no_payload => write!(f, "{}", stringify!($variant_no_payload)),
89+
)*
90+
$(
91+
Self::$variant(payload) => write!(f, "{:?}", payload),
8492
)*
8593
}
8694
}
@@ -104,16 +112,25 @@ macro_rules! rr_event {
104112
}
105113
}
106114
)*
107-
);
115+
);
116+
108117
}
109118

110119
// Set of supported record/replay events
111120
rr_event! {
112-
// Marker events
113121
/// Nop Event
114-
Nop(marker_events::NopEvent),
115-
/// A custom message
116-
CustomMessage(marker_events::CustomMessageEvent),
122+
Nop,
123+
/// Event signalling the end of a trace
124+
Eof
125+
;
126+
/// The signature of the trace, enabling trace integrity during replay.
127+
///
128+
/// This is always at the start of any valid trace.
129+
TraceSignature(common_events::TraceSignatureEvent),
130+
/// A custom message in the trace, useful for diagnostics.
131+
///
132+
/// Does not affect trace replay functionality
133+
CustomMessage(common_events::CustomMessageEvent),
117134

118135
// Common events for both core or component wasm
119136
// REQUIRED events
@@ -172,11 +189,11 @@ rr_event! {
172189
}
173190

174191
impl RREvent {
175-
/// Indicates whether current event is a marker event
192+
/// Indicates whether current event is a diagnostic event
176193
#[inline]
177-
pub fn is_marker(&self) -> bool {
194+
pub fn is_diagnostic(&self) -> bool {
178195
match self {
179-
Self::Nop(_) | Self::CustomMessage(_) => true,
196+
Self::Nop | Self::CustomMessage(_) => true,
180197
_ => false,
181198
}
182199
}

crates/wasmtime/src/runtime/rr/backend.rs

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,18 @@ impl RecordBuffer {
138138
}
139139

140140
impl Recorder for RecordBuffer {
141-
fn new_recorder(mut writer: impl RecordWriter, settings: RecordSettings) -> Result<Self> {
142-
// Replay requires the Module version and record settings
143-
to_record_writer(ModuleVersionStrategy::WasmtimeVersion.as_str(), &mut writer)?;
144-
to_record_writer(&settings, &mut writer)?;
145-
Ok(RecordBuffer {
141+
fn new_recorder(writer: impl RecordWriter, settings: RecordSettings) -> Result<Self> {
142+
let settings_local = settings.clone();
143+
let mut buf = RecordBuffer {
146144
buf: Vec::new(),
147145
writer: Box::new(writer),
148146
settings,
149-
})
147+
};
148+
buf.record_event(|| common_events::TraceSignatureEvent {
149+
checksum: ModuleVersionStrategy::WasmtimeVersion.as_str().to_string(),
150+
settings: settings_local,
151+
})?;
152+
Ok(buf)
150153
}
151154

152155
#[inline]
@@ -211,7 +214,7 @@ impl Iterator for ReplayBuffer {
211214
if let RREvent::Eof = &event {
212215
self.eof_encountered = true;
213216
break 'event_loop None;
214-
} else if event.is_marker() {
217+
} else if event.is_diagnostic() {
215218
continue 'event_loop;
216219
} else {
217220
log::debug!("Read replay event => {event}");
@@ -245,38 +248,29 @@ impl Drop for ReplayBuffer {
245248
}
246249

247250
impl Replayer for ReplayBuffer {
248-
fn new_replayer(
249-
mut reader: impl ReplayReader + 'static,
250-
settings: ReplaySettings,
251-
) -> Result<Self> {
252-
let mut scratch = [0u8; 12];
253-
// Ensure module versions match
254-
let version = from_replay_reader::<&str, _>(&mut reader, &mut scratch)?;
255-
assert_eq!(
256-
version,
257-
ModuleVersionStrategy::WasmtimeVersion.as_str(),
258-
"Wasmtime version mismatch between engine used for record and replay"
259-
);
260-
261-
// Read the recording settings
262-
let trace_settings: RecordSettings = from_replay_reader(&mut reader, &mut scratch)?;
263-
264-
if settings.validate && !trace_settings.add_validation {
251+
fn new_replayer(reader: impl ReplayReader + 'static, settings: ReplaySettings) -> Result<Self> {
252+
let mut buf = ReplayBuffer {
253+
reader: Box::new(reader),
254+
deser_buffer: vec![0; settings.deserialize_buffer_size],
255+
settings,
256+
// This doesn't matter now; will override after reading header
257+
trace_settings: RecordSettings::default(),
258+
eof_encountered: false,
259+
};
260+
261+
let signature: common_events::TraceSignatureEvent = buf.next_event_typed()?;
262+
// Ensure the trace integrity
263+
signature.validate(ModuleVersionStrategy::WasmtimeVersion.as_str())?;
264+
// Update the trace settings
265+
buf.trace_settings = signature.settings;
266+
267+
if buf.settings.validate && !buf.trace_settings.add_validation {
265268
log::warn!(
266269
"Replay validation will be omitted since the recorded trace has no validation metadata..."
267270
);
268271
}
269272

270-
let deser_buffer = vec![0; settings.deserialize_buffer_size];
271-
let reader = Box::new(reader);
272-
273-
Ok(ReplayBuffer {
274-
reader,
275-
settings,
276-
trace_settings,
277-
deser_buffer,
278-
eof_encountered: false,
279-
})
273+
Ok(buf)
280274
}
281275

282276
#[inline]

0 commit comments

Comments
 (0)