Skip to content

Alan/cmon polish - #1855

Open
leftwo wants to merge 71 commits into
mainfrom
alan/cmon-polish
Open

Alan/cmon polish#1855
leftwo wants to merge 71 commits into
mainfrom
alan/cmon-polish

Conversation

@leftwo

@leftwo leftwo commented Feb 14, 2026

Copy link
Copy Markdown
Contributor

Reviewer warning.

I started this PR 100 years ago, but over time I've been using claude to
iterate on it, and now it's almost all claude generated. I've gone over
what it has done, and it seems fine for this level of tool. However, I'm
more interested in the result it produces here than the actual code
itself as this is a tool that lives outside the product and none of the code
here is ever run in production. I've been using it and find it useful.

Summary

This PR adds ctop, an interactive curses monitor for Crucible upstairs
processes, and factors the display code it shares with cmon into a new
cmon-common library. cmon prints DTrace output a line at a time;
ctop gives you a top-like view of every upstairs on the system, with
history and a detail graph. It runs a DTrace command internally and then
processes the output, it does not require piping output like cmon.

ctop

ctop - Unix timestamp: 1787930755

    PID  SESSION DS0 DS1 DS2    NEXTJOB DELTA EXTL RECD RECN
   7508 104bab5a ACT ACT ACT   31372481   648    0 2692    0▆▆▇▇▆▆▆▆▆▆▇▇▆▇▆▆▇▆▆▆▆▆▆▇▇▆▅▆▇▆▆▆▆▇▆▆▆▆▆▇▆
   7508 1de71ca3 ACT ACT ACT   22763021   503    0 3200    0▅▅▅▅▅▅▅▅▅▅▅▅▅▄▅▅▅▅▅▅▅▅▅▅▅▄▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅
   7508 8229753b ACT ACT ACT   22819237   498    0 2176    0▅▅▅▄▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅
   7508 ce9954c6 ACT ACT ACT      38122     0    0    0    0▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
