Download raw body.
watch(1): add knob to display command's resource utilization
The watch(1) utility is a process instrument panel. Introduce a new 'r'
interactive command to display the last command execution's resource
utilisation, kinda like time(1) does. It refreshes as new information
becomes available.
OK?
Index: watch.1
===================================================================
RCS file: /cvs/src/usr.bin/watch/watch.1,v
diff -u -p -r1.13 watch.1
--- watch.1 24 May 2025 09:49:14 -0000 1.13
+++ watch.1 24 Jun 2025 10:47:04 -0000
@@ -96,6 +96,8 @@ Scroll up one line.
Scroll right half a screen.
.It Ic l
Highlight changed lines.
+.It Ic r
+Display information about resource utilization.
.It Ic s
Change the update interval.
.It Ic p
@@ -110,7 +112,8 @@ Quit
.El
.Sh SEE ALSO
.Xr sh 1 ,
-.Xr execl 3
+.Xr execl 3 ,
+.Xr getrusage 2
.Sh HISTORY
.Nm
was first published in 1991 and has been available since
Index: watch.c
===================================================================
RCS file: /cvs/src/usr.bin/watch/watch.c,v
diff -u -p -r1.30 watch.c
--- watch.c 24 Jun 2025 00:51:04 -0000 1.30
+++ watch.c 24 Jun 2025 10:47:04 -0000
@@ -1,5 +1,6 @@
/* $OpenBSD: watch.c,v 1.30 2025/06/24 00:51:04 job Exp $ */
/*
+ * Copyright (c) 2025 Job Snijders <job@openbsd.org>
* Copyright (c) 2000, 2001 Internet Initiative Japan Inc.
* All rights reserved.
*
@@ -20,6 +21,9 @@
#include <sys/types.h>
#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
#include <sys/wait.h>
#include <curses.h>
@@ -73,9 +77,12 @@ int start_line = 0, start_column = 0; /*
int pause_on_error = 0;
int paused = 0;
int want_update;
+int show_rusage = 0;
+struct rusage prev_ru, ru;
int last_exitcode = 0;
time_t lastupdate;
int xflag = 0;
+struct timespec prev_start, start, prev_stop, stop;
#define addwch(_x) addnwstr(&(_x), 1);
#define WCWIDTH(_x) ((wcwidth((_x)) > 0)? wcwidth((_x)) : 1)
@@ -105,6 +112,7 @@ struct event ev_timer;
int display(BUFFER *, BUFFER *, highlight_mode_t);
kbd_result_t kbd_command(int);
void show_help(void);
+void print_rusage(void);
void untabify(wchar_t *, int);
void on_signal(int, short, void *);
void on_sigchild(int, short, void *);
@@ -286,6 +294,11 @@ display(BUFFER * cur, BUFFER * prev, hig
move(1, 1);
+ if (show_rusage) {
+ print_rusage();
+ return 1;
+ }
+
if (!prev || (cur == prev))
hm = HIGHLIGHT_NONE;
@@ -407,6 +420,10 @@ start_child()
if (pipe(fds) == -1)
err(1, "pipe()");
+ (void)memset(&ru, 0, sizeof(struct rusage));
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+
child->pid = vfork();
if (child->pid == -1)
err(1, "vfork");
@@ -469,13 +486,18 @@ on_sigchild(int sig, short event, void *
int st;
do {
- pid = waitpid(WAIT_ANY, &st, 0);
+ pid = wait4(WAIT_ANY, &st, 0, &ru);
} while (pid == -1 && errno == EINTR);
if (!running_child || running_child->pid != pid)
return;
/* Remember update time */
time(&lastupdate);
+ clock_gettime(CLOCK_MONOTONIC, &stop);
+ prev_start = start;
+ prev_stop = stop;
+
+ prev_ru = ru;
if (WIFEXITED(st))
last_exitcode = WEXITSTATUS(st);
@@ -529,6 +551,11 @@ kbd_command(int ch)
{
char buf[10];
+ if (show_rusage) {
+ show_rusage = 0;
+ return (RSLT_REDRAW);
+ }
+
switch (ch) {
case '?':
@@ -630,6 +657,10 @@ kbd_command(int ch)
return (RSLT_REDRAW);
}
+ case 'r':
+ show_rusage = 1;
+ return (RSLT_REDRAW);
+
case 's':
move(1, 0);
@@ -698,6 +729,7 @@ show_help(void)
"l - highlight changed lines\n"
"w - highlight changed words\n"
"p - toggle pause / resume\n"
+ "r - show information about resource utilization\n"
"s - change the update interval\n"
"h | ? - show this message\n"
"q - quit\n\n");
@@ -743,6 +775,60 @@ untabify(wchar_t *buf, int maxlen)
}
}
*p = L'\0';
+}
+
+void
+print_rusage(void)
+{
+ int hz;
+ long ticks;
+ int mib[2];
+ struct clockinfo clkinfo;
+ struct timespec elapsed;
+ size_t size;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_CLOCKRATE;
+ size = sizeof(clkinfo);
+ if (sysctl(mib, 2, &clkinfo, &size, NULL, 0) < 0)
+ err(1, "sysctl");
+ hz = clkinfo.hz;
+ ticks = hz * (prev_ru.ru_utime.tv_sec + prev_ru.ru_stime.tv_sec) +
+ hz * (prev_ru.ru_utime.tv_usec + prev_ru.ru_stime.tv_usec)
+ / 1000000;
+
+ timespecsub(&prev_stop, &prev_start, &elapsed);
+
+ printw("\n%7lld.%02ld %s\n", (long long)elapsed.tv_sec,
+ elapsed.tv_nsec / 10000000, "real");
+ printw("%7lld.%02ld %s\n", (long long)prev_ru.ru_utime.tv_sec,
+ prev_ru.ru_utime.tv_usec / 10000, "user");
+ printw("%7lld.%02ld %s\n", (long long)prev_ru.ru_stime.tv_sec,
+ prev_ru.ru_stime.tv_usec / 10000, "sys");
+
+ printw("%10ld %s\n", prev_ru.ru_maxrss, "maximum resident set size");
+ printw("%10ld %s\n", ticks ? prev_ru.ru_ixrss / ticks : 0,
+ "average shared memory size");
+ printw("%10ld %s\n", ticks ? prev_ru.ru_idrss / ticks : 0,
+ "average unshared data size");
+ printw("%10ld %s\n", ticks ? prev_ru.ru_isrss / ticks : 0,
+ "average unshared stack size");
+ printw("%10ld %s\n", prev_ru.ru_minflt, "minor page faults");
+ printw("%10ld %s\n", prev_ru.ru_majflt, "major page faults");
+ printw("%10ld %s\n", prev_ru.ru_nswap, "swaps");
+ printw("%10ld %s\n", prev_ru.ru_inblock, "block input operations");
+ printw("%10ld %s\n", prev_ru.ru_oublock, "block output operations");
+ printw("%10ld %s\n", prev_ru.ru_msgsnd, "messages sent");
+ printw("%10ld %s\n", prev_ru.ru_msgrcv, "messages received");
+ printw("%10ld %s\n", prev_ru.ru_nsignals, "signals received");
+ printw("%10ld %s\n", prev_ru.ru_nvcsw, "voluntary context switches");
+ printw("%10ld %s\n", prev_ru.ru_nivcsw,
+ "involuntary context switches");
+
+ standout();
+ printw("\nHit any key to continue.");
+ standend();
+ refresh();
}
void
watch(1): add knob to display command's resource utilization