skip to content
==> src/perf.c <==
1/* This member's F_PERF (load.rs perf_report and its frame): its CPUs and RAM, each loaded program's
2 * measured performance (the pload records just sampled), its reconcile failures, the link RTTs
3 * measured from the others' echoes, and the echoes of theirs; put on the perf board and broadcast. */
4#include "fleetd_int.h"
5
6#include "mesh/abi.h"
7#include "mesh/buf.h"
8#include "mesh/prog_table.h"
9#include "mesh/samplers.h"
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15static mesh_fleetd *PERF; /* the hook has no context: one fleet member per process */
16
17static uint32_t u32_at(const uint8_t *b, size_t o) {
18    uint32_t v;
19    memcpy(&v, b + o, 4);
20    return v;
21}
22static float f32_at(const uint8_t *b, size_t o) {
23    float v;
24    memcpy(&v, b + o, 4);
25    return v;
26}
27
28static void perf_report(mesh_shared *sh, const mesh_host_sample *h, const uint8_t *cls, size_t ncls, const uint8_t (*recs)[MESH_PLOAD_BYTES],
29                        size_t n) {
30    mesh_fleetd *f = PERF;
31    mpr_relay *r = f ? atomic_load(&f->relay) : NULL;
32    if (!r) return;
33    mesh_mailbox mb = sh->mb;
34    msr_report rep = {.t_us = (uint64_t)mesh_mono_us(), .ram_mb = h->mem_total_mb, .disk_free_mb = h->disk_free_mb};
35    for (size_t i = 0; i < h->ncpus && i < MESH_MAX_CPUS; i++) rep.cpus += h->have[i];
36    for (size_t i = 0; i < ncls; i++) {
37        rep.big += cls[i] == MESH_CORE_BIG;
38        rep.little += cls[i] == MESH_CORE_LITTLE;
39    }
40    rep.heap_kb = mesh_host_block_get_u32(&sh->host, MESH_S_HEAP_RUN) * (uint32_t)(MESH_VIEW_PAGE / 1024);
41    uint32_t progs = mesh_host_block_get_u32(&sh->host, MESH_S_PROGRAMS);
42    rep.slots_free = progs < MESH_PROG_SLOTS ? MESH_PROG_SLOTS - progs : 0;
43    pthread_mutex_lock(&f->mu);
44    for (size_t i = 0; i < f->nfails; i++) msr_add_fail(&rep, f->fails[i].name, f->fails[i].hash, f->fails[i].unsupported, f->fails[i].why);
45    pthread_mutex_unlock(&f->mu);
46    for (uint32_t s = 0; s < n; s++) {
47        const uint8_t *rec = recs[s];
48        uint32_t fl = u32_at(rec, MESH_PL_FLAGS);
49        uint32_t st = mesh_mailbox_get(mb, mesh_prog_entry(s) + MESH_PT_STATE);
50        if (!(fl & MESH_PLF_LOADED) || st == MESH_ST_EMPTY) continue;
51        msm_perf p;
52        memset(&p, 0, sizeof p);
53        p.hash = mesh_mailbox_get64(mb, mesh_prog_entry(s) + MESH_PT_PTX_HASH);
54        uint32_t ex = mesh_mailbox_get(mb, mesh_prog_ext(s) + MESH_PX_EXEC);
55        snprintf(p.exec, sizeof p.exec, "%s", ex < 4 ? MESH_BACKENDS[ex] : "?");
56        p.run = st == MESH_ST_RUNNING;
57        float task = 0;
58        bool has_task = false;
59        if (fl & MESH_PLF_TASK) task = f32_at(rec, MESH_PL_TASK_US), has_task = true;
60        else if (fl & MESH_PLF_LAT) task = f32_at(rec, MESH_PL_P50_US), has_task = true;
61        p.task_us = (mof32){has_task && task > 0, has_task && task > 0 ? task : 0};
62        p.tasks_s = f32_at(rec, MESH_PL_TASKS_S);
63        p.cpu = fl & MESH_PLF_HOST ? f32_at(rec, MESH_PL_CPU10) : 0;
64        p.share = (mof32){(fl & MESH_PLF_GPU) != 0, fl & MESH_PLF_GPU ? f32_at(rec, MESH_PL_SHARE10) : 0};
65        if (fl & MESH_PLF_HOST) {
66            uint64_t rss;
67            memcpy(&rss, rec + MESH_PL_RSS, 8);
68            p.rss_mb = (float)rss / 1048576.0f;
69        }
70        char name[MESH_NAME_BYTES + 1];
71        mesh_pt_name_of(mb, s, name);
72        msr_add_prog(&rep, name, &p);
73    }
74    uint32_t k[MESH_MAX_SYSTEMS];
75    uint64_t t[MESH_MAX_SYSTEMS], held[MESH_MAX_SYSTEMS];
76    size_t ne = mpr_board_echoes(r, k, t, held);
77    for (size_t i = 0; i < ne; i++) msr_add_echo(&rep, k[i], t[i], held[i]);
78    float us[MESH_MAX_SYSTEMS];
79    size_t nr = mpr_board_rtts(r, k, us);
80    for (size_t i = 0; i < nr; i++) msr_add_rtt(&rep, k[i], us[i]);
81    char *text = msr_encode(&rep);
82    size_t len = strlen(text);
83    if (len > MESH_F_PERF_MAX) len = MESH_F_PERF_MAX;
84    uint8_t *fr = mesh_xmalloc(5 + len);
85    fr[0] = MESH_F_PERF;
86    uint32_t l = (uint32_t)len;
87    memcpy(fr + 1, &l, 4);
88    memcpy(fr + 5, text, len);
89    mesh_shared_broadcast(sh, fr, 5 + len);
90    free(fr);
91    free(text);
92    mpr_board_own(r, &rep);
93    msr_free(&rep);
94}
95
96void fd_perf_set(mesh_fleetd *f) {
97    PERF = f;
98    mesh_load_perf = f ? perf_report : NULL;
99}