>  7508 e6871ed6 ACT ACT ACT   24301614   511    0 3200    0▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅
  18857 0bf19645 ACT ACT ACT   31186108   676    0    0    0▅▇▇▇▆▆▆▇▇▆▇▆▆▇▆▆▇▆▆▆▆▆▆▇▇▆▆▆▇▆▇▅▆▆▇▆▇▆▇▆▆
  18857 8ba590c2 ACT ACT ACT   23310144   477    0 1136    0▅▅▅▅▅▅▅▅▅▅▅▅▅▄▄▅▅▅▄▅▅▅▅▅▅▅▄▅▅▅▅▅▅▅▄▅▅▅▅▅▅
  18857 a2ed0106 ACT ACT ACT      37942     0    0    0    0▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
  18857 cc4492d1 ACT ACT ACT   23581824   568    0 1332    0▅▅▅▅▅▅▅▅▄▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▄▅▅▅▅▅▅▅▄▅▆
  18857 de5faf7a ACT ACT ACT   24768388   534    0 3200    0▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅
  18895 211b502e ACT ACT ACT   24260982   516    0 3200    0▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅
  18895 3d4b76e0 ACT ACT ACT   30419056   662    0 1232    0▇▆▆▇▇▇▅▆▆▆▆▇▆▆▆▆▆▇▆▆▆▆▆▆▆▇▆▆▇▆▅▆▅▆▆▆▆▆▆▆▆
  18895 6d904484 ACT ACT ACT      38169     2    0    0    0▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
  18895 8a94515c ACT ACT ACT   27009241   589    0 3160    0▅▅▅▅▅▅▆▅▅▅▅▅▆▅▅▅▆▅▅▅▅▅▅▅▆▅▅▆▅▅▅▆▅▆▆▆▅▅▅▅▆
  18895 a775db81 ACT ACT ACT   29557014   622    0 3200    0▅▆▆▇▆▆▆▆▆▆▆▆▆▆▅▆▆▆▆▆▆▅▆▇▆▇▆▆▆▆▆▆▅▆▇▆▆▅▆▇▆
  18906 aca70b98 ACT ACT ACT   27361584   595    0 2960    0▅▅▆▆▅▆▆▆▅▆▆▆▅▆▅▅▆▆▅▅▆▅▆▆▆▅▅▆▆▅▅▆▅▆▆▅▆▅▅▅▆
  18906 b643be83 ACT ACT ACT   33066801   654    0  184    0▆▆▆▆▆▇▆▆▆▇▆▆▆▇▆▆▇▆▆▆▆▆▆▇▇▇▅▆▇▆▆▆▆▆▇▇▇▆▆▆▆
  18906 bda4a25e ACT ACT ACT   28265673   626    0    0    0▅▅▅▆▆▅▅▆▅▆▅▅▅▅▅▅▅▆▆▅▅▅▅▅▅▆▆▅▅▆▅▆▅▅▆▆▅▅▅▆▆
  18906 bffa39d4 ACT ACT ACT   25272553   520    0    0    0▅▅▆▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅
  18906 dd2e1392 NEW NEW NEW     127230     0    0    0    0▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
  18906 f2f7928e ACT ACT ACT     160179     0    0    0    0▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
  22288 526de860 ACT ACT ACT   22424752   510    0  148    0▅▅▄▅▅▅▅▅▅▅▅▄▅▅▄▄▅▅▅▅▅▄▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅
  22288 a04f6640 ACT ACT ACT   26836497   617    0  572    0▆▅▆▅▅▆▅▅▅▆▅▆▅▅▅▅▅▅▅▅▅▅▆▆▆▆▅▅▆▆▅▅▅▆▆▅▅▅▅▅▆
  22288 a6a08f12 ACT ACT ACT      33361     0    0   28    0▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
  22288 d7a6c94d ACT ACT ACT   30059745   679    0 3200    0▆▅▆▆▇▆▅▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▇▅▆▆▆▆▇▅▇▆▆▆▆▆▆▇
  22288 d904c02d ACT ACT ACT   30429055   568    0 3144    0▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▇▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆
  26007 0008a369 ACT ACT ACT   30343149   640    0 1168    0▆▆▆▅▆▅▆▆▆▆▆▆▆▆▆▅▆▆▆▅▆▆▅▆▆▆▅▆▆▆▅▆▆▆▆▆▆▆▆▆▆
  26007 1f18cc30 ACT ACT ACT   23339947   484    0    0    0▄▄▅▅▅▅▅▅▅▅▅▅▅▅▄▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅
  26007 5accd66c ACT ACT ACT   27070163   553    0 2348    0▆▆▆▆▅▆▅▆▆▅▅▆▅▅▅▅▆▅▅▆▅▅▆▆▅▆▅▅▆▅▅▆▅▅▆▅▆▅▅▆▅
  26007 68e020ff ACT ACT ACT      34445     0    0   28    0▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
  26007 9e2b5e43 ACT ACT ACT   27187929   581    0 3076    0▅▆▆▆▅▅▆▆▅▆▅▆▅▆▆▅▆▆▅▅▅▅▅▆▆▅▅▅▆▅▅▅▅▆▅▆▅▅▆▆▆
  26007 a31640fe ACT ACT ACT      17580     0    0    0    0▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

[↑↓/PgUp/PgDn: Navigate | 'd': Details | 'q': Quit] > = selected, * = stale (5s)               [5/32]

One row per session, sorted by pid then session id. DELTA is how far
NEXTJOB moved since that session's previous record, so it is a rate of
jobs per second while records keep arriving; the sparkline on the right
is the last hundred of those, scaled against the busiest session on the
screen so rows can be compared against each other.

> marks the selected row and * a session that has not reported for
five seconds. A session that goes quiet for thirty seconds is dropped.

Detail view

