Age | Commit message (Collapse) | Author |
|
Another row clipping check off by one, it'd be nice to make this
draw text into partial rows... but this as-is may just scribble.
|
|
No functional change, just firming up some assumptions
|
|
|
|
This really needs to be a clock unaffected by ntp adjustments,
which CLOCK_MONOTONIC_RAW seems to provide.
|
|
I prefer this be on its own in the upper right corner.
|
|
This draws the new scheduling "adherence" metric in a row below the top
IOWait/Idle% row.
The headings have moved down one to cover "adherence" instead,
which I think should help make the important IOWait/Idle% row
more visible as well as improving headings readability.
The adherence row should generally be either black or red, rarely
cyan.
Red indicates %age of sampling interval behind schedule for the
given sample, Cyan indicates same but ahead of schedule which
should be unusual/almost never happen. Infact I think the
current sharing of the "close enough" epsilon as adherence
truncating threshold the ahead of schedule "close enough"
situations will always get truncated to zero. So it might be
impossible to see any cyan adherence as-is right now.
A future commit will move the '\/\/\ # %name @ Hz' heading up to
the IOWait/Idle% putting it back in the upper right corner, but
only that one.
|
|
This will likely be made more dynamic in the future, but for now
there's a need to shift "rest" down another row to make room for
the "adherence" row. This is a simple way to accomodate that,
another preparatory commit.
|
|
This is an attempt to add a schedule adherence metric which a
subsequent commit will plot in a row below the top IOWait/%Idle %
row.
Ideally the adherence metric's value would always be 0, because
we're always exactly on-time with our samples.
But what tends to happen is falling behind, or rarely being
slightly ahead of schedule (particularly with the epsilon
introduction).
This metric can serve as a sort of proxy for userspace's ability
to get scheduled on time, which is a useful thing to see.
|
|
This introduces a concept of a "close enough" epsilon value.
Where if the attempted update's current time is within very small
temporal distance from the precisely scheduled time dictated by
the interval, the update will still take a sample, rather than
try introduce a tiny dely the host/kernel/ppoll will likely fail
to adhere to without being tardy.
Previously the desired delay was just a third of the interval,
with no consideration for how long sampling took. This was dead
simple, but made no attempt to schedule the poll timeout to align
with the next sampling deadline, and would either cause excessive
wakeups, or excessive tardiness, depending on the host's speed.
I think this technically also fixed a bug where this_delta
wouldn't get assigned if one of the earlier conditions
short-circuited the later condition where it was being assigned.
|
|
This is mostly preparotory for having more precision in a
computed delay, but is also arguably just finishing what was
started when adding the _us suffixes throughout.
A future commit should also rework signal stuff to only unblock
signals in ppoll().
|
|
Switch to using vcr_backend_poll() like everything else which
will do the right thing about handling delay_us.
|
|
This should have been done when draw_chart() and
draw_chart_rest() were split apart making draw_chart()
non-recursive. But it becomes much more glaringly obvious in a
world where maintain_chart() is calling draw_chart() in multiple
places.
|
|
This is preparatory for shifting heading off row 0 which until
now has been the safe assumption, but I'm intending to add an
"adherence" row below the IOWait/Idle top row. The headings
will be moving down to that.
|
|
primarily s/sampling_interval/sampling_interval_secs/ units
clarification
|
|
This applies charts->this_sample_duration by advancing and drawing
the graph bars this_sample_duration times.
It's a bit crufty with conditionals especially where it overlaps
with deferred_pass handling... but seems to work ok in initial
tests.
Future work will have to add a row indicating how far we've
deviated from the scheduled sample time... Maybe cyan would show
how premature we were, and red how late we were. Where 100%
would be the entire sample interval was exceeded, but < 100%
would show our still more or less on-schedule scheduling
deviations.
|
|
This turns the time passed since the last sample taken into a
"sample duration".
Ideally this would always be 1, and up until now in the main use
case, vwm, it's been assumed to generally be 1 and drops in the
timeline treated benign/fleeting because of the live viewing.
But with the introduction of --headless and increasing use on my
servers / embedded interests, this has become more problematic.
In this commit the duration is only being maintained, but not
applied.
Subsequent commits will have to repeat the current sample in the
graphs (this_sample_duration - 1) times.
|
|
Mechanical renaming of this vestigial name choice from when
vmon_proc_t was below the "monitor". Now it's just the
vmon_proc_t pointed at from the chart, so let's name accordingly.
No functional change.
|
|
More clarification of delay/timeout units in naming.
|
|
More clarification of delay/timeout units in naming
|
|
This API is targeting poll() usage which implies microseconds,
but let's better clarify it in naming.
|
|
vcr_backend_poll() mirrors the poll() api, but let's clarify the
timeout units as microseconds.
|
|
For rows reflecting threads and single/non-threaded processes,
let's scale the bar % by the number of cpus, so they can use the
full height of the row.
These tasks can't scale to multiple CPUs, so it's pointless to
leave vertical space for the other cores' capacity, if present.
For multi-threaded process rows, the vertical space continues to
accomodate all cores.
I've been on the fence about this change for a while because it
increases the cognitive load of reading the graphs, now the
scales are inconsistent. But when you've got 16 cores like on my
AMD P14s thinkpad, combined with a row height of 16 pixels, you
start wishing these rows used the full height of the row for
their single-core-constrained %ages.
|
|
Preparatory commit for enabling charts to apply % scaling to
non-threaded procesess, to make better use of the row's available
space.
A non-threaded process can't use more than a single core, so it
should be able to scale its %age out to the full row height. The
same will be applied to individual thread rows, as those can at
most use a single core.
The exception is a threaded process - its CPU %ages are
aggregate, and must represent up to the number of CPUs in the
system within their row.
|
|
Preparatory commit for enabling charts that scale per-thread and
per-non-threaded-process CPU utilization levels by number of
cpus, so they can utilize the whole row.
|
|
I planned to use the 256-colors for differentiating graphs in
other row types, but it's becoming clear saving space is more
important.
So this cuts the file size down further quite a bit:
-rw-r--r-- 1 vc vc 219323 Sep 19 01:37 09.19.24-01:36:43-2.png
Becomes:
-rw-r--r-- 1 vc vc 152674 Sep 21 14:25 09.21.24-14:25:16-2.png
|
|
This introduces a LUT indirection table for mapping the raw layer
values to a dense, deduplicated palette used with the PNG.
This should help with compression ratios at basically no cost.
Before `1800x8000 --headless --snapshot 10 --hertz 60`:
-rw-r--r-- 1 vc vc 87873 Sep 19 01:36 09.19.24-01:36:43-0.png
-rw-r--r-- 1 vc vc 215719 Sep 19 01:36 09.19.24-01:36:43-1.png
-rw-r--r-- 1 vc vc 219323 Sep 19 01:37 09.19.24-01:36:43-2.png
-rw-r--r-- 1 vc vc 221979 Sep 19 01:37 09.19.24-01:36:43-3.png
After:
-rw-r--r-- 1 vc vc 72303 Sep 19 01:37 09.19.24-01:37:30-0.png
-rw-r--r-- 1 vc vc 174100 Sep 19 01:37 09.19.24-01:37:30-1.png
-rw-r--r-- 1 vc vc 177430 Sep 19 01:37 09.19.24-01:37:30-2.png
-rw-r--r-- 1 vc vc 178711 Sep 19 01:38 09.19.24-01:37:30-3.png
Without any increase in compression level used. Which while it
would improve ratios further, substantially increases CPU cost.
|
|
This reverts commit 9f564cf8df6ef5fcba37082ba8013d6175955125.
Experimenting with smaller initial seq_file buffers in the kernel
has exposed this actually breaks, which contradicts my
expectations for proc files established back in the /proc/mdstat
racy incremental parsing corrupting the output days.
I'm seeing /proc/$pid/task/$pid/children spit out short reads
when the seq_file size is smaller than the amount of output.
Userspace's read() call can provide a large buffer, and if
seq_file's is smaller than the children output, it'll split the
children output instead of enlarging the seq_file buf to the
read() buffers bounds.
|
|
It'd be nice to allow the last partial row to be rendered, but
as-is it can result in segfault for some operations that aren't
clipping at that granularity.
Another option is to always round up the bits allocation to the
ROW_HEIGHT boundaries, then not worry about this, and do the
partial clip @ serialization to png time.
|
|
Increasing contrast a bit for odd rows / separators
|
|
This should have been changed when transitioning to nibbles and
the separators became generated @ present time when serializing
to png.
The first pass clears the shadow layer while assigning the first
offset part of the shadow. But it was staying within the
separators, which is now resulting in small bits of littered
shadow corruption in the separators barely visible in the PNGs.
Fix is trivial; initialize the separator bits when shadowing the
row as well.
|
|
Eventually this should get applied semi consistently to all
snapshots, but I'm most annoyed by its omission from the
--headless PNGs at the moment.
Also it arguably makes sense to always start with extending the
constrained mem-to-png case where we're working with a 256-color
palette, since the Xlib/XRender case has effectively no
constraints. Or just abandon any hope of preserving consistency
across the rendered output modes..
|
|
There's still assumptions that everything in the hierarchy fits
within the canvas... the Xlib stuff would clip all this behind
the scenes, but vcr/headless mode doesn't have such guard rails.
At some point I need to sit down and do a thorough pass in this
vein... Fortunately most my headless use cases have the canvas
configured appropriately.
|
|
When using vmon to monitor a system PID1 will kill it @
shutdown/reboot, and we should save one last snapshot of what's
been captured before we exit in that case.
SIGTERM is sent first before the SIGKILL killing spree, so let's
handle the SIGTERM by writing the snapshot, then exiting the main
loop.
The service manager can then do something with the produced
snapshots after we've exited, if they're considered interesting.
|
|
8 layers is no longer supported as a future expansion path...
|
|
These snuck in during the Xlib->vcr refactor which involved a lot
of copy-n-pasta taking Xlib sections from charts.c
|
|
This mostly works, but the maintenance of text shadows are a
gross naive conversion of the pre-nibbles code. It would
probably be better to add the shadows @ mem->png serialization
time and not bother maintaining them at all for headless.
It seems to work well enough to exercise and evaluate memory
footprints though...
The reason for "nibbles" is to save memory. Prior to this, the
mem backend would use a byte per pixel of layer information. By
not storing the background layer in this space, the current set
of layers used can fit in 4 bits (aka a nibble).
So this commit pivots to packing two pixels worth of layer data
into each of those bytes, effectively cutting the memory
requirements of the mem backend (headless mode) in half.
It matters for embedded use cases. The next step from here to
use substantially less memory in headless mode would require a
deeper refactor where we don't maintain a bitmap style
representation at all. It's doable, but not in the cards for my
free time right now.
|
|
--wip-name sets a constant name to use for the pre-rename temp
name of snapshots.
Otherwise a dynamic dot-filename augmented from the destination
name is used.
The impetus for this is to simplify garbage collection of
produced PNGs. We'll ignore dot-files to never step on the WIP
file during GC, but would like vmon to truncate and reuse the
same WIP name so it's not potentially accumulating the dot-files
in weird failure modes where the snapshots repeatedly fail to
complete and get renamed.
So in such a scenario we'll pass a dot-file for --wip-name and
vmon will keep reusing that name, never leaking more than the
single WIP file in even a persistent a failure mode.
|
|
cosmetic change; insert a space after the "#" in the string used
when comm/argv can't be sampled
|
|
Much of this stuff is pretty sloppy ever since it was first
written as a casual experiment. Fixup types to use
size_t/ssize_t where appropriate, and free the actual realloc'd
member of the char_array struct - the container struct with the
assumption that the member is at the struct start.
|
|
|
|
|
|
This switches to constructing the WIP png in a temporary dot-file
derived from the final name, then an atomic rename from the
dot-file to the final name. The temporary name is placed in the
same directory as the final one.
|
|
|
|
This upsets clang in particular, mechanical type substitution.
|
|
proc->stores is always allocated as part of vmon_proc_t, so this
can't possibly be NULL. IIRC an earlier form of libvmon
allocated the stores array lazily once needed.
|
|
There's no children processes expected for threads, and the
sampler assumes this is the case - but let's assert it holds
true.
|
|
Clarify the naming here so it's more obvious this only applies to
the single-pass mode (!VMON_FLAG_2PASS && !VMON_FLAG_PROC_ARRAY).
|
|
libvmon's internal api for samplers is extremely ad-hoc and
implicit.
This was done at the time to keep the source compact and have the
sampler ctor/dtor branches commingled immediately adjacent to
eachother... the thinking being this would help keep them in sync
as the code evolved. The ctor branches generally open fds and
allocate resources, with the dtor intended to undo those things.
With them kept more or less in the same page of code, it /should/
be obvious when one changes the other must as well.
In the long-term it probably makes sense to just explode this api
to something more formal and step back from those assumptions.
In lieu of doing such a refactor, let's improve the situation by
asserting the return codes at least stay within the expected
range. i.e. let's abort when a sample_changed/unchanged/error
return code comes from an dtor invocation, since this implies a
program error where someone isn't handling the implicit dtor
branches properly, instead falling through sampling paths.
|
|
Mechnical fix of longstanding typo I'm tired of ignoring...
|
|
Funny how long one can ignore something like this in their window
manager when X resources are in play, plus having 16G RAM helps.
|