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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Craton Software Company
//! Shared helpers for the W4.2 cross-backend snapshot conformance suite.
//!
//! The W1.3 [cross-version snapshot compat suite][compat] in
//! `tensor-wasm-snapshot/tests/compat.rs` already proves the on-disk format
//! is **backend-independent** — it reads checked-in golden fixtures with
//! the current reader and asserts byte-level equivalence. What it does
//! *not* exercise is the **producer** side under each CUDA backing: when
//! the bytes destined for the snapshot blob come out of a real
//! `cuMemAllocManaged` region (cust, cudarc, or cuda-oxide host), do they
//! still serialise to the identical wire format that golden-fixture
//! consumers expect?
//!
//! That is the regression guard this module enables. It exposes a single
//! generic helper, [`snapshot_round_trip_with_source`], that drives the
//! `SnapshotWriter` → `SnapshotReader` round-trip against three byte
//! sources supplied by the caller. Three sibling test files
//! (`cust_snapshot_conformance.rs`, `cudarc_snapshot_conformance.rs`,
//! `cuda_oxide_snapshot_conformance.rs`) each compile under a different
//! backend feature, allocate buffers via that backend's primitive,
//! populate them with deterministic patterns, and call the helper. The
//! helper asserts the captured blob is decode-able and the restored
//! payload is byte-for-byte identical to the input.
//!
//! Where applicable, tests that touch a real CUDA driver are marked
//! `#[ignore = "requires CUDA hardware"]` per the repo convention so a
//! host-only contributor box runs the *unignored* portion (the
//! pure-`Vec<u8>` baseline that proves the snapshot format itself is
//! backend-stable) without dlopen-ing libcuda.
//!
//! [compat]: ../../tensor-wasm-snapshot/tests/compat.rs
//!
//! # Why this lives in `tensor-wasm-mem` rather than `tensor-wasm-snapshot`
//!
//! The backend allocators (`UnifiedBuffer`, `CudarcUnifiedBuffer`,
//! `CudaOxideUnifiedBuffer`) are defined here; the snapshot crate is
//! deliberately decoupled from any CUDA backing so it remains
//! `cargo build`-able on hosts without a toolkit. The conformance
//! direction we want to exercise is *backend → snapshot*, so the test
//! belongs in the crate that knows what the backends are.
// Some backend-gated test binaries do not pull in every helper. Suppressing
// the per-binary `dead_code` warning here keeps the module reusable across
// the three sibling test files without needing per-helper `#[allow]`
// attributes that would have to be kept in sync.
use ;
use SnapshotReader;
use ;
/// Deterministic tenant ID embedded into every conformance snapshot.
/// Chosen to share no nibble pattern with `CONFORMANCE_INSTANCE_ID` so a
/// byte-swap regression in the metadata encoder is obvious from the
/// failure diff.
pub const CONFORMANCE_TENANT_ID: u64 = 0xB4CC_0AF2_DEAD_BEEF;
/// Deterministic instance ID embedded into every conformance snapshot.
pub const CONFORMANCE_INSTANCE_ID: u128 = 0x1234_5678_9ABC_DEF0_F00D_BABE_CAFE_5A5A;
/// Deterministic wasm-memory payload size in bytes used by the conformance
/// suite. Sized at 8 KiB so:
/// - it is large enough to exercise zstd's dictionary path (>4 KiB
/// compresses meaningfully);
/// - the pattern wraps the byte domain (256) several times to catch any
/// off-by-256 indexing error;
/// - the total round-trip stays well under the cust per-managed-buffer
/// test budget (16 MiB).
pub const CONFORMANCE_WASM_LEN: usize = 8 * 1024;
/// Deterministic gpu-memory payload size in bytes. Smaller than the wasm
/// payload so a swap-of-fields regression in the writer struct is caught
/// by a length mismatch in the assertion.
pub const CONFORMANCE_GPU_LEN: usize = 4 * 1024;
/// Deterministic register-blob size in bytes. Tiny by design — registers
/// are typically a few hundred bytes in practice and the value here
/// prevents the test from accidentally turning into a compression
/// benchmark.
pub const CONFORMANCE_REGISTERS_LEN: usize = 512;
/// Fill `dst` with the wasm-memory byte pattern used by the conformance
/// suite. The pattern is `(i % 251) as u8` — `251` is the largest prime
/// below 256, which guarantees every byte value in `0..251` appears
/// within any contiguous 251-byte window. Choosing a prime modulus also
/// rules out accidental alignment-coincidence bugs (a power-of-two
/// modulus would mask off-by-`page_size` errors).
///
/// Returns `dst` for the convenience of in-line use.
/// Fill `dst` with the gpu-memory byte pattern used by the conformance
/// suite. Distinct from [`fill_wasm_pattern`] so a swap-of-fields bug in
/// the writer would surface as both `wasm_memory` and `gpu_memory`
/// assertions failing simultaneously rather than passing by coincidence.
/// Fill `dst` with the register byte pattern used by the conformance
/// suite. XOR-stamped so it is visibly distinct from the other two
/// payloads when staring at a hex dump.
/// Drive a full `SnapshotWriter::capture` → `SnapshotReader::restore`
/// round-trip against caller-supplied byte slices and assert the
/// recovered payload is byte-for-byte identical to the input.
///
/// The slices may be backed by *any* allocator — a heap `Vec<u8>`, a
/// cust `UnifiedBuffer`, a cudarc `CudarcUnifiedBuffer`, or a
/// `CudaOxideUnifiedBuffer`. The whole point of the helper is that the
/// caller's choice of backing must not influence the wire format
/// produced by the writer or the bytes recovered by the reader.
///
/// # Why no `&InstanceState` parameter
///
/// The InstanceState shape is fixed across backends; only the bytes
/// vary. The helper builds the InstanceState itself with deterministic
/// tenant/instance IDs ([`CONFORMANCE_TENANT_ID`] /
/// [`CONFORMANCE_INSTANCE_ID`]) so the assertions can pin those fields
/// without each call site having to repeat them.
/// Build the three deterministic byte payloads (wasm, gpu, registers)
/// used by the conformance suite into caller-supplied destination
/// slices.
///
/// The destinations are passed in rather than allocated here so each
/// backend's test can route the writes through its own allocator
/// (`UnifiedBuffer::as_mut_slice`, `CudarcUnifiedBuffer::as_mut_slice`,
/// `CudaOxideUnifiedBuffer::as_mut_slice`) and the helper stays
/// allocator-agnostic.
///
/// Panics if any destination length differs from the corresponding
/// `CONFORMANCE_*_LEN` constant — that mismatch indicates a test wrote
/// the wrong setup code, not a backend regression.