d opens the selected session's delta history as a graph:

  1441 91902e16 ACT ACT ACT  677582142 12690    0  392    0
┌ Delta History - PID 1441 - Session 91902e16 ─────────────────────────────────────────────────────┐
│12923                  ⢠⠓⢄    ⢀⢴                                                                  │
│                       ⡜ ⠈⠢⡀⡠⠒⠁⠈⡆                                                                 │
│     ⠈⠉⠉⠉⠹⡀           ⢰⠁   ⠈    ⡇         ⢠                                                       │
│12786     ⢇           ⡎         ⢸         ⡎⢇                                                      │
│          ⠸⡀         ⡸          ⠸⡀       ⢠⠃⠘⡄                                     ⡜⡄              │
│           ⢇        ⢀⠇           ⡇       ⢸  ⢱                                    ⡸ ⢣         ⢀    │
│12649      ⠸⡀      ⢀⠎            ⢇       ⡇   ⢇       ⢠                 ⡰⡀       ⡰⠁ ⠘⡄     ⡠⠔⠊⠁    │
│            ⢇     ⡠⠃             ⢸      ⢰⠁   ⠘⡄      ⡇⢇     ⢀         ⢠⠃⢇      ⢠⠃   ⢣    ⢰⠁       │
│            ⠸⡀   ⡔⠁              ⠘⡄     ⡜     ⢱     ⢸ ⠘⡄   ⢀⠎⢆       ⢀⠇ ⠘⡄    ⢀⠇    ⠘⡄  ⢀⠇        │
│12512        ⠉⠉⠉⠉                 ⡇    ⢀⠇     ⠈⡆   ⢀⠇  ⠱⡀ ⢀⠎ ⠘⡄      ⡜   ⢣    ⡜      ⢣  ⡜         │
│                                  ⢱    ⢸       ⢸   ⡸    ⢣⢀⠎   ⠱⡀    ⡸    ⠈⡆  ⢰⠁      ⠘⡄⡸          │
│                                  ⢸    ⡎        ⢇ ⢠⠃    ⠈⠎     ⢣  ⢀⠔⠁     ⢱ ⢠⠃        ⢣⠃          │
│                                   ⣇⣀ ⢠⠃        ⠘⡄⡜            ⠈⢆⡠⠊        ⡇⡎                     │
│12376                                ⠉⠉          ⢣⠃             ⠈          ⠘                      │
└ Samples: 25 | Min: 12376 | Max: 12923 | Avg: 12622 | Current: 12690 | Scale: 12376-12923 ────────┘
['d'/Esc: Back | 'n': Toggle normalize | 'q': Quit]

n toggles normalization: the graph is scaled to every session on the
system rather than just this one, which is how you compare a quiet
session against a busy one. Min and Max always describe the
selected session, and Scale is what the axis is actually scaled to, so
the two do not have to agree.

Keys

Key Effect
/ Move the selection
PgUp / PgDn Move by a screen
d Enter or leave the detail view
Esc Leave the detail view
n Toggle normalization in the detail view
q, Ctrl-C Quit

Running it

ctop needs DTrace privileges, so you may need to elevate

pfexec ctop

Without them DTrace exits immediately, and ctop complains.
You can use --dtrace-cmd to replace the built in DTrace command.

ctop is added to tools/make-nightly.sh and to tools/make-utils.sh, so
it lands in the nightly archive and in the sled global zone alongside
crucible-verify-raw.

cmon-common

format_header(), format_row(), the DtraceDisplay field list, the
default field set and short_state() now live in one place, which both
tools call. New tests make sure cmon and ctop don't drift apart by
walking every DtraceDisplay variant and checking the header and the
row agree on the width of that field.

cmon

cmon dtrace now expects the wrapped JSON that upstairs_raw.d emits
(see below), and gained pid, session and upstairs_id fields along
with single column forms of several existing ones.

upstairs_raw.d

