From: Stuart Henderson Subject: Re: watch(1): add knob to display command's resource utilization To: Job Snijders Cc: tech@openbsd.org Date: Tue, 24 Jun 2025 14:11:05 +0100 does this really make sense for watch(1), why not just run time? iwatch '\time -l md5 -t 2>&1' On 2025/06/24 10:55, Job Snijders wrote: > 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 trailing whitespace btw. > .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 > * Copyright (c) 2000, 2001 Internet Initiative Japan Inc. > * All rights reserved. > * > @@ -20,6 +21,9 @@ > > #include > #include > +#include > +#include > +#include > #include > > #include > @@ -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 >