skip to content
==> include/mesh/abi/control_block.h <==
1/* @ajax/mesh-abi-control-block: A program's control block (P_*): shutdown, run state, faults, the request window, worker words, counters.
2 *
3 * Part of alpha-c-mesh, a C port of alpha-rust-mesh (README.md says from where). */
4#ifndef MESH_ABI_CONTROL_BLOCK_H
5#define MESH_ABI_CONTROL_BLOCK_H
6
7#include <stdbool.h>
8#include <stddef.h>
9#include <stdint.h>
10#include "mesh/abi/fields.h"
11
12/* ---------------------------------------------------------------- control block + ring */
13/* Program s's control block at `prog_ctl(s)`, PROG_CTL_BYTES.  The hot words
14 * (ticket head; completions; program counters) each own a 128-byte line, so
15 * programs do not share one line (a shared line capped v1 at ~40k tasks/s).  The
16 * cold words share line 0 (the block has 16 lines and the ring, results and
17 * marks need 12). */
18#define MESH_PROG_CTL 0x2000
19#define MESH_PROG_CTL_BYTES 0x800
20#define MESH_LINE 0x80
21/* line 0: cold */
22/* u32 host: nonzero -> every node exits at its next task boundary.
23 * SHUTDOWN_HALT for a halt the slot comes back from (a blink, a rebind),
24 * SHUTDOWN_EXIT for a stop, a failure or meshd's exit (a native worker's
25 * process then exits too; a GPU kernel treats both alike). */
26#define MESH_P_SHUTDOWN 0x00
27#define MESH_SHUTDOWN_HALT 1u
28#define MESH_SHUTDOWN_EXIT 2u
29#define MESH_P_ONLINE 0x04 /* u32 GPU atom: nodes online (host zeroes before a launch) */
30#define MESH_P_HALTED 0x08 /* u32 GPU atom: nodes halted */
31/* u32 host only: the run state meshd wants (1 run / 0 stop).  Plain host
32 * stores; the GPU only reads it. */
33#define MESH_P_RUN 0x0c
34/* u32 GPU only: a GPU program's run request (READS_ALL, i.e. http's
35 * /start, /stop): `n << 1 | on`, n counting requests, advanced with a GPU
36 * atom.cas (`run_req_next`); meshd only reads it and honours a changed n on
37 * its next tick (then stores P_RUN).  meshd never writes this word, not even
38 * at load: it notes its value instead.  So every word is read-modify-written
39 * by one side only -- required where host and GPU RMWs on the same word are
40 * not mutually atomic (CU_DEVICE_ATTRIBUTE_HOST_NATIVE_ATOMIC_SUPPORTED = 0,
41 * e.g. an RTX 3060 over PCIe).  Mailbox rule: the host RMWs only host-only
42 * words (H_PROG_SEQ, P_LAUNCHES); it stores to GPU-atomic words (P_ONLINE,
43 * P_HALTED, P_RING_HEAD, P_FAULT, the view) only while that program's kernel
44 * is halted. */
45#define MESH_P_RUN_REQ 0x10
46/* u32 GPU: the first fault the runtime caught (FAULT_*), 0 none; meshd marks the program FAILED. */
47#define MESH_P_FAULT 0x14
48#define MESH_P_RING_TAIL 0x18 /* u64 host: tickets published (informational) */
49/* The request window handshake (on_demand byte requests): host writes the
50 * request bytes at view PT_REQ_OFF, P_REQ_LEN, then P_REQ_SEQ += 1 (release)
51 * and publishes OP_REQ; the program writes the response at PT_RESP_OFF,
52 * P_RESP_LEN, then P_RESP_SEQ = P_REQ_SEQ (release) (`Ctx::respond`). */
53#define MESH_P_REQ_SEQ 0x20 /* u64 */
54#define MESH_P_RESP_SEQ 0x28 /* u64 */
55#define MESH_P_REQ_LEN 0x30 /* u32 */
56#define MESH_P_RESP_LEN 0x34 /* u32 */
57#define MESH_P_LAUNCHES 0x38 /* u32 host: launches of this slot (informational) */
58/* A native worker's words (PX_EXEC = BACKEND_NATIVE): host-only, 0 for any */
59/* other program; meshd refreshes them every tick.  Its CPU time and RSS are */
60/* load figures: pload(s) PL_HOST (PL_CPU_NS ..), like a wasm slot's. */
61#define MESH_P_PID 0x40 /* u32 the running image's worker process (0: none) */
62#define MESH_P_SPAWNS 0x44 /* u32 processes started for the current image */
63#define MESH_P_CRASHES 0x48 /* u32 of those, the ones that died while running (FAILED) */
64#define MESH_P_EXIT 0x4c /* u32 the last exit: status << 8 | signal (0: none yet) */
65#define MESH_P_LIMITS 0x50 /* u32 LIMIT_* bits actually applied to the process */
66#define MESH_LIMIT_CPU 1u /* Linux: systemd scope CPUQuota (checked in its cgroup) */
67#define MESH_LIMIT_MEM 2u /* Linux: MemoryMax + MemorySwapMax = 0 (checked in its cgroup) */
68#define MESH_LIMIT_NICE 4u
69#define MESH_LIMIT_BG 8u /* macOS: PRIO_DARWIN_BG (taskpolicy -b); Linux: SCHED_IDLE */
70/* line 1 */
71#define MESH_P_RING_HEAD 0x80 /* u32 GPU atom.add -> ticket */
72/* line 2 */
73#define MESH_P_DONE 0x100 /* u32 GPU red.add per completion */
74#define MESH_P_TRACE_N 0x104 /* u32 GPU atom.add per completion: trace records written */
75/* line 3 */
76#define MESH_P_COUNTERS 0x180 /* u32 x COUNTERS, program-defined (Ctx::count) */
77#define MESH_COUNTERS 4
78/* The control block's cold line (P_*, line 0: host and GPU words). */
79#define MESH_CTL_FIELDS_LEN 17
80extern const mesh_field MESH_CTL_FIELDS[17];
81
82/* Slot s's control block. */
83static inline size_t mesh_prog_ctl(uint32_t slot) { return MESH_PROG_CTL + MESH_PROG_CTL_BYTES * (size_t)slot; }
84/* The next P_RUN_REQ value after `cur` for a request to run (`on`) or stop. */
85static inline uint32_t mesh_run_req_next(uint32_t cur, bool on) { return ((cur & ~1u) + 2u) | (uint32_t)on; }
86
87/* The Rust const asserts that only involve this package. */
88_Static_assert(MESH_P_LAUNCHES + 4 <= MESH_LINE, "P_LAUNCHES + 4 <= LINE");
89_Static_assert((MESH_P_RING_TAIL % 8 == 0), "P_RING_TAIL.is_multiple_of(8)");
90_Static_assert((MESH_P_REQ_SEQ % 8 == 0), "P_REQ_SEQ.is_multiple_of(8)");
91_Static_assert(MESH_P_RING_HEAD == MESH_LINE, "P_RING_HEAD == LINE");
92_Static_assert(MESH_P_DONE == 2 * MESH_LINE, "P_DONE == 2 * LINE");
93_Static_assert(MESH_P_COUNTERS == 3 * MESH_LINE, "P_COUNTERS == 3 * LINE");
94
95#endif