The script now wraps each record with the pid of the upstairs that
produced it:

{"pid":<pid>,"status":{ ...DtraceInfo... }}

This allows us to tell records from different processes apart once they
interleave. tools/dtrace/README.md documents the format with a worked
example.

Testing

cargo nextest run -p ctop -p cmon-common, plus manual runs against
captured and synthetic DTrace output at a range of terminal sizes,
including the failure paths where the DTrace command cannot start.

I've also been using this for months to watch crucible on dogfood and
on the racklettes to see what is going on.

leftwo and others added 30 commits August 27, 2026 12:34
Found a bunch of places where we just panic and don't include session or
client id.

Started from here: #1924
But, then just found a bunch more.

Co-authored-by: Alan Hanson <alan@oxide.computer>
`Volume::construct` was unintentionally adding another layer of Volume
when constructing from a request. Remove this, ensuring that what is
constructed matches the request.
Add a new VolumeInfo enum that will be returned and provide a richer
tree of information that matches the shape of the Volume. The intended
consumer of this is the control plane in a few areas:

- when performing region replacement or region snapshot replacement, the
control plane needs to know when to consider the live repair or
reconciliation successful, ultimately proceeding to cleaning up the
temporary resources and continuing with another replacement. The
upstairs has always been the source of this answer but the plan is to
move from using activation as this signal to using this introduced enum

- when activating with only 2 out of 3 downstairs available, the control
plane needs to know the difference between an unhealthy volume and one
that activated early with 2 out of 3 but eventually had all 3 mirrors
online.

- in the future, the control plane could query for health when
performing updates or sled reboots, pausing until impacted Volumes
become healthy again

The VolumeInfo enum already existed so this PR renames that to
VolumeExtentInfo. Eventually we should probably combine the two.
Drift 0.1.4 includes oxidecomputer/drift#20 and
oxidecomputer/drift#22 -- the latter is
particularly important because it can lead to false negatives where
actually-incompatible APIs are marked as compatible.
Now that Omicron uses reqwest 0.13, we can update omicron/oximeter, and
remove the explicit dependency on reqwest 0.12.
This is required for the simulated Pantry embedded in omicron's
simulated sled-agent.
Chasing down a cargo build failure in propolis caused by multiple
versions of the same package lead to the discovery that rev of omicron
that is in propolis' lock file is old, about 700 commits behind main.
Once propolis was updated to the same rev of omicron that crucible uses,
cargo no longer hit that same build error.

Use explicit git revs in Cargo.toml: this doesn't change the version in
the lock file but does make it explicit what is being used. Propolis
will be updated shortly to pull this commit in (a no-op, as the lockfile
version doesn't change), and will be updated to use explicit revs in the
same way.
I'll continue work in other tests, but wanted to start with making
crutest main use slog instead of println.
It can be difficult to parse messages when println and slog are
interleaved.

I started to do this work in the 2/3 PR that Matt started, but better to
split this out and not add
extra noise to that PR.
Added the volume-info command to crutest cli.
This will get the VolumeInfo, make it json, and send it over to the CLI.
Update Crucible's Omicron to
oxidecomputer/omicron@5fd53a9.

Also run `cargo update rand@0.8.5 daft` to resolve dependency conflicts.
This provides a pantry test program and a few basic commands to talk to
a running pantry server. It allows some exercise of the pantry outside of omicron.
Initial support for attach, detach, status, and volume-status. 
The pantest program uses dsc to get information and from that constructs
a VCR to use with the pantry.

This also adds a "readonly" endpoint to dsc. This allows us to get everything
we need from the dsc server to create a volume and attach it to the pantry.
…1948)

When a read-only upstairs is deactivating and a downstairs reconnects
and negotiates to WaitQuorum,
on_reconciliation_skipped() previously hit a catch-all arm that logged a
warning but left the client stuck in WaitQuorum. Since
ready_to_deactivate() only returns true for WaitConnect, deactivation
could never complete.

