L
ling-sys
↓ 0 downloadsSystem activity and performance monitor in the Ling Design System — dials, meshes, drums and crosshatch for CPU, GPU, memory, disk, network, board, processes and audio, with every subsystem given a voice. A LingOS app for rpi5: live board/CPU/memory/process stats from the kernel (stats-lingos.ling).
lingfu install ling-sysCode / Files (13)
stats-lingos.ling
# ============================================================
# stats-lingos.ling — native sources for LingOS. The kernel's
# app runtime answers os_info / os_uptime / os_apps_running /
# os_platform; everything it reports here is real, and what it
# cannot report stays at zero rather than being invented.
# host, board, platform os_info / os_platform
# uptime os_uptime
# memory free MiB against the kernel's
# real RAM total (mem_total)
# network, disk byte counters the NIC and disk
# drivers keep (net_rx/net_tx,
# disk_rd/disk_wr), shown as rates
# task switches the scheduler's switch counter
# temperature, clock the Pi's SoC sensor and ARM clock
# (blank on x86)
# processes the running app list
# There is no per-core CPU or GPU counter in the kernel, so those
# instruments stay at zero.
# ============================================================
# substring test by scanning (str_contains is not a builtin)
fn lhas(s, sub) {
bind n = len(s)
bind m = len(sub)
if m < 1 { return 0 }
bind i = 0
while i + m <= n {
if str_slice(s, i, m) == sub { return 1 }
bind i = i + 1
}
return 0
}
# "123 MiB free" -> 123
fn lmem_free_mib() {
bind ms = os_info("memory")
bind parts = str_split(str_trim(ms), " ")
if len(parts) < 1 { return 0.0 }
return to_number(list_get(parts, 0))
}
fn lstats_info() {
if st_get("linfo_done", 0.0) == 1.0 { return 0 }
bind board = os_info("board")
if len(board) < 2 { return 0 }
st_set("i_host", os_info("hostname"))
st_set("i_board", board)
st_set("i_os", os_platform())
# the SoC and clocks follow the board model
bind soc = "ARM"
bind mhz = "1000"
if lhas(board, "Pi 5") == 1 {
bind soc = "BCM2712"
bind mhz = "2400"
}
if lhas(board, "Pi 4") == 1 {
bind soc = "BCM2711"
bind mhz = "1500"
}
if lhas(board, "Pi 3") == 1 {
bind soc = "BCM2837"
bind mhz = "1200"
}
st_set("i_cpu_name", soc)
st_set("i_cpu_mhz", mhz)
st_set("i_cpu_threads", "4")
st_set("s_cpu_count", 4.0)
st_set("i_gpu_name", "VIDEOCORE " + os_info("display"))
st_set("i_snd0", "LINGOS AUDIO")
st_set("i_snd_n", "1")
bind ip = os_info("ip")
if len(ip) > 0 {
st_set("i_bios", ip + " " + os_info("network"))
}
st_set("linfo_done", 1.0)
return 0
}
# a cumulative kernel counter -> per-second rate in s_<name>
# (the first reading only records the baseline)
fn lrate(key, name, dt) {
bind raw = os_info(key)
if len(raw) < 1 { return 0 }
bind now = to_number(raw)
bind prev = st_get("lc_" + key, 0.0 - 1.0)
st_set("lc_" + key, now)
if prev < 0.0 { return 0 }
bind r = (now - prev) / dt
if r < 0.0 { bind r = 0.0 }
st_set("s_" + name, r)
return 0
}
fn lstats_poll(t) {
if t - st_get("lpoll_at", 0.0 - 9.0) < 1.0 { return 0 }
bind dt = t - st_get("lpoll_at", t - 1.0)
if dt < 0.2 { bind dt = 1.0 }
st_set("lpoll_at", t)
lstats_info()
st_set("s_uptime", os_uptime())
# the kernel's own counters: network, disk, task switches, SoC temperature, clock
lrate("net_rx", "net_rx", dt)
lrate("net_tx", "net_tx", dt)
lrate("disk_rd", "disk_read", dt)
lrate("disk_wr", "disk_write", dt)
lrate("switches", "cswitch", dt)
bind tmp = os_info("temp")
if len(tmp) > 0 { st_set("s_board_temp", to_number(tmp)) }
bind clk = os_info("clock_mhz")
if len(clk) > 0 { st_set("i_cpu_mhz", clk) }
# memory: free MiB against the most free ever seen this run
bind free = lmem_free_mib()
if free > 0.0 {
# a real event: free memory moved by 4 MiB or more since the last reading
if abs(free - st_get("lprev_free", free)) >= 4.0 { st_set("ev_mem", 1.0) }
st_set("lprev_free", free)
bind base = st_get("lmem_base", 0.0)
if free > base {
bind base = free
st_set("lmem_base", base)
}
# the kernel's real RAM total when it reports one, else the high-water mark
bind mt = os_info("mem_total")
if len(mt) > 0 {
if to_number(mt) > base { bind base = to_number(mt) }
}
st_set("s_mem_total", base)
st_set("s_mem_used", base - free)
}
# the running apps are the process drum
bind apps = os_apps_running()
bind n = len(apps)
# a real event: an app started or stopped
if n != st_get("lprev_apps", n) { st_set("ev_proc", abs(n - st_get("lprev_apps", n))) }
st_set("lprev_apps", n)
st_set("s_procs", n)
bind shown = n
if shown > 8.0 { bind shown = 8.0 }
st_set("s_proc_n", shown)
bind i = 0
while i < shown {
st_set("s_proc" + num_str(i), list_get(apps, i) + "|0|0")
bind i = i + 1
}
st_set("stat_ticks", st_get("stat_ticks", 0.0) + 1.0)
hist_tick(t)
return 0
}