==> src/tick.c <==1/* tick: the scheduler's test program (program.toml has the layout). A
2 * migration must carry its view: the ticks go on from where they were, the
3 * inits stay 1 (no OP_INIT on the target), and `task tick 3 0` finds every
4 * sampled pattern word in place.
5 * Ported from alpha-rust-mesh programs/tick/src/lib.rs. */
6#include "mesh/rt.h"
7
8#define TICK_MAGIC 0x4b434954u /* "TICK" */
9#define TICK_TICKS 0x4u
10#define TICK_INITS 0x8u
11#define TICK_MISMATCH 0xcu
12#define TICK_REGION 0x40u
13#define TICK_OP_VERIFY 3u
14#define TICK_SAMPLES 4096u
15#define TICK_RECENT 64u
16
17static uint32_t tick_pattern(uint32_t i) { return (i * 2654435761u) ^ 0x5a5a5a5au; }
18
19/* Word i of the region after `ticks` ticks (w words). */
20static uint32_t tick_expect(uint32_t i, uint32_t ticks, uint32_t w) {
21 if (ticks <= i) return tick_pattern(i);
22 /* The last tick t < ticks with t mod w == i. */
23 uint32_t t = i + (ticks - 1 - i) / w * w;
24 return tick_pattern(i) ^ (t + 1);
25}
26
27static uint32_t tick_words(const mesh_ctx *ctx) { return (mesh_ctx_view_len(ctx) - TICK_REGION) / 4; }
28
29static void tick_init(const mesh_ctx *ctx) {
30 uint32_t w = tick_words(ctx);
31 for (uint32_t i = mesh_ctx_lane(ctx); i < w; i += 32) mesh_ctx_set_u32(ctx, TICK_REGION + 4 * i, tick_pattern(i));
32 if (mesh_ctx_leader(ctx)) {
33 mesh_ctx_set_u32(ctx, 0x0, TICK_MAGIC);
34 mesh_ctx_set_u32(ctx, TICK_TICKS, 0);
35 mesh_ctx_set_u32(ctx, TICK_INITS, mesh_ctx_view_u32(ctx, TICK_INITS) + 1);
36 mesh_ctx_count(ctx, 1, 1);
37 }
38}
39
40static uint32_t tick_task(const mesh_ctx *ctx, uint32_t op, uint32_t arg) {
41 (void)arg;
42 uint32_t w = tick_words(ctx);
43 if (op == MESH_OP_TASK) {
44 if (mesh_ctx_leader(ctx)) {
45 uint32_t t = mesh_ctx_view_u32(ctx, TICK_TICKS);
46 uint32_t i = t % w;
47 mesh_ctx_set_u32(ctx, TICK_REGION + 4 * i, tick_pattern(i) ^ (t + 1));
48 mesh_ctx_set_u32(ctx, TICK_TICKS, t + 1);
49 mesh_ctx_count(ctx, 0, 1);
50 }
51 return 0;
52 }
53 if (op == TICK_OP_VERIFY) {
54 uint32_t bad = 0;
55 if (mesh_ctx_leader(ctx)) {
56 uint32_t t = mesh_ctx_view_u32(ctx, TICK_TICKS);
57 for (uint32_t s = 0; s < TICK_SAMPLES; s++) {
58 uint32_t i = (uint32_t)((uint64_t)s * w / TICK_SAMPLES);
59 if (mesh_ctx_view_u32(ctx, TICK_REGION + 4 * i) != tick_expect(i, t, w)) bad++;
60 }
61 uint32_t recent = TICK_RECENT < t ? TICK_RECENT : t;
62 for (uint32_t k = 1; k <= recent; k++) {
63 uint32_t i = (t - k) % w;
64 if (mesh_ctx_view_u32(ctx, TICK_REGION + 4 * i) != tick_expect(i, t, w)) bad++;
65 }
66 mesh_ctx_set_u32(ctx, TICK_MISMATCH, bad);
67 }
68 return bad;
69 }
70 return MESH_R_BAD_OP;
71}
72
73MESH_PROGRAM(tick_init, tick_task);