Deactivate any client in WaitQuorum when the upstairs is in the
Deactivating state. This moves them through
Stopping(Deactivated) and back to WaitConnect, allowing deactivation to
finish.

Fix for #1947
Holding the `entries` lock across an activation or deactivation will
lock out _all_ other Pantry operations. If a activation or deactivation
can not complete, this makes the Pantry un-usable.

Drop the mutex guards before long-running operations.

Also: in the Pantry implementation, re-implement `attach` in terms of
`attach_activate_background`, which already does the activation in the
background and drops the `entries` lock. However callers of `attach`
expect the Volume to be activated when the call returns so wait for the
background job.

Co-authored-by: Alan <alan@oxide.computer>

Fixes #1945.
When detaching a Volume from the Pantry, garbage-collect all the related
jobs. A previous commit changed the implementation of `attach` to be
implemented in terms of `attach_activate_background`, and this used the
volume_id as the supplied job_id, This caused a problem because the
re-use of a job_id isn't allowed, meaning that clients of the Pantry
could only attach a volume once!
Found this while debugging a nightly test failure.
This is not related to the failure.

Co-authored-by: Alan Hanson <alan@oxide.computer>
Ack flushes on read-only volumes without sending to downstairs

A flush on a read-only volume has no data to persist, so ack it
immediately in the guest Flush path instead of sending it to the
downstairs.

