1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
|
\/\/\
Built-ins:
Mod1-RClick Focus the clicked window, but suppress raising
Mod1-RClick-drag Focus the clicked window, suppress raising, resizing
the window from its nearest corner until drag
completes
Mod1-LClick Focus and raise the clicked window
Mod1-LClick-drag Focus and raise the clicked window, moving the window
until the drag completes
* Mod1-l Switch to virtual desktop to the right (if exists)
* Mod1-h Switch to virtual desktop to the left (if exists)
Mod1-j Lower focused window, if the focused window is in
"allscreen" mode it will simply be fullscreened first
without lowering
Mod1-k [-k [-k] Raise focused window [a second k raises and
[-k] [-k]] fullscreens the window [a third k raises and
"allscreens" without a visible border [a fourth k
raises and fullscreens across all heads [a fifth k
raises and "allscreens" across all heads]]]
Mod1-Shift-k Shelve focused window and switch to the shelf context
Mod1-Shift-j Migrate the focused window from the shelf to the last
focused virtual desktop, switch to that virtual
desktop, and focus the migrated window
* Mod1-Shift-l Migrate the focused window to the virtual desktop
to the right (if exists), keeping the window focused
* Mod1-Shift-h Migrate the focused window to the virtual desktop
to the left (if exists), keeping the window focused
Mod1-v Create a new virtual desktop and switch to it
Mod1-Shift-v Create a new virtual desktop, move the focused window
to it, and switch to it
* Mod1-Space Switch to the most recently used virtual desktop
(like Mod1-Tab but for virtual desktops)
* Mod1-Shift-Space Switch to the most recently used virtual desktop,
bringing the focused window with
Mod1-` Alternate between shelf (if populated) and virtual
desktop contexts
Mod1-s Shelve the focused window without switching to the
shelf, adopting the newly shelved window as the
focused window within the shelf
* Mod1-Tab Focus and raise the next window in the current
context (shelf or virtual desktop), the focused
window is not 'committed' as the MRU window until
Mod1 is released, so you may peruse intermediate
windows without affecting the order until releasing
Mod1. In multihead configurations the next window
selection is confined to the current screen.
Mod1-Shift-Tab Identical to Mod1-Tab except switches to the MRU
window on another screen in a multihead configuration
Mod1-d Request the client destroy the focused window, or
destroy the current virtual desktop when no windows
exist on it
Mod1-Shift-d XKillClient the focused window (useful for
misbehaving clients)
Mod1-Enter Alternate between full-screen and windowed dimensions
for the focused window
Mod1-[ [-[] Reconfigure the focused window to fill the left half
of the screen [ left bottom quarter of screen ]
Mod1-] [-]] Reconfigure the focused window to fill the right half
of the screen [ right top quarter of screen ]
Mod1-Shift-[ [-[] Reconfigure the focused window to fill the top half
of the screen [ top left quarter of screen ]
Mod1-Shift-] [-]] Reconfigure the focused window to fill the bottom
half of the screen [ bottom right quarter of screen ]
Mod1-Semicolon Toggle monitoring overlays (when active vwm becomes a
compositing manager, which is slower)
Mod1-Apostrophe Discard the "snowflakes" region of the focused
window's monitoring overlay
Mod1-Right Increase monitoring frequency (when overlays are
active, too high a frequency can overload X)
Mod1-Left Decrease monitoring frequency, the lowest setting
halts monitoring)
Mod1-Esc-Esc-Esc Exit vwm (if vwm is the child of your X server, X
exits too, so your X clients all lose their
connection and die. However, your clients are
running under screen, and if your X server didn't
exit, they won't lose their X connection.)
*'s above indicate commands which initiate an MRU-update to be committed
on the next Mod1 release. One may traverse windows and desktops
without affecting their MRU order by returning to the original
initiating window and/or desktop before releasing Mod1. This permits
one to do quite a lot of things under a single, long-duration Mod1
press only committing to a potentially different focused
window/desktop at the very end.
Think of the Mod1 release as a transaction commit when coupled with
the *'d commands.
If a simultaneous second Mod1 is pressed at any point during a *'d
command, the window (and its desktop) focused when the *'d command
began will immediately be refocused - but not raised. This is
intentional to simplify the arranging of obscured focused windows. If
you find yourself restored to a desktop full of windows where your
focused window is totally obscured/invisible, simply press Mod1-k to
raise it if desired.
At any point during a *'d operation one may (re)press a second Mod1
to return to the origin, it is not limited to a single use.
Default launchers (configure by editing launchers.def and rebuild):
Mod1-x xterm
Mod1-b iceweasel
Mod1-g gimp
Mod1-. xlock
Mod1-- xset -dpms s off
Mod1-= xset +dpms s on
General:
Newly created windows are raised but not focused unless they are the first
window on an otherwise empty virtual desktop, then they are focused as well.
When new windows appear on a populated virtual desktop, they are inserted
immediately after the currently focused window in the windows list, so a
Mod1-Tab will immediately focus new windows. Windows are kept in a MRU (Most
Recently Used) order, keeping it efficient to alternate between an evolving
set of active windows.
The shelf is a sort of omnipresent and limited virtual desktop always
available via Mod1-`, it only shows a single window at a time, Mod1-Tab
cycles through the shelved windows. I use it as a place to stow xterms
running backround processes I would like to retain the ability to observe the
output of or interact with occasionally. Programs like transmission-gtk,
cmus, wpa_supplicant under xterm, sometimes even iceweasel sessions find
themselves in my shelf on a regular basis.
Multihead/Xinerama:
In multihead configurations new windows are placed on the screen containing
the pointer if that screen is empty. Should the pointer be on a non-empty
screen, then new windows are placed on the screen containing the currently
focused window.
New windows will automatically be focused if the screen they were placed on
is empty, even if their virtual desktop is not, which is a divergence from
the single-headed behavior where only lone windows on virtual desktops are
automatically focused.
Composite/Monitoring:
One reason vwm was created was to provide a simplified platform for the
research and development of a window manager with integrated omnipresent
first-class local process monitoring. Early attempts were made to modify an
existing window manager (WindowMaker) which produced unsatisfactory though
inspiring results. The window managers vwm[12] were created shortly after to
flesh out the interaction model and solidify an perfectly usable and easily
modified window manager foundation, while libvmon was created in parallel to
facilitate the efficient process monitoring required for such a task.
After a number of iterations it was found that the Composite extension (along
with the accompanying Damage and Render extensions) would give the best
results on a modern Xorg linux system. Compositing hurts the rendering
performance of X applications significantly however, so a hybrid model has
been employed.
Monitoring overlays visibility is toggled using Mod1-Semicolon, the sample
rate is increased using Mod1-Right, and decreased using Mod1-Left.
When the monitoring is not visible, vwm3 continues to leave X in immediate
rendering mode with no additional overhead in the rendering pipeline, just
like vwm2. The only additional overhead is the cost of regularly sampling
process statistics and maintaining the state of window overlays (which does
involve some X rendering of graphs and text, but does not introduce overhead
to the drawing of client windows).
When monitoring overlays are made visible vwm3 temporarily becomes a
compositing manager, redirecting the rendering of all windows to offscreen
memory and assuming the responsibility of drawing all damaged contents to the
root window on their behalf. This is what gives vwm3 the opportunity to draw
alpha-blended contextual monitoring data over all of the windows, but it does
come with a cost.
Most modern GNU/Linux desktop environments are full-time composited, meaning
all X clients are redirected at all times. This makes their draws more
costly and latent due to all the additional copies being performed.
Depending on how things have been implemented, in the interests of supporting
things like transparent windows it also generally results in overlapping
window regions being drawn repeatedly for every overlapping window from the
bottom-up rather than just the top one.
In vwm3 transparent windows are not supported, and shape windows (xeyes) are
made rectangular in composited mode. This is so overlapping regions are only
drawn once for the top windows having damage per burst of screen updates.
Immediate rendering mode is restored upon disabling the monitoring overlays,
restoring the drawing performance to vwm[12] levels where vwm3 is completely
out of the drawing loop.
Here are some relevant things worth noting:
- The monitoring is only heirarchical if your kernel is configured with
CONFIG_CHECKPOINT_RESTORE, which seems to be common nowadays. This is
required for the /proc/$pid/task/$tid/children files, which is what
libvmon uses to efficiently scope monitoring to just the descendants of
the explicitly monitored client precesses.
- tmux orphans its backend process immediately at startup, discarding its
parent->child relationship, so you don't get any monitoring of the commands
running in your local tmux session. Use GNU screen instead.
- GNU screen orphans its backend on detach, so on reattach you've lost the
parent->child relationship and find yourself in the same situation tmux
puts you in immediately. I've developed an adopt() system call patch for
the linux kernel to enable adopting orphans in this situation, but it
hasn't been accepted. With this patch and a one line change to GNU screen
the parent->child relationship is restored on reattach.
You may find patches for adding the adopt() system call to Linux and its
integration into GNU screen in the patches/ subdirectory.
- The top row of the overlays shows:
Total CPU Idle % (cyan):
The height of every cyan vertical line reflects the %age of ticks since
the previous sample which were spent in the idle task.
Total CPU IOWait % (red):
The height of every red vertical line reflects the %age of ticks since
the previous sample which were lost to IO wait. Many people don't
understand this correctly. This reflects opportunities to execute
something other than the idle task which were lost because _all_
runnable tasks at the time were blocked in IO.
An absence of IOWait does not mean nothing is blocked on IO. It just
means there weren't opportunities to execute something which were lost due
to waiting on IO.
For example, lets say you have a dual core machine, and you launch two
"yes > /dev/null &" commands. These two yes commands are essentially busy
loops writing "yes" to /dev/null, they will always be runnable, and you
will see a top row in the overlay devoid of any cyan _or_red_ while they
execute.
While they execute run something like:
"sudo echo 2 > /proc/sys/vm/drop_caches && du /"
Still no IOWait in the top row. We know that du is blocking on IO, the
caches are empty, but because there is always something runnable on the
two cores thanks to the two yes commands, we'll never see IOWait. The
other runnable processes mask the IOWait from our visibility.
Now kill the two yes commands and rerun the du command, watch the top
row. Some red should appear, the red indicates that there was CPU time
available for running something, and the _only_ things available for that
time was blocked in IO. Had there something else runnable, we wouldn't
see the time lost to IOWait.
When you see IOWait time, it's just saying nothing executed for that
time, not for lack of any runnable tasks, just that all runnable tasks
were blocked. It's still of value, but easily obscured on a system with
any cpu-bound tasks constantly running.
- The per-task (processes or threads) rows of the overlays show:
User CPU % (cyan):
The height of every cyan vertical line reflects the %age of ticks since
the previous sample which were spent executing this task in the user
context.
System CPU % (red):
The height of every red vertical line reflects the %age of ticks since
the previous sample which were spent executing this task in kernel/system
context.
Task monitoring beginning and ending is indicated with solid and checkered
vertical bars, respectively. These generally coincide with the task clone
and exit, but not always, especially the cloning.
- You can pause sampling by lowering its rate (Mod1-Left) to 0Hz. Just be
aware that this also pauses the updating of the overlay contents, so window
resizes won't be adapted to in the overlay until increasing the sample rate
(Mod1-Right). Pausing is useful if you've seen something interesting and
would like to screenshot, study, or discuss. BTW, to take a screenshot
when composited you have to capture the root window. If you capture the
client window, you won't get the overlays, you'll just get the redirected
window contents. Compositing mode composites everything into the root
window, when you're interacting with the composited vwm3, you're looking at
the root window the entire time.
- The sample rate will automatically be lowered by vwm3 when it detects that
it's having trouble maintaining the current one. If you have many windows
or have a slow or heavily loaded processor/GPU they can become bottlenecks,
especially at higher sample rates. Rather than continuing to bog down your
X server (Xorg is not good at fairly scheduling clients under GPU
contention), vwm3 will simply back off the sample rate as if you had hit
Mod1-Left, to try ameliorate rather than exacerbate the situation.
- The monitoring is implemented using sampling, not tracing. Below the
current process heirarchy for every window there is an exited tasks
snowflakes section filling the remaining space. Do not mistake this for
something lossless like bash history or strace output, it's lossy since
it's produced from sampled data. In part to try avoid interpretation of
these as a reliable process history I refer to them as snowflakes in the
code, since they fall downwards and sideways.
With sufficiently high sample rates the output starts to take on the
appearance of tracing, and while it may happen to capture every process in
slower executions, most automata will execute entire commands in the time
between samples. So try keep this in mind before thinking something's
broken because you don't see something you expected in the snowflakes.
Some artifacts you might notice due to this which are not bugs are:
- "#missed it!" being shown as the command name, this happens when
libvmon caught the process but the process exited before libvmon caught
a sample of the name.
- A parent's command name in the child when a different command was
executed. In UNIX systems processes fork before execing the new
command, in that window of time between the fork and exec, the child
process is a clone of the parent, command and argv included. Sometimes
the sample catches at just the right moment to see this in action.
- Varying outputs in seeming identical actions. Things like simply
launching xterm may produce no snowflakes at all in the new xterm, or a
few like "bash" "dircolors -b" and "utempter add :0", especially if you
have the sample rate turned up and cause some load on the system to slow
the xterm and interactive bash startup scripts down.
- In the interests of being efficient, nothing is being logged historically.
The snowflakes area is all you get, which is limited to the free pixel
space below the instantaneous process heirarchy within the window.
Everything which falls off the edges of the screen is lost forever, with
the exception of windows which have been made smaller than they were.
You cannot scroll down or to the right to see older snowflakes or graphs.
You cannot search the snowflakes.
The native text and numeric representations of the sampled data is not kept
any longer than the current sample, just long enough to update the
overlays. From that point on the information exists only as visualized
pixels in the overlay layers with no additional indexing or relationships
being maintained with the currently monitored state.
- You can wipe the snowflakes of the focused window with Mod1-Apostrophe
- The client PID is found via the _NET_WM_PID X property. This must be set
by the client, and not all clients cooperate (xpdf is one I've noticed).
This is annoying especially considering the vast majority of X clients run
on modern systems are local clients connected via UNIX domain sockets.
These sockets support ancillary messages including SCM_CREDENTIALS, which
contains the pid of the connected process. Some investigation into the
Xorg sources found it already queries this information and has it on hand,
but doesn't bother setting the _NET_WM_PID property even though it's well-
positioned to do so.
I've developed and submitted upstream a patch for Xorg which sets
_NET_WM_PID on local connections, it complements vwm3 nicely.
You can find the patch in the patches directory.
- There are around 5 files kept open in /proc for every task monitored by
vwm. This applies to children processes and threads alike, so on a busy
system it's not unrealistic to exceed 1024, a common default open files
ulimit for GNU/Linux distributions. You can generally change this limit
for your user via configuration in /etc/security/limits.conf or
/etc/security/limits.d/.
TODO finish and polish this readme...
|