From 711385c9d081cd35b6160cbfa5bba58b3f9f7d93 Mon Sep 17 00:00:00 2001 From: "Simon L. B. Nielsen" Date: Sat, 20 May 2006 19:17:47 +0000 Subject: [PATCH] - Add support for filtering the the list of providers by a regular expression, which makes it possible to only see interesting providers. "f" is used inside gstat to set a filter, "F" is used to remove current filter. - Do not print some uninteresting values in the gstat title line. - Do not print past the end of the screen. - Read multiple keystrokes per "wait" when gstat is running. - Remove a redundant != check, right after check of NULL against the same variable ("gid"). - Use sysexits.h. - Do not link against libkvm and libsbuf, they are not actually used. - Fix a few style(9) issues where I had to touch nearby code anyway. Approved by: cperciva (mentor) MFC after: 2 weeks --- usr.sbin/gstat/Makefile | 4 +- usr.sbin/gstat/gstat.8 | 11 ++- usr.sbin/gstat/gstat.c | 185 +++++++++++++++++++++++++++++++--------- 3 files changed, 159 insertions(+), 41 deletions(-) diff --git a/usr.sbin/gstat/Makefile b/usr.sbin/gstat/Makefile index 843264a142ed..14c12fa42cb3 100644 --- a/usr.sbin/gstat/Makefile +++ b/usr.sbin/gstat/Makefile @@ -3,7 +3,7 @@ PROG= gstat MAN= gstat.8 WARNS?= 5 -DPADD= ${LIBGEOM} ${LIBDEVSTAT} ${LIBKVM} ${LIBBSDXML} ${LIBCURSES} ${LIBSBUF} -LDADD= -lgeom -ldevstat -lkvm -lbsdxml -lcurses -lsbuf +DPADD= ${LIBGEOM} ${LIBDEVSTAT} ${LIBBSDXML} ${LIBCURSES} ${LIBEDIT} +LDADD= -lgeom -ldevstat -lbsdxml -lcurses -ledit .include diff --git a/usr.sbin/gstat/gstat.8 b/usr.sbin/gstat/gstat.8 index 2dce5c317283..08a92fbc1c71 100644 --- a/usr.sbin/gstat/gstat.8 +++ b/usr.sbin/gstat/gstat.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 3, 2003 +.Dd May 20, 2006 .Dt GSTAT 8 .Os .Sh NAME @@ -33,6 +33,7 @@ .Sh SYNOPSIS .Nm .Op Fl acd +.Op Fl f Ar filter .Op Fl I Ar interval .Sh DESCRIPTION The @@ -56,6 +57,14 @@ producers. Enable display of statistics for delete .Pq Dv BIO_DELETE operations. +.It Fl f Ar filter +A regular expression that can be used to only show statistics for some +devices. +Only devices which name match +.Ar filter +will be displayed. +The format of the regular expression is described in +.Xr re_format 7 . .It Fl I Ar interval Refresh the .Nm diff --git a/usr.sbin/gstat/gstat.c b/usr.sbin/gstat/gstat.c index f4c7e119ab4b..87d638106d54 100644 --- a/usr.sbin/gstat/gstat.c +++ b/usr.sbin/gstat/gstat.c @@ -30,32 +30,44 @@ */ -#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include #include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include static int flag_a, flag_c, flag_d; static int flag_I = 500000; static void usage(void); +static const char* +el_prompt(void) +{ + + return ("Filter: "); +} + int main(int argc, char **argv) { int error, i, quit; + int curx, cury, maxx, maxy, line_len, max_flen; struct devstat *gsp, *gsq; void *sp, *sq; double dt; @@ -64,12 +76,19 @@ main(int argc, char **argv) struct gprovider *pp; struct gconsumer *cp; struct gident *gid; + regex_t f_re, tmp_f_re; short cf, cb; char *p; + char f_s[100], pf_s[100], tmp_f_s[100]; + const char *line; long double ld[11]; uint64_t u64; + EditLine *el; + History *hist; + HistEvent hist_ev; - while ((i = getopt(argc, argv, "adcI:")) != -1) { + f_s[0] = '\0'; + while ((i = getopt(argc, argv, "adcf:I:")) != -1) { switch (i) { case 'a': flag_a = 1; @@ -80,6 +99,14 @@ main(int argc, char **argv) case 'd': flag_d = 1; break; + case 'f': + if (strlen(optarg) > sizeof(f_s) - 1) + errx(EX_USAGE, "Filter string too long"); + if (regcomp(&f_re, optarg, REG_EXTENDED) != 0) + errx(EX_USAGE, + "Invalid filter - see re_format(7)"); + strncpy(f_s, optarg, sizeof(f_s)); + break; case 'I': p = NULL; i = strtoul(optarg, &p, 0); @@ -114,6 +141,7 @@ main(int argc, char **argv) sq = geom_stats_snapshot_get(); if (sq == NULL) err(1, "geom_stats_snapshot()"); + /* Setup curses */ initscr(); start_color(); use_default_colors(); @@ -127,6 +155,20 @@ main(int argc, char **argv) nodelay(stdscr, 1); intrflush(stdscr, FALSE); keypad(stdscr, TRUE); + /* Setup libedit */ + hist = history_init(); + if (hist == NULL) + err(EX_SOFTWARE, "history_init()"); + history(hist, &hist_ev, H_SETSIZE, 100); + el = el_init("gstat", stdin, stdout, stderr); + if (el == NULL) + err(EX_SOFTWARE, "el_init"); + el_set(el, EL_EDITOR, "emacs"); + el_set(el, EL_SIGNAL, 1); + el_set(el, EL_HIST, history, hist); + el_set(el, EL_PROMPT, el_prompt); + if (f_s[0] != '\0') + history(hist, &hist_ev, H_ENTER, f_s); geom_stats_snapshot_timestamp(sq, &tq); for (quit = 0; !quit;) { sp = geom_stats_snapshot_get(); @@ -140,8 +182,26 @@ main(int argc, char **argv) geom_stats_snapshot_reset(sp); geom_stats_snapshot_reset(sq); move(0,0); - printw("dT: %5.3f flag_I %dus sizeof %d i %d\n", - dt, flag_I, sizeof(*gsp), i); + printw("dT: %5.3fs w: %.3fs", + dt, (float)flag_I / 1000000); + if (f_s[0] != '\0') { + printw(" filter: "); + getyx(stdscr, cury, curx); + getmaxyx(stdscr, maxy, maxx); + strncpy(pf_s, f_s, sizeof(pf_s)); + max_flen = maxx - curx - 1; + if ((int)strlen(f_s) > max_flen && max_flen >= 0) { + if (max_flen > 3) + pf_s[max_flen - 3] = '.'; + if (max_flen > 2) + pf_s[max_flen - 2] = '.'; + if (max_flen > 1) + pf_s[max_flen - 1] = '.'; + pf_s[max_flen] = '\0'; + } + printw("%s", pf_s); + } + printw("\n"); printw(" L(q) ops/s "); printw(" r/s kBps ms/r "); printw(" w/s kBps ms/w "); @@ -165,9 +225,19 @@ main(int argc, char **argv) } if (gid == NULL) continue; - if (gid != NULL && gid->lg_what == ISCONSUMER && - !flag_c) + if (gid->lg_what == ISCONSUMER && !flag_c) continue; + /* Do not print past end of window */ + getyx(stdscr, cury, curx); + if (curx > 0) + continue; + if ((gid->lg_what == ISPROVIDER + || gid->lg_what == ISCONSUMER) && f_s[0] != '\0') { + pp = gid->lg_ptr; + if ((regexec(&f_re, pp->lg_name, 0, NULL, 0) + != 0)) + continue; + } if (gsp->sequence0 != gsp->sequence1) { printw("*\n"); continue; @@ -237,38 +307,77 @@ main(int argc, char **argv) *gsq = *gsp; } geom_stats_snapshot_free(sp); + getyx(stdscr, cury, curx); + getmaxyx(stdscr, maxy, maxx); clrtobot(); + if (maxy - 1 <= cury) + move(maxy - 1, 0); refresh(); usleep(flag_I); - i = getch(); - switch (i) { - case '>': - flag_I *= 2; - break; - case '<': - flag_I /= 2; - if (flag_I < 1000) - flag_I = 1000; - break; - case 'c': - flag_c = !flag_c; - break; - case 'q': - quit = 1; - break; - default: - break; + while((i = getch()) != ERR) { + switch (i) { + case '>': + flag_I *= 2; + break; + case '<': + flag_I /= 2; + if (flag_I < 1000) + flag_I = 1000; + break; + case 'c': + flag_c = !flag_c; + break; + case 'f': + move(0,0); + clrtoeol(); + refresh(); + line = el_gets(el, &line_len); + if (line == NULL) + err(1, "el_gets"); + if (line_len > 1) + history(hist, &hist_ev, H_ENTER, line); + strncpy(tmp_f_s, line, sizeof(f_s)); + if ((p = strchr(tmp_f_s, '\n')) != NULL) + *p = '\0'; + /* + * We have to clear since we messed up + * curses idea of the screen by using + * libedit. + */ + clear(); + refresh(); + if (regcomp(&tmp_f_re, tmp_f_s, REG_EXTENDED) + != 0) { + move(0, 0); + printw("Invalid filter"); + refresh(); + sleep(1); + } else { + strncpy(f_s, tmp_f_s, sizeof(f_s)); + f_re = tmp_f_re; + } + break; + case 'F': + f_s[0] = '\0'; + break; + case 'q': + quit = 1; + break; + default: + break; + } } } endwin(); - exit (0); + el_end(el); + exit(EX_OK); } static void usage(void) { - fprintf(stderr, "usage: gstat [-acd] [-I interval]\n"); - exit(1); + fprintf(stderr, "usage: gstat [-acd] [-f filter] [-I interval]\n"); + exit(EX_USAGE); /* NOTREACHED */ }