Ascii.Pieces.CpuMeters (Ascii v0.3.0)

Copy Markdown View Source

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. Default nil.
  • uptime - seconds up at play time 0, up to a billion; it counts on as play goes. Default nil.
  • 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 all bar.user.
  • bar.used, bar.buffers, bar.cache - memory's and swap's (|, # and *), green, blue and yellow.
  • value - a reading, and in the table value.virt, value.res, value.cpu, value.mem and value.time.
  • header - the table's, green.
  • pid, user, command - a process's.
  • status.running (R), green, or status.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 just status.

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).