This broke a test, test_no_read_only_live_repair, which relied on a
guest flush reaching the downstairs to retire skipped jobs after a
fault.  Retiring completed jobs still must happen, but in the
production code the auto-flush will come around and clear these
jobs out.  The internal flush timer for the test framework is pinned
to 24 hours, so to enable the internal flush we add a test-only
BlockOp::FlushCheck and guest.flush_check() that runs the same work
the automatic flush timer performs.  Unlike a guest flush, this path
still sends the flush to the downstairs on a read-only volume.  Updated
the test to use this new path.  This appears to be a simpler solution and does
not require the heavier modification that enabling the auto flush on
all tests would involve.  Enabling auto-flush for all tests would
add non-determinism to many tests that don't expect it.
…me will be. (#1957)

Print more helpful info if this condition arises.

The extent number if printed as uppercase hex with 3 digits is how the
extent file will be named, so print this out as well to help someone
doing debug.

---------

Co-authored-by: Alan Hanson <alan@oxide.computer>
Added some documentation around what the nightly class tests expect for
incoming environmental variables and how the tests should use them.
These are things we already did, just writing them down somewhere.

Other work coming later in this area.

Added a bit more info about the system we are running on for the nightly
test.
Don't print the confusing message 
client 0 is in state Active not ready for activation

Co-authored-by: Alan Hanson <alan@oxide.computer>
Added an option to crucible-verify-raw that will produce csv output
instead of a formatted print.  This will allow easier post processing of
the output and ease comparing output from different extent files.

Example output: 
```
BRM42220006 # /tmp/crucible-verify-raw --verbose-csv AEF | head
# file:AEF bs:512 bytes  bc:131072  dirty:true gen:4 flush_number:37009787 ext_ver:2 bonus_sync:21543 defrag:939
file,block,dirty,status,slot_a_result,slot_a_flush_id,slot_a_hash,slot_b_result,slot_b_flush_id,slot_b_hash,selected_slot,data_hash,all_zeros
AEF,0,true,ok,HashMatch,47428,18362918644890996774,SlotHashMismatch,45302,16039251774303925735,true,18362918644890996774,false
AEF,1,true,ok,HashMatch,47428,13247521920287360720,SlotHashMismatch,45302,13200850826928211362,true,13247521920287360720,false
AEF,2,true,ok,HashMatch,47428,10545746106689772998,SlotHashMismatch,45302,12954128592411415433,true,10545746106689772998,false
AEF,3,true,ok,HashMatch,47428,6884446101332089095,SlotHashMismatch,45302,11361899870660325085,true,6884446101332089095,false
AEF,4,true,ok,HashMatch,47428,16980956734254118825,SlotHashMismatch,45302,2419870224295018126,true,16980956734254118825,false
AEF,5,true,ok,HashMatch,47428,16285263515216636595,SlotHashMismatch,45302,17408677481660435227,true,16285263515216636595,false
AEF,6,true,ok,HashMatch,47428,11101626895967727594,SlotHashMismatch,45302,9823985220066489586,true,11101626895967727594,false
AEF,7,true,ok,HashMatch,47428,38394401569940404,SlotHashMismatch,45302,1861286921230100119,true,38394401569940404,false
```

I'm building some other tools to compare output from
crucible-verify-raw, but moving to csv first will make that whole
process easier.

---------

Co-authored-by: Alan Hanson <alan@oxide.computer>
Move the shared display formatting into cmon-common.  cmon and ctop each
carried a near identical copy of format_header() and format_row() which
had already drifted apart, and both had the same LRC0/LRC1/LRC0 typo in
the LiveRepair header.  A test now walks every DtraceDisplay variant and
checks the header and the row agree on that field's width.

Fix cmon's job delta.  It kept one last job id for every session, but
the raw dtrace script matches every upstairs on the system, so rows from
different sessions interleave and the subtraction underflowed: an abort
in a debug build, a wrapped value in a release one.  Job ids are now
tracked per session.  cmon also spun printing parse errors once stdin
reached EOF, and now stops.

Report why ctop's dtrace command stopped.  Its stderr went to /dev/null
and the exit status was ignored, so the common failure of not having
enough privilege looked exactly like an idle system: an empty table and
no explanation.

Rebuild the ctop table on a ratatui Table.  It clips rows to the
terminal instead of letting them wrap and push the layout apart, scrolls
itself to keep the selection visible, and follows resizes, replacing the
hand rolled cursor, clear and scroll offset handling.  The terminal is
also restored now when the display loop returns an error, not only when
it exits normally.

Pace the ctop redraws.  Input is answered at once, arriving records get
at most one repaint every 250ms, and an idle screen still refreshes once
a second.  With 40 sessions that cut CPU use about four fold.  Input is
drained each pass, so a held arrow key stops when it is released.  The
selection now names a session rather than a row number, so sessions
coming and going above the cursor no longer move it onto a different
session.

Rename the ERR and ERN columns to RECD and RECN.  They count extents
reconciled and extents needing reconciliation, and there is a separate
error column, so the old names read as something they were not.

Describe the pid wrapper that upstairs_raw.d emits, in the script and in
the dtrace README, and add ctop to make-nightly.sh and make-utils.sh so
it reaches a sled.
The two bottom titles competed for the same border, so the key help was
cut off part way through.  Move the keys onto their own line below the
graph, where the table view already puts them, which leaves the whole
bottom border to the statistics.  That line now names Esc as well.

Normalizing scales the axis to every session while the statistics still
described only this one, so the two read as though they disagreed.
Report the range the axis is actually scaled to alongside them.

The y axis labels were printed on top of the oldest samples.  Extend the
x range to the left of the first sample by the width of the labels so
they have a strip to themselves, and drop duplicate labels, which a
session sitting at one value produced five of.
The two test modules carried about 230 lines of prose describing
coverage that does not exist.  Move what is worth doing into
ctop/TODO.md and let the tests that are there speak for themselves.
Drop one cmon-common test that only checked the compiler implements
Copy, and correct another whose comment claimed a bound it did not
assert.

render_sparkline's doc offered to scale "if global_max is provided",
which is not optional, and described the sparkline as showing values
over time.  It plots one column per recorded sample, so a session that
stops reporting holds its shape rather than leaving a gap.  Say so, and
say the same of the job delta, which is a rate per second only for as
long as records keep arriving.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants