# `Ascii.Pieces.CpuMeters`
[🔗](https://github.com/houllette/ascii_art/blob/main/lib/ascii/pieces/cpu_meters.ex#L1)

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

```elixir
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
```

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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
