Htop-style core, memory and swap meters over a process list.
The top of an htop screen. Eight cores split into user and kernel time, memory and swap bars, load and uptime, and the busiest processes. As upstream draws it, a made-up machine is busy; each reading you give replaces that part of it, and the rest plays on.
Options
Give them to Ascii.new/2 as options:, and new ones while it plays
with Ascii.put_options/2 (or a Phoenix player's options), as the
readings change: the simulation carries on under them, so the parts not
given keep moving rather than start over. Ascii.BEAM.cpu_meters/1
gives this BEAM's own readings, its schedulers as cores.
cores- each core's use, in percent: a meter each, in two columns. More than eight make the frame taller; up to 32 show. Default[]: upstream's eight.memory,swap-[used, total], in gigabytes. Default[].load- the load averages, up to three. Default[].tasks- the number of tasks, up to a million. Defaultnil.uptime- seconds up at play time 0, up to a billion; it counts on as play goes. Defaultnil.processes- rows of%{pid, user, cpu, mem, virt, res, time, state, command}(cpu and mem in percent, virt and res in gigabytes, time in seconds, state a letter as"R"or"S"; any may be left out), of which the five busiest are shown. Default[].commands- the names of upstream's made-up processes. Default["build", "indexer", "server", "backup", "sync", "editor", "shell"]; new ones start its simulation afresh.
The frame is 66 wide, and 16 rows tall, or more for more than eight
cores. Every row of the table is the frame's width, whatever it holds. A
reading too wide for its column is written shorter: a pid takes room
from the user's name, a size from 100G is in whole gigabytes and from
1000G in terabytes (1.95T) or petabytes, a percentage loses its
decimal, then goes to thousands (12k) or millions, and a CPU time from
a thousand hours is in days and hours (41d16h). Each reading has a
range of its own: a pid up to 4,294,967,295, CPU% up to ten million,
MEM% up to 100, sizes up to a billion gigabytes and times up to a
billion seconds, none below zero. Upstream's own readings always fit,
and are written as upstream writes them, but for CPU times past a
thousand hours, which upstream's simulation reaches after some ten days
of play.
Colours
In one ink, or a gradient, with :ink and :gradient (see
Ascii.Ink); part by part with :parts (see Ascii.Parts),
parts: true taking the colours suggested here, htop's own:
label- a meter's or a reading's name, cyan: a core's number,Mem,Swp,Tasks:,Load average:,Uptime:.frame- a meter's brackets, grey;track, its empty cells, grey.bar.user,bar.system- a core's user and kernel time (|and#), green and red; a core's use given is allbar.user.bar.used,bar.buffers,bar.cache- memory's and swap's (|,#and*), green, blue and yellow.value- a reading, and in the tablevalue.virt,value.res,value.cpu,value.memandvalue.time.header- the table's, green.pid,user,command- a process's.status.running(R), green, orstatus.sleeping(S), grey, a process's state; or for a state given,status.waiting(D),status.zombie(Z),status.stopped(T),status.idle(I), or juststatus.
Keys and clicks
It takes none: it shows readings, and Ascii.handle_event/2 ignores
every event. A Phoenix player given interactive and notify still tells
your LiveView where it was clicked, and on which part
(Ascii.part_at/4): a process's pid or command, say, to show more
of it.
Screen readers
Ascii.describe/1 reads the readings given: the cores' average,
memory and swap, the load, tasks, uptime and the busiest process, as
"cpu meters: 2 cores 52% busy on average, memory 5.3 of 15.5 gb, load
0.50 0.25 0.13, 142 tasks". With none given, it gives the piece's name
and note.
Example
readings = %{cores: [72, 31], memory: [5.3, 15.5], load: [0.5, 0.25, 0.13], tasks: 142}
meters = Ascii.new!("cpu-meters", options: readings, parts: true)
Ascii.describe(meters)
#=> "cpu meters: 2 cores 52% busy on average, memory 5.3 of 15.5 gb, load 0.50 0.25 0.13, 142 tasks"
# This BEAM's own, measured between two samples.
sample = Ascii.BEAM.sample(Ascii.BEAM.sample())
meters = Ascii.put_options!(meters, Ascii.BEAM.cpu_meters(sample))
length(meters.options.cores) == System.schedulers_online()
#=> true<Ascii.Phoenix.live_player id="top" piece="cpu-meters" options={Ascii.BEAM.cpu_meters(@sample)} parts />Ported from src/pieces/cpu-meters.ts in bas3line/ascii (MIT).