==> 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}