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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
// RLX — versatile ML compiler + runtime.
// Copyright (C) 2026 Eugene Hauptmann, Nataliya Kosmyna.
// SPDX-License-Identifier: MIT OR Apache-2.0
//! A heterogeneous mesh where one rank is **pre-synthesized hardware**.
//!
//! rank 0 (coordinator) → rank 1 (general worker, compiles a shipped stage)
//! → rank 2 (fixed-function rank, e.g. an FPGA bitstream)
//! → rank 0
//!
//! The fixed-function rank stands in for a board via [`LoopbackFixedFunction`],
//! so the mesh-side contract — capability handshake, placement refusal, shape
//! enforcement, activation streaming — is exercised with no hardware attached.
use rlx_driver::{NetTransport, ProcessGroup};
use rlx_ir::op::Activation;
use rlx_ir::{DType, Graph, Shape};
use rlx_runtime::dist::node::{
FixedFunction, LoopbackFixedFunction, NodeControl, NodeRole, collect_caps,
serve_fixed_function_n, serve_worker_n,
};
use rlx_runtime::dist::{StageSpec, recv_activation, send_activation, ship_stage};
use std::net::{Ipv4Addr, SocketAddr, TcpListener};
use std::sync::Arc;
use std::thread;
const N: usize = 4;
const STAGE: &str = "relu4-int8-v1";
/// The stage the board implements: ×3 on 4 elements.
fn board_fn(x: &[f32]) -> Vec<f32> {
x.iter().map(|v| v * 3.0).collect()
}
/// The stage the general worker compiles: relu on 4 elements.
fn worker_graph() -> Graph {
let mut g = Graph::new("relu_stage");
let shape = Shape::new(&[1, N], DType::F32);
let x = g.input("x", shape.clone());
let y = g.activation(Activation::Relu, x, shape);
g.set_outputs(vec![y]);
g
}
#[test]
fn fixed_function_rank_joins_mesh_and_streams() {
let world: u32 = 3;
let listeners: Vec<TcpListener> = (0..world)
.map(|_| TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap())
.collect();
let addrs: Vec<SocketAddr> = listeners.iter().map(|l| l.local_addr().unwrap()).collect();
let handles: Vec<_> = listeners
.into_iter()
.enumerate()
.map(|(rank, listener)| {
let addrs = addrs.clone();
thread::spawn(move || -> Result<Vec<f32>, String> {
let rank = rank as u32;
let t = NetTransport::from_listener(rank, world, listener, addrs, 1 << 20)
.map_err(|e| e.to_string())?;
let group = Arc::new(ProcessGroup::new(Arc::new(t)));
match rank {
// ── coordinator ──────────────────────────────────────
0 => {
let caps = collect_caps(&group)?;
assert_eq!(caps.len(), 2, "expected caps from ranks 1..3");
// The board rank must advertise itself as fixed-function.
let fpga = caps
.iter()
.find(|c| matches!(c.role, NodeRole::FixedFunction(_)))
.expect("no fixed-function rank announced");
assert_eq!(fpga.rank, 2);
// Placement must REFUSE a stage the bitstream doesn't
// implement — the whole point of the handshake.
let wrong = StageSpec::new(worker_graph(), "x", "y", "cpu")
.stage_id("some-other-datapath");
let err = fpga.accepts(&wrong).unwrap_err();
assert!(
err.contains(STAGE) && err.contains("some-other-datapath"),
"refusal should name both stages, got: {err}"
);
// An untagged stage is also refused (a general stage
// cannot be silently clocked into a fixed datapath).
let untagged = StageSpec::new(worker_graph(), "x", "y", "cpu");
assert!(fpga.accepts(&untagged).is_err());
// The matching stage is accepted.
let right = StageSpec::new(worker_graph(), "x", "y", "cpu").stage_id(STAGE);
fpga.accepts(&right).expect("matching stage_id must accept");
// A general worker accepts anything.
let general = caps
.iter()
.find(|c| matches!(c.role, NodeRole::Worker))
.expect("no general worker announced");
general
.accepts(&untagged)
.expect("worker accepts any stage");
// Drive one activation through the pipeline.
ship_stage(&group, 1, &untagged)?;
send_activation(&group, 1, &[-1.0, 2.0, -3.0, 4.0])?;
let out = recv_activation(&group, 2)?;
Ok(out)
}
// ── general worker: compiles the shipped stage ────────
1 => {
let caps = rlx_runtime::dist::node::NodeCaps {
rank,
role: NodeRole::Worker,
devices: vec!["cpu".into()],
platform: rlx_runtime::dist::node::platform_tag().into(),
};
serve_worker_n(&group, &caps, |_| Vec::new(), &NodeControl::steps(1))?;
Ok(Vec::new())
}
// ── fixed-function rank: pre-synthesized datapath ─────
_ => {
let ff = FixedFunction::new(STAGE, N, N, DType::F32);
let mut board = LoopbackFixedFunction::new(STAGE, board_fn);
let report = serve_fixed_function_n(
&group,
&ff,
&mut board,
&NodeControl::steps(1),
)?;
assert_eq!(report.activations, 1);
Ok(Vec::new())
}
}
})
})
.collect();
let mut out = Vec::new();
for (i, h) in handles.into_iter().enumerate() {
let r = h.join().expect("thread panicked");
let v = r.unwrap_or_else(|e| panic!("rank {i}: {e}"));
if i == 0 {
out = v;
}
}
// relu([-1,2,-3,4]) = [0,2,0,4], then ×3 on the board = [0,6,0,12].
assert_eq!(out, vec![0.0, 6.0, 0.0, 12.0]);
}
/// A fixed-function rank refuses an activation whose length its datapath was
/// not synthesized for, instead of clocking a wrong-shaped feed into fabric.
#[test]
fn fixed_function_rank_rejects_wrong_shape() {
let world: u32 = 2;
let listeners: Vec<TcpListener> = (0..world)
.map(|_| TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap())
.collect();
let addrs: Vec<SocketAddr> = listeners.iter().map(|l| l.local_addr().unwrap()).collect();
let handles: Vec<_> = listeners
.into_iter()
.enumerate()
.map(|(rank, listener)| {
let addrs = addrs.clone();
thread::spawn(move || -> Result<(), String> {
let rank = rank as u32;
let t = NetTransport::from_listener(rank, world, listener, addrs, 1 << 20)
.map_err(|e| e.to_string())?;
let group = Arc::new(ProcessGroup::new(Arc::new(t)));
if rank == 0 {
let _ = collect_caps(&group)?;
// 5 elements into a datapath synthesized for 4.
send_activation(&group, 1, &[1.0, 2.0, 3.0, 4.0, 5.0])?;
Ok(())
} else {
let ff = FixedFunction::new(STAGE, N, N, DType::F32);
let mut board = LoopbackFixedFunction::new(STAGE, board_fn);
let err =
serve_fixed_function_n(&group, &ff, &mut board, &NodeControl::steps(1))
.expect_err("wrong-length activation must be refused");
assert!(
err.contains("takes 4 elems, got 5"),
"unexpected error: {err}"
);
Ok(())
}
})
})
.collect();
for (i, h) in handles.into_iter().enumerate() {
h.join()
.expect("thread panicked")
.unwrap_or_else(|e| panic!("rank {i}: {e}"));
}
}
/// A board whose stage id disagrees with the rank's advertised descriptor is a
/// configuration error, caught before the mesh handshake.
#[test]
fn board_stage_id_must_match_descriptor() {
let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap();
let addr = listener.local_addr().unwrap();
let t = NetTransport::from_listener(0, 1, listener, vec![addr], 1 << 16).unwrap();
let group = Arc::new(ProcessGroup::new(Arc::new(t)));
let ff = FixedFunction::new(STAGE, N, N, DType::F32);
let mut board = LoopbackFixedFunction::new("a-different-bitstream", board_fn);
let err = serve_fixed_function_n(&group, &ff, &mut board, &NodeControl::steps(1)).unwrap_err();
assert!(
err.contains("a-different-bitstream") && err.contains(STAGE),
"unexpected error: {err}"
);
}
/// A fixed-function rank must be refused a **training** job, at placement.
///
/// This is the failure the capability handshake exists to prevent, and it is
/// silent: a `TrainSpec` shipped to a bitstream lands on a tag that rank never
/// reads, and the coordinator then waits forever on the first gradient
/// all-reduce, because a barrier needs every rank to arrive. No error, no
/// timeout — the run simply stops.
///
/// The test never ships anything, so a regression here fails rather than hangs.
#[test]
fn a_fixed_function_rank_is_refused_a_training_job() {
let world: u32 = 2;
let listeners: Vec<TcpListener> = (0..world)
.map(|_| TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap())
.collect();
let addrs: Vec<SocketAddr> = listeners.iter().map(|l| l.local_addr().unwrap()).collect();
let handles: Vec<_> = listeners
.into_iter()
.enumerate()
.map(|(rank, listener)| {
let addrs = addrs.clone();
thread::spawn(move || -> Result<(), String> {
let rank = rank as u32;
let t = NetTransport::from_listener(rank, world, listener, addrs, 1 << 20)
.map_err(|e| e.to_string())?;
let group = Arc::new(ProcessGroup::new(Arc::new(t)));
if rank == 0 {
let caps = collect_caps(&group)?;
let fpga = caps
.iter()
.find(|c| matches!(c.role, NodeRole::FixedFunction(_)))
.expect("the board announced itself");
let err = fpga
.can_train()
.expect_err("a bitstream has no backward pass");
assert!(
err.contains(STAGE) && err.contains("cannot"),
"refusal should name the stage and say why: {err}"
);
// A general worker is still allowed to train.
let worker = rlx_runtime::dist::node::NodeCaps {
rank: 9,
role: NodeRole::Worker,
devices: vec!["cpu".into()],
platform: "test".into(),
}
.can_train();
assert!(worker.is_ok(), "a worker must still be allowed: {worker:?}");
Ok(())
} else {
// Announce as a board, then leave — nothing is shipped.
let ff = FixedFunction::new(STAGE, N, N, DType::F32);
let caps = rlx_runtime::dist::node::NodeCaps {
rank,
role: NodeRole::FixedFunction(ff),
devices: vec!["fpga".into()],
platform: "test".into(),
};
rlx_runtime::dist::node::send_caps(&group, &caps)
}
})
})
.collect();
for (i, h) in handles.into_iter().enumerate() {
h.join()
.unwrap_or_else(|_| panic!("rank {i} panicked"))
.unwrap_or_else(|e| panic!("rank {i}: {e}"));
}
}
/// A node's platform tag must actually name the platform it was compiled for.
///
/// `platform_tag` is a hand-written `cfg!` ladder, so a target it has never
/// heard of falls through to `"unknown"` — silently, and only visible in a
/// coordinator log nobody reads until a mesh misbehaves. Apple ships five OSes
/// that RLX builds nodes for and the ladder has to name each one; this pins
/// that, plus the desktop tags, against the target the test itself is built
/// for.
#[test]
fn platform_tag_names_this_target() {
let tag = rlx_runtime::dist::node::platform_tag();
let expected = if cfg!(target_os = "ios") {
"ios"
} else if cfg!(target_os = "tvos") {
"tvos"
} else if cfg!(target_os = "watchos") {
"watchos"
} else if cfg!(target_os = "visionos") {
"visionos"
} else if cfg!(target_os = "macos") {
"macos"
} else if cfg!(target_os = "android") {
"android"
} else if cfg!(target_os = "linux") {
"linux"
} else if cfg!(target_os = "windows") {
"windows"
} else {
// Some other target: only require that it is named at all.
assert_ne!(tag, "unknown", "platform_tag has no arm for this target");
return;
};
assert_eq!(tag, expected);
}