skip to content
==> tests/snap.c <==
1/* crates/mesh-top/tests/snap.rs, ported: snapshot parsing against mesh-abi's constants (framing,
2 * sections, fields, the host block) and the trace reply. */
3#include "mesh/check.h"
4#include "mesh/top_snap.h"
5
6#include <stdlib.h>
7#include <string.h>
8
9static void parts(uint8_t *head, mt_section secs[2], uint8_t *host) {
10    memset(head, 0, MESH_H_BYTES);
11    mt_put_u32(head, MESH_H_EPOCH, 9);
12    mt_section a = mt_section_new(3, 2, 0x41); /* an odd view length: padded to 0x44 */
13    mt_put_str(mt_section_entry(&a), MESH_PT_NAME, MESH_NAME_BYTES, "life");
14    mt_put_u32(mt_section_entry(&a), MESH_PT_STATE, MESH_ST_RUNNING);
15    mt_put_u64(mt_section_entry(&a), MESH_PT_PTX_HASH, 0x123456789abcdef0u);
16    mt_put_u32(mt_section_ctl(&a), MESH_P_ONLINE, 2);
17    mt_put_u32(mt_section_ctl(&a), MESH_P_COUNTERS + 4, 77);
18    mt_put_str(mt_section_ext(&a), MESH_PX_COUNTER_NAMES + MESH_NAME_BYTES, MESH_NAME_BYTES, "births");
19    mt_put_u32(mt_section_ext(&a), MESH_PX_FIELD_COUNT, 3);
20    const char *names[3] = {"gen", "rate", "tail"};
21    uint32_t types[3] = {MESH_FT_U32, MESH_FT_F32, MESH_FT_U64};
22    uint32_t offs[3] = {0, 4, 0x3c};
23    for (size_t i = 0; i < 3; i++) {
24        size_t at = MESH_PX_FIELDS + MESH_FIELD_BYTES * i;
25        mt_put_str(mt_section_ext(&a), at + MESH_FD_NAME, MESH_FD_NAME_MAX + 1, names[i]);
26        mt_put_u32(mt_section_ext(&a), at + MESH_FD_TYPE, types[i]);
27        mt_put_u32(mt_section_ext(&a), at + MESH_FD_OFF, offs[i]);
28    }
29    mt_put_u32(mt_section_node_rec(&a, 1), MESH_N_SM, 33);
30    mt_put_u64(mt_section_node_rec(&a, 1), MESH_N_BUSY_NS, 0x100000002u);
31    mt_put_u32(mt_section_view(&a), 0, 42);
32    mt_put_f32(mt_section_view(&a), 4, 1.5f);
33    mt_section_view(&a)[0x40] = 0xab;
34    mt_section b = mt_section_new(0, 0, 0);
35    mt_put_str(mt_section_entry(&b), MESH_PT_NAME, MESH_NAME_BYTES, "idle");
36    mt_put_u32(mt_section_entry(&b), MESH_PT_STATE, MESH_ST_LOADED);
37    memset(host, 0, MESH_SNAP_HOST);
38    mt_put_str(host, MESH_S_HOSTNAME, 32, "dgx-00");
39    mt_put_f32(host, MESH_S_RATES + 4 * 3, 1234.5f);
40    mt_put_u64(host, MESH_S_LOCK_STEP, (uint64_t)1 << 40);
41    mt_put_str(host, MESH_S_LOCK_NAME, MESH_NAME_BYTES, "train");
42    host[MESH_S_LOCK_VIEW + 31] = 7;
43    secs[0] = a;
44    secs[1] = b;
45}
46
47static bool parses(const uint8_t *b, size_t len, char **err) {
48    mt_snapshot s;
49    *err = NULL;
50    bool ok = mt_snapshot_parse(b, len, &s, err);
51    if (ok) mt_snapshot_free(&s);
52    return ok;
53}
54
55int main(void) {
56    static uint8_t head[MESH_H_BYTES], host[MESH_SNAP_HOST];
57    mt_section secs[2];
58    parts(head, secs, host);
59    mt_snapshot s = mt_snapshot_assemble(head, secs, 2, host);
60    CHECK_U(s.nsections, 2);
61    CHECK_U(mt_section_slot(&s.sections[0]), 0);
62    CHECK_U(mt_section_slot(&s.sections[1]), 3);
63    CHECK_U(s.len, MESH_SN_HEAD_BYTES + MESH_H_BYTES + mesh_section_bytes(0, 0) + mesh_section_bytes(2, 0x41) + MESH_SNAP_HOST);
64    CHECK_U(mt_snapshot_head(&s, MESH_H_EPOCH), 9);
65    const mt_section *p = mt_snapshot_by_name(&s, "life");
66    CHECK(p != NULL);
67    CHECK_U(mt_section_slot(p), 3);
68    CHECK_S(mt_section_state_name(p), "running");
69    CHECK(mt_section_running(p));
70    CHECK_U(mt_section_nodes(p), 2);
71    CHECK_U(mt_section_ptx_hash(p), 0x123456789abcdef0u);
72    char cn[64];
73    CHECK_U(mt_section_counter(p, 1), 77);
74    mt_section_counter_name(p, 1, cn);
75    CHECK_S(cn, "births");
76    mt_section_counter_name(p, 0, cn);
77    CHECK_S(cn, "");
78    mt_field f[MESH_MAX_FIELDS];
79    CHECK_U(mt_section_fields(p, f), 3);
80    char v[64];
81    CHECK_S(f[0].name, "gen");
82    mt_section_field_value(p, &f[0], v, sizeof v);
83    CHECK_S(v, "42");
84    mt_section_field_value(p, &f[1], v, sizeof v);
85    CHECK_S(v, "1.500000");
86    mt_section_field_value(p, &f[2], v, sizeof v); /* a u64 at 0x3c needs 0x44 bytes; only 0x41 were copied */
87    CHECK_S(v, "-");
88    CHECK_U(mt_section_view_len(p), 0x41);
89    CHECK_U(mt_section_view(p)[0x40], 0xab);
90    CHECK_U(mt_section_view_u32(p, 0x40), 0);
91    mt_node n = mt_section_node(p, 1);
92    CHECK_U(n.sm, 33);
93    CHECK_U(n.busy_ns, 0x100000002u);
94    CHECK_U(mt_section_node(p, 5).sm, 0);
95    CHECK_U(mt_snapshot_nodes_online(&s), 2);
96    CHECK(!mt_section_running(mt_snapshot_by_slot(&s, 0)));
97    char hn[97];
98    mt_snapshot_hostname(&s, hn);
99    CHECK_S(hn, "dgx-00");
100    CHECK(mt_snapshot_rate(&s, 3) == 1234.5f);
101    char ln[64];
102    uint64_t step;
103    uint8_t view[32];
104    mt_snapshot_lock_pair(&s, ln, &step, view);
105    CHECK_S(ln, "train");
106    CHECK_U(step, (uint64_t)1 << 40);
107    CHECK_U(view[31], 7);
108
109    /* Bad framing is refused. */
110    char *err;
111    uint8_t *good = malloc(s.len);
112    memcpy(good, s.bytes, s.len);
113    size_t len = s.len;
114    CHECK(parses(good, len, &err));
115    CHECK(!parses(good, len - 4, &err));
116    free(err);
117    uint8_t zeros[64] = {0};
118    CHECK(!parses(zeros, 64, &err));
119    free(err);
120    size_t first = MESH_SN_HEAD_BYTES + MESH_H_BYTES;
121    struct {
122        size_t at;
123        uint32_t v;
124    } bad[] = {{MESH_SN_VERSION, 1}, {MESH_SN_COUNT, 1}, {MESH_SN_COUNT, 3}, {first + MESH_SC_BYTES, 0x999},
125               {first + MESH_SC_NODES, 40}, {first + MESH_SC_SLOT, 3}, {MESH_SN_HOST_AT, 0x200}};
126    for (size_t i = 0; i < sizeof bad / sizeof bad[0]; i++) {
127        uint8_t *b = malloc(len);
128        memcpy(b, good, len);
129        mt_put_u32(b, bad[i].at, bad[i].v);
130        CHECK(!parses(b, len, &err));
131        if (i == 0) CHECK(err && strstr(err, "version"));
132        free(err);
133        free(b);
134    }
135    free(good);
136    mt_snapshot empty = mt_snapshot_assemble(head, NULL, 0, host);
137    CHECK_U(empty.nsections, 0);
138    mt_snapshot_free(&empty);
139    mt_snapshot_free(&s);
140    mt_section_free(&secs[0]);
141    mt_section_free(&secs[1]);
142
143    /* The trace reply. */
144    size_t per = 8 + (size_t)MESH_TRACE_PER_PROG * MESH_TRACE_BYTES;
145    uint8_t *t = calloc(2, per);
146    uint8_t *ring = t + 8;
147    mt_put_u32(t, 0, 2);
148    mt_put_u32(t, 4, 130);
149    for (uint32_t k = 0; k < 130; k++) {
150        size_t at = MESH_TRACE_BYTES * (k % MESH_TRACE_PER_PROG);
151        mt_put_u32(ring, at, 2 | (k % 3) << 8 | MESH_OP_TASK << 16);
152        mt_put_u32(ring, at + 4, k);
153        mt_put_u32(ring, at + 8, (UINT32_MAX - 500) + 10 * k);
154        mt_put_u32(ring, at + 12, (UINT32_MAX - 500) + 10 * k + 1000 + k);
155    }
156    uint8_t *t5 = t + per;
157    mt_put_u32(t5, 0, 5);
158    mt_put_u32(t5, 4, 3);
159    mt_put_u32(t5 + 8, 0, 5 | 1 << 8 | 4 << 16);
160    mt_trace_prog *v2;
161    size_t nv;
162    CHECK(mt_parse_trace(t, 2 * per, &v2, &nv, &err));
163    CHECK_U(nv, 2);
164    CHECK(v2[0].slot == 2 && v2[0].n == 130 && v2[0].nrecs == 128);
165    CHECK(v2[0].recs[0].ticket == 2 && v2[0].recs[127].ticket == 129);
166    CHECK(v2[0].recs[0].node == 2 && v2[0].recs[0].op == MESH_OP_TASK && mt_rec_ns(&v2[0].recs[0]) == 1002);
167    CHECK_U(v2[1].nrecs, 3);
168    CHECK(v2[1].recs[0].slot == 5 && v2[1].recs[0].node == 1 && v2[1].recs[0].op == 4);
169    double p50;
170    CHECK(mt_quantile_us(v2[0].recs, v2[0].nrecs, 0.5, &p50) && p50 >= 1.06 && p50 < 1.07);
171    CHECK(!mt_quantile_us(NULL, 0, 0.5, &p50));
172    mt_trace_free(v2, nv);
173    CHECK(!mt_parse_trace(t, 2 * per - 1, &v2, &nv, &err));
174    free(err);
175    mt_put_u32(t, 0, 99);
176    CHECK(!mt_parse_trace(t, 2 * per, &v2, &nv, &err));
177    free(err);
178    free(t);
179    return mesh_check_done();
180}