Age | Commit message (Collapse) | Author |
|
Instead of assigning top-down vs. bottom-up semantics to the
layers behind vcr, let's use negative values to indicate
top-down.
This may change again in the future, but presently there's no
support for signed bar graphs within a given layer.
|
|
Not taking advantage of this yet, but may in the future as rendering
of mem (and maybe pgflts) evolves with the existing cpu bars...
|
|
The extra per-proc row showing RSS needs overlay text for at least showing
the numeric RSS KiB value, that's achieved via row-columns
This only adds and initalizes the columns, they're not being drawn anywhere
yet.
|
|
With how wide the charts can be, it's helpful to have the Row
enumeration visible at both sides, if you need to correlate
something you see at one edge with information at the opposite
one - look at the Row #.
|
|
This is necessary if we're going to actually rendering an RSS
value in overlay text.
|
|
Rather than hard-coding justification in draw_row_column() cases
by column type, the row-column instances should be able to
specify it own along with the side.
|
|
Particularly with designated struct initializers it's
particularly convenient to have the default value the zero value,
since you get that for free via silent omission.
Preparatory commit for row-columns specifying their
justification.
|
|
This is basically just an indirection table so there's somewhere
to represent row-column intersection state and instantiate
columns in muliple places from within the same row to across
different rows even differently located/justified horizontally,
while still being able to share the column's width for the
current draw/sample.
|
|
These are CPU-specific columns, so prefix them appropriately, in
preparation for memory columns accompnaying them in an additional
per-proc row.
|
|
This helps reading the precise magnitude of these numbers when large.
I considered also adding more units for the times, but I kinda
like the ability to scan the width of the time columns to see
short vs. long durations without actually reading what they
contain, as a broad-phase scan. If they were simply HH:MM:SS
it'd require scanning the colon-separated columns with enough
scrutiny to parse zeroes vs. non-zeroes...
|
|
I'd like to get thousands markers in some of the numbers produced
via snprintf in the charts, so call setlocale() with "" so it
gets set to whatever the environment has.
e.g.
LC_ALL=$LANG src/vmon
In Arch here gets my LC_ALL set to "en_US.UTF-8", which will put
commas in for thousands separators wherever the format modifier
"'" has been added.
|
|
If we're not showing the threads, the caption shouldn't mention
it.
|
|
This adds a [$n_current_threads] prefix to the argv/~threadname
part of the tree column, for non-stale processes.
It's suppressed for stale processes because we don't actually
have a meaningful count to render at that point; it'd always be
zero. This would be visible as an oddity in the snowflakes.
The count is also suppressed for non-threaded processes, leaving
a bare "[]", which may change again in the future. It seems like
noise in the chart, but it also serves to prevent an argv somehow
starting with "[N]" being ambiguous - perhaps not something worth
caring about *shrug*.
|
|
This introduces vmon_proc_t.n_current_threads, a counter
reflecting the currently non-stale number of threads in an
is_threaded process.
You could get this by walking the threads linked list and
filtering out the is_stale entries, but in preparation of showing
this count in the charts hierarchy I'm caching the incrementally
maintained count so the list doesn't need to be walked
repeatedly.
Note it's important to suppress the is_stale nodes from the
count, so the count isn't being decremented when stale nodes get
finally removed from the list - instead when nodes transition to
being stale. The count shown in charts should reflect the number
of thread rows seen at the same time (when --no-threads isn't in
use)
|
|
|
|
This is a first stab at supporting --no-threads, which is a
little awkward because of how threads must still be followed to
maintain an awareness of the potential children processes of
threads.
So in libvmon there's a flag now for neglecting monitoring of
threads, while still following them. This retains the same
libvmon topology as before, where threads were always monitored,
and threads still get their own vmon_proc_t instances in the
in-memory representation of the vmon_proc_t hierarchy.
What the libvmon flag changes is it prevents the vmon_proc_t
instances representing threads from allocating sampler states and
opening the various proc files used for sampling that information
from threads. So it reduces the number of proc files held open
when there are threaded processes monitored, and saves some
memory allocation for eliding storage for those samples.
For the charts rendering side, since libvmon's representation is
essentially unchanged with --no-threads, and actually breaks some
assumptions rendering previously made about proc_ctxt's always
being allocated for any vmon_proc_t in the tree because
these allocations are suppressed when neglecting threads, there
needs to be an awareness of --no-threads mode and a pile of
conditional goo to prevent rendering the threads both
statistically/informationally and hierarchically.
This commit adds that goo to the charts rendering while
simultaneously actually wiring up this flag to libvmon. On a
high level the primary facets of what this goo does are:
1. Suppress the effects of vmon_proc_t.is_thread nodes on the
rendered hierarchy, keeping these rows invisible, preventing
their impact on the row and depth variables, suppressing their
counting towards row counts in snowflaking of subtrees, and
suppressing their influence on the connectivity branches
normally drawn to link siblings separated by threaded
processes.
2. Bypass the usual ommission of rendering wchan and process
state on multithreaded processes. Normally we'd rely on the
main thread's rendering of these fields, but when the threads
aren't being shown, we'd like to still see at least a single
wchan and state for that main thread in the still shown
process' row. But this is barely useful, you really need to
see all the threads' wchans and states if you have any hope to
understand what multithreaded processes are doing.
I think this also highlights a shortcoming in that there's no
obvious indicator showing which processes are multithreaded
when --no-threads is in use. A subsequent commit will likely
add something like a [$threads_count] at the start of the
Argv/~ThreadName field.
|
|
Still no actual implementation yet
|
|
No actual implementation here, just flag propagation.
|
|
|
|
This will suppress showing threads in the output, and save on
much of the overhead associated with monitoring them.
Subsequent commits will augment libvmon to support this use case,
followed by charts changes to support a threads-hidden mode which
must still consider any of the threads children.
|
|
--hide-threads needs a way to tell libvmon to both follow threads
and neglect to actually sample them.
Note this will still allocate the vmon_proc_t for every thread,
but conserves in the open proc files department by not
opening/reading everything other than the children proc file for
threads - regardless of what other proc wants have been specified.
So front-ends still need to traverse threads of processes, and if
they want to collapse the children of threads as if they're all
children of the threads' parent, that's up to the front-end to do
so. In the vwm/vmon case, that's a detail for charts.c to
handle, when --hide-threads is in effect. It will have to render
the children of threads as if they're children of the threads'
parent, to hide this clusterfuck from what's visible to the user.
|
|
This is better than nothing, but the screens should be cycled in
MRU order like everything else. The way things are as-is with
the bare bones RandR integration, screens are just an array of
the underlying X type. There isn't really a vwm-native type
representing the screen, it's just an alias for the X type.
So there should be a refactor surrounding screens and a switch to
MRU order.
Anyhow, even though it's not ideal, I've been using this daily on
a multihead setup and it's a marked usability improvement.
|
|
|
|
This is an attempt to minimally support autoconfing windows to
different screens on multihead setups.
|
|
Vestigial from long ago when this all got hastily split up into separate headers
|
|
Now that threads can have children, the tree markup needs more
goo to cover those cases.
|
|
no functional difference
|
|
Long ago an assumption was made that only the main thread having
tid matching the pid would ever be the parent of children
processes.
This was an optimization done to avoid having to keep open the
/proc/$pid/task/$tid/children node for every thread being
monitored.
For the longest time this seemed to be fine, as most things
weren't forking from threaded programs, and if they were it
didn't seem to produce descendants from threads other than for
tid==pid.
But that's not the case anymore. Running `go test` on things
it's pretty apparent that go is cloning children from any old
thread and those children are under
/proc/$pid/tasks/$tid/children, and vmon is missing them from
monitoring as a result.
The bummer here is with large numbers of threads under
monitoring, there's an added fd for every one of those threads.
Each of those fds pins 4KiB in the kernel for the seq_file
buffer, it adds up.
Note this is only the libvmon side of things, there are other
assumptions in charts.c resulting in awkward rendering of this
new children-of-threads possibility. But other than some
weirdness in the visual details, it's surprisingly mostly correct
as-is.
|
|
There's potential for spending a whole lot of cycles filling a
huge time delta from the time things became paused to the current
time.
The output from that is pretty much pointless, so let's prevent
it from happening by simply bumping the sample time to the
current time whenever we're unpausing.
|
|
This shifts everything below IOWait/Idle% down one row.
|
|
Now when holding down XK_m during focus changing operations the
pointer will follow the focus, which should be handy on
multihead.
Also simply pressing Mod1+XK_m without doing anything else will
chase the currently focused window, so you can bring the pointer
where you are immediately on demand using the keyboard.
|
|
Particularly on large multi-head display setups it can be
annoying to have to find the mouse pointer after long periods of
not using it, on the rare occasion one must bring it to the
currently focused window to do a pointer operation.
This commit introduces XK_m for controlling a "chase_it" flag,
which future commits will utilize for augmenting focus-changing
operations, and maybe window configuring operations, by warping
the pointer to the center of the focused window /after/ the
augmented operation has been performed.
|
|
trivial fixup, no functional difference
|
|
These are just some potentially helpful warnings, they're not
treated as fatal... just informative regarding somewhat obviously
confused combinations.
|
|
If vmon ran a command as its child and was told to be the reaper,
we probably want to see any inherited orphans vmon becomes
responsible for reaping in the graph.
The simplest robust way to achieve this is to monitor vmon's PID
as the root instead of the pid of the command being executed.
There's an argument to be made that this is how it should always
be done when executing a command, but for now I'm only going to
do it when being the reaper. I think there's also an argument to
be made that becoming a subreaper should also be the default when
executing a command.
|
|
This adds minimal support for becoming a child subreaper.
Exited orphans are handled correctly by being identified and
ignored without triggering SIGCHLD snapshots nor exiting vmon.
A subsequent commit will make vmon monitor itself as the root pid
when reaper mode is active and vmon is parent of the command
being executed, making it possible to observe any orphans vmon
inherits as subreaper.
|
|
Beginnings of PR_SET_CHILD_SUBREAPER mode, this only adds the
CLI flags.
Becoming a subreaper is only relevant to running commands via
vmon. If the commands being executed fork/exec/daemonize or
otherwise may produce orphaned processes, they escape the
scoped hierarchical monitoring when init inherits them, so you
lose visibility into their actions once orphaned.
By becoming a subreaper, vmon can be the process inheriting those
orphans, so they may continue being monitored, as if vmon were
init, for its descendants.
|
|
This can be necessary for headless mode on cramped embedded
devices to prevent vmon from being delayed excessively due to
page faults/thrashing.
Even with Adherence visually indicated, it complicates
comparisons across snapshots to have this be
inconsistent/thrashing-severity-dependent.
Use this flag in combination with something like SCHED_RR to make
vmon more immune to memory and scheduling contention. If you use
SCHED_RR, it's wise to also use LimitRTTIME to prevent potential
bugs from bogarting the system.
|
|
The public callers of vmon_proc_monitor() shouldn't ever be
passing a non-NULL parent as that's a pretty intimate and messy
internal aspect of libvmon. So let's remove that altogether from
the public function for monitoring a process, and turn existing
one supporting parents into a libvmon-private function.
Trivial cleanup, there's so much more needed in libvmon since
it's the epitome of an organically evolved crusty thing.
|
|
Now that vmon is a real thing with PID1 monitoring, there's this
detail of orphans getting inherited which libvmon has so far
largely been able to ignore because vwm doesn't care about such
things, always monitoring subtrees attached to X windows.
This fixes the vmon asserts when monitoring the PID1 hierarchy
where vcr_shift_below_row_up_one() would abort @:
>·······assert(*(vcr->hierarchy_end_ptr) >= row);
It was being triggered when orphans were found by the PID1
children following while they were still children of their
exited-from-kernel's-perspective-but-not-yet-libvmon's-perspective
parent process.
There's more work to be done to improve this situation, but it's
likely going to be quite invasive. For now this is a simple
solution that should prevent the asserts. We just might not see
a process being orphaned for a sample while it gets ignored for
still having its vestigial parent around as is_stale=1.
|
|
This is useful for debugging purposes.
|
|
libvmon isn't really exposed to the front-end code beyond charts,
so it's this or a vwm_charts_t.vmon accessor and callers
including libvmon/vmon.h (yuck).
|
|
It's handy to see what the libvmon hash table state of the world
is when trying to understand brokenness, but also as a tool for
verifying things aren't out of sync with what the hierarchical
view contains.
|
|
This assert has proven interesting, but sticking it in the mem
backend limits its exercising to headless. I mostly run this on
Xlib in vwm/vmon, and it's proving annoying to trigger this
assert outside of embedded headless scenarios.
|
|
This is really how things are implemented today, which may
actually be incorrect in some edge case scenarios... but let's
assert it holds true currently to aid debugging some spurious
asserts in vcr_shift_below_row_up_one() about row vs.
hierarchy_end.
The potential issue I see with this assumption as-is is it's
entirely possible to have descendants survive a parent's demise,
grandchildren don't have to exit when a parent does. But it
might be OK to treat it that way, as they'll be rediscovered as
children of PID 1, and there's no strict need to preserve
continuity of their associated charts state across that
transition. It's rare enough that I don't think it's worth
worrying about, but maybe this is what's happening with the
asserts during startup specifically; when things are daemonizing
/ double forking etc.
|
|
The charts code in vwm/vmon assumes stale descendants of a stale
node, but there seems to be some theoretical potential for that
to not hold true.
Let's be more agressive about ensuring that's the case. The
current code already does this style propagation for stale
processes, but not for threads. It seems like it'd be weird to
have this happen, but maybe there's edge cases where you have a
parent process exit with grandchildren threads surviving until
a later sample, creating opportunity for a inconsistency.
|
|
An extra 0 snuck in here and got copy and pasted too, oof.
|
|
The current value of 128 doesn't really accomodate most the
systems I'm dealing with these days... bump to 1024.
|
|
The deferred pass only enters draw_chart() once regardless of
this_sample_duration, with the idx always 0.
So when this_sample_duration > 1 (stalls/repeated samples), the
conditional draw_overlay_row() would only get entered in the
non-deferred passes in deferred mode, which are short-circuited
within draw_overlay_row() because we don't want to do render that
stuff in those passes in deferred mode.
The fix is trivial; always enter draw_overlay_row() for the
deferred pass.
This fixes a cosmetic artifact where you'd see stale / missing
overlays in the hierarchy rows of output, when sample durations
were falling behind schedule enough for this_sample_duration to
be greater than 1.
|
|
This is a stupid simple naive implementation, but it does add
markers when enabled for mem->png (headless mode), e.g.:
`vmon --hertz 1 --markers 60 --headless --snapshots 3600`
Would give you minute markers in the borders of png snapshots
created every hour with 1hz samples (every column of pixels
represents a second, hence markers 60 gives you per-minute markers)
The current color used for the markers is not quite full
intensity yellow: {c0,c0,0}
|