skip to content
==> src/train.c <==
1/* ui.rs's "4 train" section, ported. */
2#include "mesh/top_ui_train.h"
3
4#include "tui/chart.h"
5
6#include <math.h>
7#include <string.h>
8
9tui_line mt_identity_line(mt_frame *f, const mt_app *app) {
10    const char *lock = "lockstep";
11    for (size_t i = 0; i < app->nmachines; i++) {
12        const mt_machine *m = &app->machines[i];
13        if (!m->has_snap) continue;
14        char name[3 * MESH_NAME_BYTES + 1];
15        uint64_t step;
16        uint8_t view[32];
17        mt_snapshot_lock_pair(&m->snap, name, &step, view);
18        if (*name) {
19            lock = tui_arena_strdup(f->a, name);
20            break;
21        }
22    }
23    mt_identity id;
24    if (!mt_params_identity(app, &id))
25        return MT_LINE(f, mt_label(MT_FMT(f, " %s params bitwise identical: ", lock)), mt_fgs("waiting for a step every machine reports", MT_WARN));
26    tui_line v = MT_LINE(f, mt_label(MT_FMT(f, " %s params bitwise identical across %zu: ", lock, id.n)),
27                         id.identical ? mt_styled("YES", mt_fg_bg_bold(MT_BG, MT_GOOD)) : mt_styled("NO", mt_fg_bg_bold(TUI_WHITE, MT_BAD)),
28                         mt_label(MT_FMT(f, " (at step %llu)", (unsigned long long)id.step)));
29    if (!id.identical) {
30        const char *j = "";
31        for (size_t i = 0; i < id.ndiffer; i++) j = MT_FMT(f, "%s%s%s", j, i ? ", " : "", id.differ[i]);
32        tui_line_push(f->a, &v, mt_fgb(MT_FMT(f, "  differ: %s", j), MT_BAD));
33    }
34    return v;
35}
36
37static void draw_train_machine(mt_frame *f, tui_rect area, const mt_machine *m, size_t i, bool focused) {
38    tui_color color;
39    tui_line title = mt_machine_title(f, m, focused, "train", &color);
40    tui_block block = mt_panel(f, title, color);
41    tui_rect inner = tui_block_inner(&block, area);
42    mt_block(f, &block, area);
43    const mt_section *t = mt_bound(f, inner, m, "train");
44    if (!t) return;
45    const mt_snapshot *s = &m->snap;
46    tui_rect hs[2];
47    tui_hsplit(inner, 2, (tui_constraint[]){TUI_FILL(1), TUI_LENGTH(30)}, hs);
48
49    tui_point *pts = tui_arena_alloc(f->a, (m->nlosses ? m->nlosses : 1) * sizeof *pts);
50    size_t np = 0;
51    for (size_t k = 0; k < m->nlosses; k++) {
52        float l = m->losses[k].loss;
53        if (isfinite(l) && l > 0.0f) pts[np++] = (tui_point){(double)m->losses[k].step, log10((double)l)};
54    }
55    double x0 = 0.0, x1 = 1.0;
56    if (np) {
57        x0 = pts[0].x;
58        x1 = fmax(pts[np - 1].x, pts[0].x + 1.0);
59    }
60    double lo = INFINITY, hi = -INFINITY;
61    for (size_t k = 0; k < np; k++) {
62        lo = fmin(lo, pts[k].y);
63        hi = fmax(hi, pts[k].y);
64    }
65    if (isfinite(lo)) {
66        double fl = floor(lo);
67        hi = fmax(ceil(hi), fl + 1.0);
68        lo = fl;
69    } else {
70        lo = -3.0;
71        hi = 0.0;
72    }
73    double ev[3] = {lo, (lo + hi) / 2.0, hi};
74    tui_line *ylabels = tui_arena_alloc(f->a, 3 * sizeof *ylabels);
75    for (int k = 0; k < 3; k++) ylabels[k] = tui_line_from_str(f->a, mt_fe(f, pow(10.0, ev[k]), 0));
76    tui_line *xlabels = tui_arena_alloc(f->a, 2 * sizeof *xlabels);
77    xlabels[0] = tui_line_from_str(f->a, mt_ff(f, x0, 0));
78    xlabels[1] = tui_line_from_str(f->a, MT_FMT(f, "step %s", mt_ff(f, x1, 0)));
79    tui_dataset ds = tui_dataset_new();
80    ds.has_name = true;
81    ds.name = tui_line_from_str(f->a, MT_FMT(f, "loss, log scale, %zu pts", np));
82    ds.marker = TUI_MARKER_BRAILLE;
83    ds.graph_type = TUI_GRAPH_LINE;
84    ds.style = tui_fg(MT_MACHINE[i % 8]);
85    ds.data = pts;
86    ds.n = np;
87    tui_chart chart = tui_chart_new(&ds, 1);
88    chart.x_axis = tui_axis_new();
89    chart.x_axis.style = tui_fg(MT_DIM);
90    chart.x_axis.bounds[0] = x0;
91    chart.x_axis.bounds[1] = x1;
92    chart.x_axis.labels = xlabels;
93    chart.x_axis.nlabels = 2;
94    chart.y_axis = tui_axis_new();
95    chart.y_axis.style = tui_fg(MT_DIM);
96    chart.y_axis.bounds[0] = lo;
97    chart.y_axis.bounds[1] = hi;
98    chart.y_axis.labels = ylabels;
99    chart.y_axis.nlabels = 3;
100    chart.style = tui_style_bg(tui_style_new(), MT_BG);
101    tui_chart_render(f->a, &chart, hs[0], f->buf);
102
103    uint32_t err = mt_section_view_u32(t, MESH_TRAIN_T_ERR);
104    float rtt = mt_snapshot_host_f32(s, MESH_S_PEER_RTT_US);
105    mt_loss ls[256];
106    size_t nl = mt_train_losses(t, ls);
107    float last = nl ? ls[nl - 1].loss : NAN;
108    mt_lines lines = {0};
109    mt_lines_push(f, &lines, MT_LINE(f, mt_label("train "), mt_styled(mt_section_state_name(t), mt_state_style(t))));
110    mt_lines_push(f, &lines, MT_LINE(f, mt_label("step    "), mt_val(MT_FMT(f, "%llu", (unsigned long long)mt_train_next_step(t)))));
111    mt_lines_push(f, &lines, MT_LINE(f, mt_label("steps/s "), mt_fgb(mt_ff(f, mt_rate_per_s(&m->train_steps), 0), MT_WARN)));
112    mt_lines_push(f, &lines, MT_LINE(f, mt_label("loss    "), mt_val(mt_fe(f, last, 3))));
113    static const char *const pn[4] = {"a", "b", "c", "d"};
114    for (size_t k = 0; k < 4; k++)
115        mt_lines_push(f, &lines, MT_LINE(f, mt_label(MT_FMT(f, "%s  ", pn[k])), mt_val(mt_ffp(f, mt_section_view_f32(t, MESH_TRAIN_T_PARAMS + 4 * k), 6))));
116    mt_lines_push(f, &lines, MT_LINE(f, mt_label("peer "), mt_peer_span(f, s)));
117    mt_lines_push(f, &lines, MT_LINE(f, mt_label("RTT  "), mt_val(rtt > 0.0f ? MT_FMT(f, "%sus", mt_ff(f, rtt, 1)) : "-"),
118                                     mt_label(MT_FMT(f, "  round %u", mt_section_view_u32(t, MESH_TRAIN_T_ROUND)))));
119    uint32_t wk;
120    float wus;
121    if (mt_slowest_wait(s, &wk, &wus))
122        mt_lines_push(f, &lines, MT_LINE(f, mt_label("wait "), mt_val(mt_fmt_us(f, wus)), mt_label(" /round for "),
123                                         mt_fgb(MT_FMT(f, "sys %u", wk), mt_sys_color(wk))));
124    if (err != 0)
125        mt_lines_push(f, &lines, tui_line_span(f->a, mt_styled(" T_ERR: peer timed out ", mt_fg_bg_bold(TUI_WHITE, MT_BAD))));
126    else
127        mt_lines_push(f, &lines, MT_LINE(f, mt_label("T_ERR   "), mt_fgs("0", MT_GOOD)));
128    tui_block b = tui_block_new();
129    b.borders = TUI_BORDER_LEFT;
130    b.border_style = tui_fg(MT_FAINT);
131    tui_paragraph p = tui_paragraph_new(mt_text(f, &lines));
132    p.block = &b;
133    tui_paragraph_render(f->a, &p, hs[1], f->buf);
134}
135
136void mt_draw_train(mt_frame *f, tui_rect area, const mt_app *app) {
137    size_t n = app->nmachines;
138    size_t nc = n + (n >= 2);
139    tui_constraint *cons = tui_arena_alloc(f->a, nc * sizeof *cons);
140    for (size_t i = 0; i < n; i++) cons[i] = TUI_FILL(1);
141    if (n >= 2) cons[n] = TUI_LENGTH(1);
142    tui_rect *rows = tui_arena_alloc(f->a, nc * sizeof *rows);
143    tui_vsplit(area, nc, cons, rows);
144    for (size_t i = 0; i < n; i++) draw_train_machine(f, rows[i], &app->machines[i], i, i == app->focus);
145    if (n >= 2) mt_par_line(f, mt_identity_line(f, app), rows[n]);
146}