1/* @ajax/mesh-lease: the lease (mesh-host lease.rs): mesh-rt's node loop played by a host thread
2 * against the mailbox, for executors without resident kernels -- wasm (CPU programs) and, in the
3 * Rust, Metal. One maintained owner of the node-loop protocol; the executor supplies only a runner
4 * that runs the taken tickets (wasm: calls into an instance).
5 *
6 * A lease lane owns `count` node records from `first` (wasm: one lane per node):
7 * - start: writes its node records (N_SM = the node number), P_ONLINE += count;
8 * - each turn it takes published tickets in order -- E_SEQ == t + 1, at most the runner's
9 * max_take, none while H_BLINK is set if the lane is gated by it (a wasm lane is never relaunched
10 * by a GPU blink and ignores it) -- each by a CAS on P_RING_HEAD, so several lanes of one slot
11 * share its ring without a lock and no lane ever holds an unpublished ticket;
12 * - the runner runs them and completes each exactly as mesh-rt's nodes do (mesh_lease_complete):
13 * P_RESULTS, P_MARKS = t + 1 (release), P_DONE += 1, the node record (tasks, last op, busy ns,
14 * heartbeat), a trace record;
15 * - a fault (mesh_lease_fault, the first kept) leaves the tickets incomplete: the driver fails the
16 * slot and shuts it down;
17 * - P_SHUTDOWN with nothing published: P_HALTED += count and the lane ends.
18 *
19 * mesh_round is the lockstep round (train), with the bounded wait in the host lane: publish
20 * ex_counter(k) = n, wait PEER_POLLS x PEER_POLL_NS for every member's counter >= n.
21 *
22 * A gated (GPU) lease counts each run in the slot's pipe flight word (pipe flight_begin/end); a
23 * wasm lane's pushes count themselves (host calls). */
24#ifndef MESH_LEASE_H
25#define MESH_LEASE_H
2627#include "mesh/abi/control_block.h"
28#include "mesh/mailbox.h"
2930#include <stdatomic.h>
31#include <stdbool.h>
32#include <stddef.h>
33#include <stdint.h>
3435/* A lockstep round's outcome. */
36#define MESH_ROUND_OK 1u
37#define MESH_ROUND_TIMEOUT 2u
3839/* Idle lanes heartbeat their node records this often (mesh-rt: HEARTBEAT_NS). */
40#define MESH_LEASE_HEARTBEAT_NS 2000000ull
4142/* Host clock in ns (CLOCK_MONOTONIC): the trace's and the node records' timebase on a lease. */
43uint64_t mesh_host_ns(void);
4445/* A taken ticket: (ticket, op, arg, completion slot). */
46typedef struct {
47 uint32_t t, op, arg, cslot;
48} mesh_taken;
4950/* Counters for tools: batches run, tasks, passes, lockstep rounds and the wait in them. */
51typedef struct {
52 _Atomic uint64_t buffers, tasks, passes, rounds, round_wait_ns;
53} mesh_lane_stats;
5455typedef struct mesh_lease mesh_lease;
5657/* What an executor does with taken tickets. */
58typedef struct {
59 /* At most this many tickets per turn. */
60 size_t (*max_take)(void *self);
61 /* Runs taken[0..n) and completes each (mesh_lease_complete); false: a fault was recorded
62 * (mesh_lease_fault) and the rest stay incomplete. */
63 bool (*run)(void *self, mesh_lease *lease, const mesh_taken *taken, size_t n);
64 /* Idle, at each heartbeat (wasm: its CPU time and memory into cpuuse). NULL: nothing. */
65 void (*heartbeat)(void *self);
66} mesh_runner;
6768/* One lane of a running slot. */
69struct mesh_lease {
70 mesh_mailbox mb;
71 uint32_t slot;
72 uint32_t first, count; /* the node records this lane owns: first .. first + count */
73 bool blink_gate; /* no ticket is taken while H_BLINK is set (GPU leases) */
74 _Atomic bool *done; /* set when the lane ends (the caller's, outlives the lane) */
75 mesh_lane_stats *stats; /* the caller's */
76 uint64_t beat_at;
77};
7879/* done and stats are the caller's and must outlive the lane (the Rust's Arcs). */
80void mesh_lease_init(mesh_lease *l, mesh_mailbox mb, uint32_t slot, uint32_t first, uint32_t count, bool blink_gate,
81 _Atomic bool *done, mesh_lane_stats *stats);
82static inline size_t mesh_lease_ctl(const mesh_lease *l, size_t off) { return mesh_prog_ctl(l->slot) + off; }
8384/* The node loop. Runs on its own thread until P_SHUTDOWN with nothing published. */
85void mesh_lease_run(mesh_lease *l, const mesh_runner *runner, void *self);
8687/* mesh-rt's completion of ticket k on node: result, mark (release), P_DONE, the node record, the
88 * trace (start/end: host or GPU ns). */
89void mesh_lease_complete(mesh_lease *l, uint32_t node, const mesh_taken *k, uint32_t result, uint64_t start, uint64_t end);
90/* Records the slot's first fault (P_FAULT keeps only the first). */
91void mesh_lease_fault(const mesh_lease *l, uint32_t code);
92/* The lockstep round n (mesh_round), counted in the lane's stats. */
93uint32_t mesh_lease_exchange(mesh_lease *l, uint64_t n);
9495/* Round n for group rank k of N (H_GROUP_RANK, H_GROUP_N): publish ex_counter(k) = n (unless
96 * already), wait bounded for every other member's counter >= n. MESH_ROUND_OK or
97 * MESH_ROUND_TIMEOUT, and the time waited in *waited_ns (may be NULL). Not in a group:
98 * MESH_ROUND_TIMEOUT at once. */
99uint32_t mesh_round(mesh_mailbox mb, uint64_t n, uint64_t *waited_ns);
100101#endif