skip to content
==> src/load.c <==
1/* ui.rs's "8 load" section, ported. */
2#include "mesh/top_ui_load.h"
3
4#include "tui/sparkline.h"
5
6#include <string.h>
7
8static mt_opt_f32 some(float v) { return (mt_opt_f32){true, v}; }
9static const mt_opt_f32 NONE = {false, 0.0f};
10
11mt_load_row mt_load_row_from_load(const mt_load *l) {
12    mt_load_row r = {0};
13    r.share = l->share10;
14    r.cpu = l->cpu;
15    r.big = l->cpu_big;
16    r.little = l->cpus_little > 0 ? some(l->cpu_little) : NONE;
17    r.has_psi = l->has_psi;
18    if (l->has_psi) {
19        r.psi[0] = l->psi[0];
20        r.psi[1] = l->psi[1];
21    }
22    r.mem_free = some(l->mem_free);
23    r.meshd = l->meshd_cpu;
24    return r;
25}
26
27mt_load_row mt_load_row_from_member(const mt_member_load *l) {
28    mt_load_row r = {0};
29    r.share = l->share10;
30    r.cpu = l->cpu;
31    r.big = l->cpu_big;
32    r.little = l->cpus_little > 0 ? some(l->cpu_little) : NONE;
33    r.has_psi = l->psi_cpu.some && l->psi_mem.some;
34    if (r.has_psi) {
35        r.psi[0] = l->psi_cpu.v;
36        r.psi[1] = l->psi_mem.v;
37    }
38    r.mem_free = l->mem_total_mb > 0 ? some((float)l->mem_avail_mb / (float)l->mem_total_mb) : NONE;
39    r.meshd = l->meshd_cpu;
40    return r;
41}
42
43size_t mt_load_cols_header(mt_load_cols lt, const char **out) {
44    switch (lt) {
45    case MT_LOAD_COLS_NONE: return 0;
46    case MT_LOAD_COLS_ONE: out[0] = "GPU CPU"; return 1;
47    case MT_LOAD_COLS_PAIR: out[0] = "GPU CPU"; out[1] = "meshd"; return 2;
48    default:
49        out[0] = "GPU got";
50        out[1] = "CPU B/L";
51        out[2] = "PSI c/m";
52        out[3] = "meshd";
53        return 4;
54    }
55}
56
57size_t mt_load_cols_widths(mt_load_cols lt, tui_constraint *out) {
58    switch (lt) {
59    case MT_LOAD_COLS_NONE: return 0;
60    case MT_LOAD_COLS_ONE: out[0] = TUI_LENGTH(8); return 1;
61    case MT_LOAD_COLS_PAIR: out[0] = TUI_LENGTH(8); out[1] = TUI_LENGTH(5); return 2;
62    default:
63        out[0] = TUI_LENGTH(7);
64        out[1] = TUI_LENGTH(11);
65        out[2] = TUI_LENGTH(9);
66        out[3] = TUI_LENGTH(5);
67        return 4;
68    }
69}
70
71/* pct(x) without its trailing '%' (trim_end_matches). */
72static const char *pct_bare(mt_frame *f, float x) {
73    char *s = tui_arena_strdup(f->a, mt_pct(f, x));
74    size_t n = strlen(s);
75    while (n && s[n - 1] == '%') s[--n] = 0;
76    return s;
77}
78
79size_t mt_load_cells(mt_frame *f, const mt_load_row *r, mt_load_cols lt, tui_table_cell *out) {
80    if (!r) {
81        const char *h[4];
82        size_t n = mt_load_cols_header(lt, h);
83        for (size_t i = 0; i < n; i++) out[i] = mt_cell_span(f, mt_fgs("-", MT_FAINT));
84        return n;
85    }
86    tui_line pair = MT_LINE(f, mt_share_span(f, r->share), tui_span_raw(" "), mt_styled(mt_pct(f, r->cpu), mt_busy_style(r->cpu)));
87    tui_table_cell meshd = mt_cell_span(f, mt_styled(mt_pct(f, r->meshd), mt_busy_style(r->meshd)));
88    switch (lt) {
89    case MT_LOAD_COLS_NONE: return 0;
90    case MT_LOAD_COLS_ONE: out[0] = mt_cell_line(f, pair); return 1;
91    case MT_LOAD_COLS_PAIR:
92        out[0] = mt_cell_line(f, pair);
93        out[1] = meshd;
94        return 2;
95    default: break;
96    }
97    tui_line cpu;
98    if (r->little.some)
99        cpu = MT_LINE(f, mt_styled(mt_pct(f, r->cpu), mt_busy_style(r->cpu)),
100                      mt_fgs(MT_FMT(f, " %s/%s", pct_bare(f, r->big), pct_bare(f, r->little.v)), MT_DIM));
101    else
102        cpu = tui_line_span(f->a, mt_styled(mt_pct(f, r->cpu), mt_busy_style(r->cpu)));
103    tui_line psi;
104    if (r->has_psi) {
105        float c = r->psi[0], m = r->psi[1];
106        psi = MT_LINE(f, mt_styled(mt_ff(f, c * 100.0f, 1), mt_busy_style(c * 10.0f)), mt_fgs("/", MT_DIM),
107                      mt_styled(MT_FMT(f, "%s%%", mt_ff(f, m * 100.0f, 1)), mt_busy_style(m * 10.0f)));
108    } else if (r->mem_free.some) {
109        psi = tui_line_span(f->a, mt_styled(MT_FMT(f, "mem %s", mt_pct(f, r->mem_free.v)), mt_busy_style(1.0f - r->mem_free.v)));
110    } else {
111        psi = tui_line_span(f->a, mt_fgs("-", MT_FAINT));
112    }
113    out[0] = mt_cell_span(f, mt_share_span(f, r->share));
114    out[1] = mt_cell_line(f, cpu);
115    out[2] = mt_cell_line(f, psi);
116    out[3] = mt_cell_span(f, mt_styled(mt_pct(f, r->meshd), mt_busy_style(r->meshd)));
117    return 4;
118}
119
120const char *mt_gb_pair(mt_frame *f, uint32_t a_mb, uint32_t b_mb) {
121    return MT_FMT(f, "%s/%sG", mt_ff(f, (float)a_mb / 1024.0f, 0), mt_ff(f, (float)b_mb / 1024.0f, 0));
122}
123
124static void cpu_spans(mt_frame *f, const mt_load *l, tui_line *out) {
125    tui_line_push(f->a, out, mt_styled(mt_pct(f, l->cpu), mt_busy_style(l->cpu)));
126    if (l->cpus_little > 0) {
127        tui_line_push(f->a, out, mt_label(" big "));
128        tui_line_push(f->a, out, mt_styled(mt_pct(f, l->cpu_big), mt_busy_style(l->cpu_big)));
129        tui_line_push(f->a, out, mt_label(" little "));
130        tui_line_push(f->a, out, mt_styled(mt_pct(f, l->cpu_little), mt_busy_style(l->cpu_little)));
131    }
132}
133
134static void pressure_spans(mt_frame *f, const mt_load *l, tui_line *out) {
135    if (l->has_psi) {
136        const float *p = l->psi;
137        tui_line_push(f->a, out, mt_label(" PSI cpu "));
138        tui_line_push(f->a, out, mt_styled(MT_FMT(f, "%s%%", mt_ff(f, p[0] * 100.0f, 1)), mt_busy_style(p[0] * 10.0f)));
139        tui_line_push(f->a, out, mt_label(" mem "));
140        tui_line_push(f->a, out, mt_styled(MT_FMT(f, "%s%%", mt_ff(f, p[1] * 100.0f, 1)), mt_busy_style(p[1] * 10.0f)));
141        tui_line_push(f->a, out, mt_label(" io "));
142        tui_line_push(f->a, out, mt_styled(MT_FMT(f, "%s%%", mt_ff(f, p[3] * 100.0f, 1)), mt_busy_style(p[3] * 10.0f)));
143    } else if (l->has_mem_level) {
144        uint32_t lv = l->mem_level;
145        const char *t = lv == 1 ? "normal" : lv == 2 ? "warn" : lv == 4 ? "critical" : MT_FMT(f, "?%u", lv);
146        tui_line_push(f->a, out, mt_label(" mem pressure "));
147        tui_line_push(f->a, out, mt_fgs(t, lv == 1 ? MT_GOOD : lv == 2 ? MT_WARN : MT_BAD));
148    }
149}
150
151void mt_load_lines(mt_frame *f, const mt_load *l, bool compact, mt_lines *out) {
152    if (compact) {
153        tui_line s = MT_LINE(f, mt_label("GPU "), mt_share_span(f, l->share), mt_label(" CPU "));
154        cpu_spans(f, l, &s);
155        pressure_spans(f, l, &s);
156        tui_line_push(f->a, &s, mt_label(" meshd "));
157        tui_line_push(f->a, &s, mt_styled(mt_pct(f, l->meshd_cpu), mt_busy_style(l->meshd_cpu)));
158        mt_lines_push(f, out, s);
159        return;
160    }
161    tui_line g = MT_LINE(f, mt_label("GPU got "), mt_share_span(f, l->share), mt_label(" (10 s "), mt_share_span(f, l->share10),
162                         mt_label(")"));
163    if (!l->share.some) {
164        tui_line_push(f->a, &g, mt_fgs("nothing observed (no idle node, no lease)", MT_DIM));
165    } else {
166        tui_line_push(f->a, &g, mt_label(" slice "));
167        tui_line_push(f->a, &g, mt_val(mt_fmt_us(f, l->slice_us)));
168        tui_line_push(f->a, &g, mt_label(" gap "));
169        tui_line_push(f->a, &g, mt_val(mt_fmt_us(f, l->gap_us)));
170        tui_line_push(f->a, &g, mt_label(" max "));
171        tui_line_push(f->a, &g, mt_fgs(mt_fmt_us(f, l->max_gap_us), l->max_gap_us > 10000.0f ? MT_BAD : MT_FG));
172        tui_line_push(f->a, &g, mt_label(" ×"));
173        tui_line_push(f->a, &g, mt_val(l->inflate.some ? mt_ff(f, l->inflate.v, 2) : "-"));
174    }
175    if (l->util_ext.some) {
176        tui_line_push(f->a, &g, mt_label(" busy "));
177        tui_line_push(f->a, &g, mt_fgs(mt_pct(f, l->util_ext.v), MT_DIM));
178    }
179    tui_line c = tui_line_span(f->a, mt_label("CPU "));
180    cpu_spans(f, l, &c);
181    tui_line_push(f->a, &c, mt_label(" load "));
182    tui_line_push(f->a, &c, mt_val(mt_ff(f, l->loadavg[0], 2)));
183    pressure_spans(f, l, &c);
184    tui_line m = MT_LINE(f, mt_label("mem "), mt_styled(mt_gb_pair(f, l->mem_avail_mb, l->mem_total_mb), mt_busy_style(1.0f - l->mem_free)),
185                         mt_label(" avail"), mt_label("  meshd "), mt_styled(mt_pct(f, l->meshd_cpu), mt_busy_style(l->meshd_cpu)),
186                         mt_fgs(MT_FMT(f, " %sM", mt_ff(f, l->meshd_rss_mb, 0)), MT_DIM), mt_label("  disk "),
187                         mt_val(MT_FMT(f, "%sG", mt_ff(f, (float)l->disk_free_mb / 1024.0f, 0))), mt_label(" free"));
188    if (l->has_thermal) {
189        uint32_t t = l->thermal;
190        tui_line_push(f->a, &m, mt_label("  thermal "));
191        tui_line_push(f->a, &m, mt_fgs(t < MESH_THERMAL_STATES_LEN ? MESH_THERMAL_STATES[t] : "?", t == 0 ? MT_GOOD : t == 1 ? MT_WARN : MT_BAD));
192    } else if (l->temp_c.some) {
193        float t = l->temp_c.v;
194        tui_line_push(f->a, &m, mt_label("  "));
195        tui_line_push(f->a, &m, mt_fgs(MT_FMT(f, "%s°C", mt_ff(f, t, 0)), t >= 85.0f ? MT_BAD : MT_DIM));
196    }
197    mt_lines_push(f, out, g);
198    mt_lines_push(f, out, c);
199    mt_lines_push(f, out, m);
200}
201
202void mt_draw_load_box(mt_frame *f, tui_rect area, const mt_snapshot *s, const mt_lines *lines) {
203    if (area.height == 0 || area.width == 0) return;
204    mt_load l;
205    const char *age = "no sample ";
206    if (mt_snapshot_load(s, &l)) age = l.age_ms > 3000 ? MT_FMT(f, "stale %ss ", mt_ff(f, (float)l.age_ms / 1000.0f, 0)) : "";
207    tui_line title = MT_LINE(f, mt_fgb(" Load ", MT_FG), mt_fgs(age, MT_WARN));
208    tui_block b = tui_block_bordered();
209    b.set = &TUI_BORDER_ROUNDED;
210    b.border_style = tui_fg(MT_FAINT);
211    tui_block_add_title(f->a, &b, title, TUI_TITLE_DEFAULT);
212    tui_rect inner = tui_block_inner(&b, area);
213    mt_block(f, &b, area);
214    mt_par(f, mt_text(f, lines), inner);
215}
216
217/* One cell per logical CPU: a block whose height is its busy share, big cores bright, little ones dim. */
218static tui_span core_bar(uint8_t u, uint8_t c) {
219    static const char *const BARS[9] = {" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"};
220    if (u == 0xff) return mt_fgs("·", MT_FAINT);
221    size_t i = ((size_t)u * 8 + 50) / 100;
222    static const uint8_t little[3] = {110, 150, 200}, big[3] = {110, 190, 255};
223    tui_color col = u >= 90 ? MT_BAD : u >= 60 ? MT_WARN : mt_rgb(c == MESH_CORE_LITTLE ? little : big, c == MESH_CORE_LITTLE ? 0.7f : 1.0f);
224    return mt_styled(BARS[i < 8 ? i : 8], tui_fg_bg(col, MT_FAINT));
225}
226
227typedef struct {
228    const char *name;
229    uint16_t w;
230    uint8_t tier;
231} col;
232
233void mt_draw_load(mt_frame *f, tui_rect area, const mt_app *app) {
234    uint16_t n = (uint16_t)app->nmachines;
235    const mt_machine *m = mt_app_focused(app);
236    const char *pnames[MESH_PROG_SLOTS];
237    mt_prog_load ploads[MESH_PROG_SLOTS];
238    size_t nprogs = 0;
239    if (m->has_snap)
240        for (size_t i = 0; i < m->snap.nsections; i++) {
241            const mt_section *p = &m->snap.sections[i];
242            if (mt_snapshot_prog_load(&m->snap, mt_section_slot(p), &ploads[nprogs])) pnames[nprogs++] = mt_sec_name(f, p);
243        }
244    tui_rect r[4];
245    tui_constraint cons[4] = {TUI_LENGTH(tui_min16((uint16_t)(n + 3), area.height)), TUI_LENGTH(4), TUI_LENGTH(nprogs + 3), TUI_MAX(12)};
246    tui_vsplit(area, 4, cons, r);
247    tui_rect mach = r[0], cores = r[1], prog = r[2], hist = r[3];
248    /* Columns by tier: 0 always, 1 from 130 columns, 2 from 150. */
249    int tier = area.width >= 150 ? 2 : area.width >= 130 ? 1 : 0;
250    static const col cols[22] = {
251        {"machine", 14, 0}, {"GPU got", 7, 0}, {"10 s", 5, 0}, {"slice", 7, 1}, {"gap", 7, 1}, {"max gap", 7, 0},
252        {"gaps/s", 6, 2}, {"seen", 5, 2}, {"×lat", 5, 1}, {"queue", 6, 2}, {"busy ext", 8, 2}, {"CPU", 5, 0},
253        {"big", 5, 0}, {"little", 6, 0}, {"load", 5, 1}, {"PSI cpu/mem/io", 15, 0}, {"mem avail", 9, 0}, {"swap", 8, 2},
254        {"meshd", 5, 0}, {"rss", 5, 1}, {"disk free", 9, 1}, {"temp", 0, 1},
255    };
256    bool keep[22];
257    const char *header[22];
258    tui_constraint widths[22];
259    size_t nh = 0;
260    for (size_t i = 0; i < 22; i++) {
261        keep[i] = cols[i].tier <= tier;
262        if (keep[i]) {
263            widths[nh] = cols[i].w == 0 ? TUI_FILL(1) : TUI_LENGTH(cols[i].w);
264            header[nh++] = cols[i].name;
265        }
266    }
267    mt_rows rows = {0};
268    for (size_t i = 0; i < app->nmachines; i++) {
269        const mt_machine *mi = &app->machines[i];
270        tui_span name = mt_fgb(mt_name(f, mi), MT_MACHINE[i % 8]);
271        mt_load l;
272        if (!mi->has_snap || !mt_snapshot_load(&mi->snap, &l)) {
273            tui_table_cell c2[2] = {mt_cell_span(f, name), mt_cell_span(f, mt_fgs(mi->has_snap ? "no load sample" : mi->status, MT_DIM))};
274            mt_rows_push(f, &rows, mt_row(f, c2, 2));
275            continue;
276        }
277        bool g = l.share.some;
278        const char *psi;
279        if (l.has_psi)
280            psi = MT_FMT(f, "%s/%s/%s%%", mt_ff(f, l.psi[0] * 100.0f, 1), mt_ff(f, l.psi[1] * 100.0f, 1), mt_ff(f, l.psi[3] * 100.0f, 1));
281        else if (l.has_mem_level && l.mem_level == 1)
282            psi = "mem normal";
283        else if (l.has_mem_level && l.mem_level == 2)
284            psi = "mem warn";
285        else if (l.has_mem_level && l.mem_level == 4)
286            psi = "mem critical";
287        else
288            psi = "-";
289        const char *temp;
290        if (l.has_thermal)
291            temp = l.thermal < MESH_THERMAL_STATES_LEN ? MESH_THERMAL_STATES[l.thermal] : "?";
292        else if (l.temp_c.some)
293            temp = MT_FMT(f, "%s°C", mt_ff(f, l.temp_c.v, 0));
294        else
295            temp = "-";
296        tui_table_cell all[22] = {
297            mt_cell_span(f, name),
298            mt_cell_span(f, mt_share_span(f, l.share)),
299            mt_cell_span(f, mt_share_span(f, l.share10)),
300            mt_cell_str(f, g ? mt_fmt_us(f, l.slice_us) : "-"),
301            mt_cell_str(f, g ? mt_fmt_us(f, l.gap_us) : "-"),
302            mt_cell_span(f, mt_fgs(mt_fmt_us(f, l.max_gap_us), l.max_gap_us > 10000.0f ? MT_BAD : MT_FG)),
303            mt_cell_str(f, mt_ff(f, l.gaps_s, 0)),
304            mt_cell_span(f, mt_fgs(mt_ff(f, l.observed, 1), MT_DIM)),
305            mt_cell_str(f, l.inflate.some ? mt_ff(f, l.inflate.v, 2) : "-"),
306            mt_cell_str(f, l.queue_us > 0.0f ? mt_fmt_us(f, l.queue_us) : "-"),
307            mt_cell_str(f, l.util_ext.some ? mt_pct(f, l.util_ext.v) : "-"),
308            mt_cell_span(f, mt_styled(mt_pct(f, l.cpu), mt_busy_style(l.cpu))),
309            mt_cell_span(f, mt_styled(mt_pct(f, l.cpu_big), mt_busy_style(l.cpu_big))),
310            mt_cell_span(f, l.cpus_little > 0 ? mt_styled(mt_pct(f, l.cpu_little), mt_busy_style(l.cpu_little)) : mt_fgs("-", MT_FAINT)),
311            mt_cell_str(f, mt_ff(f, l.loadavg[0], 2)),
312            mt_cell_str(f, psi),
313            mt_cell_span(f, mt_styled(mt_gb_pair(f, l.mem_avail_mb, l.mem_total_mb), mt_busy_style(1.0f - l.mem_free))),
314            mt_cell_str(f, mt_gb_pair(f, l.swap_used_mb, l.swap_total_mb)),
315            mt_cell_span(f, mt_styled(mt_pct(f, l.meshd_cpu), mt_busy_style(l.meshd_cpu))),
316            mt_cell_str(f, MT_FMT(f, "%sM", mt_ff(f, l.meshd_rss_mb, 0))),
317            mt_cell_str(f, MT_FMT(f, "%sG", mt_ff(f, (float)l.disk_free_mb / 1024.0f, 0))),
318            mt_cell_str(f, temp),
319        };
320        tui_table_cell kept[22];
321        size_t nk = 0;
322        for (size_t c = 0; c < 22; c++)
323            if (keep[c]) kept[nk++] = all[c];
324        mt_rows_push(f, &rows, mt_row(f, kept, nk));
325    }
326    tui_line title = MT_LINE(f, mt_fgb(" load ", MT_FG),
327                             mt_label("GPU got: the share of wall time our work ran (measured inside our kernels / per Metal command "
328                                      "buffer); ×lat = 1 / share "));
329    tui_block pb = mt_panel(f, title, MT_FAINT);
330    tui_table_row hdr = mt_header(f, header, nh);
331    tui_table t = tui_table_new(rows.rows, rows.n, widths, nh);
332    t.header = &hdr;
333    t.column_spacing = 1;
334    t.block = &pb;
335    mt_table(f, &t, mach);
336
337    /* The focused machine's cores. */
338    if (cores.height > 0) {
339        tui_line ctitle;
340        mt_lines lines = {0};
341        mt_load l;
342        if (m->has_snap && mt_snapshot_load(&m->snap, &l)) {
343            tui_line big = tui_line_span(f->a, mt_label(MT_FMT(f, "%s%s  ", mt_pad(f, "big", 7, '<'), mt_pad(f, MT_FMT(f, "%u", l.cpus_big), 3, '>'))));
344            tui_line little = tui_line_span(f->a, mt_label(MT_FMT(f, "%s%s  ", mt_pad(f, "little", 7, '<'), mt_pad(f, MT_FMT(f, "%u", l.cpus_little), 3, '>'))));
345            tui_line other = tui_line_span(f->a, mt_label(MT_FMT(f, "%s%s  ", mt_pad(f, "cpus", 7, '<'), mt_pad(f, MT_FMT(f, "%u", l.cpus), 3, '>'))));
346            for (size_t i = 0; i < l.ncores; i++) {
347                tui_span bar = core_bar(l.cores[i][0], l.cores[i][1]);
348                if (l.cores[i][1] == MESH_CORE_BIG) tui_line_push(f->a, &big, bar);
349                else if (l.cores[i][1] == MESH_CORE_LITTLE) tui_line_push(f->a, &little, bar);
350                else tui_line_push(f->a, &other, bar);
351            }
352            if (l.cpus_little > 0) {
353                mt_lines_push(f, &lines, big);
354                mt_lines_push(f, &lines, little);
355            } else if (l.cpus_big > 0) {
356                mt_lines_push(f, &lines, big);
357            } else {
358                mt_lines_push(f, &lines, other);
359            }
360            ctitle = MT_LINE(f, mt_fgb(MT_FMT(f, " %s cores ", mt_name(f, m)), MT_FG), mt_label("busy per logical CPU, last second "));
361        } else {
362            ctitle = tui_line_span(f->a, mt_fgb(" cores ", MT_FG));
363            mt_lines_push(f, &lines, tui_line_span(f->a, mt_label("no load sample")));
364        }
365        tui_block cb = mt_panel(f, ctitle, MT_FAINT);
366        tui_paragraph p = tui_paragraph_new(mt_text(f, &lines));
367        p.block = &cb;
368        tui_paragraph_render(f->a, &p, cores, f->buf);
369    }
370
371    /* The focused machine's programs. */
372    if (prog.height > 0) {
373        static const char *const ph[15] = {"program", "GPU got", "10 s", "slice", "max gap", "seen", "p50", "p90",
374                                           "p99", "max", "n", "per task", "tasks/s", "busy", "queue"};
375        mt_rows prows = {0};
376        for (size_t i = 0; i < nprogs; i++) {
377            const mt_prog_load *l = &ploads[i];
378#define Q(x) ((x).some ? mt_fmt_us(f, (x).v) : "-")
379            tui_table_cell c[15] = {
380                mt_cell_span(f, mt_fgb(pnames[i], MT_FG)),
381                mt_cell_span(f, mt_share_span(f, l->share)),
382                mt_cell_span(f, mt_share_span(f, l->share10)),
383                mt_cell_str(f, l->share.some ? mt_fmt_us(f, l->slice_us) : "-"),
384                mt_cell_str(f, mt_fmt_us(f, l->max_gap_us)),
385                mt_cell_span(f, mt_fgs(mt_ff(f, l->observed, 1), MT_DIM)),
386                mt_cell_str(f, Q(l->p50_us)),
387                mt_cell_str(f, Q(l->p90_us)),
388                mt_cell_str(f, Q(l->p99_us)),
389                mt_cell_str(f, Q(l->max_us)),
390                mt_cell_span(f, mt_fgs(MT_FMT(f, "%u", l->lat_n), MT_DIM)),
391                mt_cell_str(f, Q(l->task_us)),
392                mt_cell_span(f, mt_fgs(mt_fmt_rate(f, l->tasks_s), MT_WARN)),
393                mt_cell_span(f, mt_styled(mt_pct(f, l->busy), mt_busy_style(l->busy))),
394                mt_cell_str(f, l->queue_us > 0.0f ? mt_fmt_us(f, l->queue_us) : "-"),
395            };
396#undef Q
397            mt_rows_push(f, &prows, mt_row(f, c, 15));
398        }
399        static const tui_constraint pw[15] = {
400            {TUI_C_LENGTH, 15, 0}, {TUI_C_LENGTH, 7, 0}, {TUI_C_LENGTH, 5, 0}, {TUI_C_LENGTH, 7, 0}, {TUI_C_LENGTH, 7, 0},
401            {TUI_C_LENGTH, 5, 0},  {TUI_C_LENGTH, 7, 0}, {TUI_C_LENGTH, 7, 0}, {TUI_C_LENGTH, 7, 0}, {TUI_C_LENGTH, 7, 0},
402            {TUI_C_LENGTH, 5, 0},  {TUI_C_LENGTH, 8, 0}, {TUI_C_LENGTH, 8, 0}, {TUI_C_LENGTH, 5, 0}, {TUI_C_FILL, 1, 0},
403        };
404        tui_line ptitle = MT_LINE(f, mt_fgb(MT_FMT(f, " %s programs ", mt_name(f, m)), MT_FG),
405                                  mt_label("task time from the trace (10 s), per task = node busy / tasks, seen = node-s observed idle per s "));
406        tui_block pb2 = mt_panel(f, ptitle, MT_FAINT);
407        tui_table_row phdr = mt_header(f, ph, 15);
408        tui_table pt = tui_table_new(prows.rows, prows.n, pw, 15);
409        pt.header = &phdr;
410        pt.column_spacing = 1;
411        pt.block = &pb2;
412        mt_table(f, &pt, prog);
413    }
414
415    /* GPU share and CPU history, one column per sample. */
416    if (hist.height > 2) {
417        size_t w = tui_sat_sub(hist.width, 2);
418        size_t nh2 = m->nload_hist;
419        uint64_t *share = tui_arena_alloc(f->a, (nh2 ? nh2 : 1) * sizeof *share);
420        for (size_t i = 0; i < nh2; i++) share[i] = m->load_hist[i][0];
421        size_t from = nh2 > w ? nh2 - w : 0;
422        uint64_t cpu = nh2 ? m->load_hist[nh2 - 1][1] : 0;
423        tui_line htitle = MT_LINE(f, mt_fgb(MT_FMT(f, " %s GPU got, %% per second ", mt_name(f, m)), MT_FG),
424                                  mt_label(MT_FMT(f, "CPU now %llu%% ", (unsigned long long)cpu)));
425        tui_block hb = mt_panel(f, htitle, MT_FAINT);
426        tui_sparkline sp = {0};
427        sp.data = share + from;
428        sp.n = nh2 - from;
429        sp.has_max = true;
430        sp.max = 100;
431        sp.style = tui_fg(MT_ACCENT);
432        sp.block = &hb;
433        tui_sparkline_render(f->a, &sp, hist, f->buf);
434    }
435}