static void devstats(void) { int dn, state; long double transfers_per_second; long double busy_seconds; long tmp; for (state = 0; state < CPUSTATES; ++state) { tmp = cur.cp_time[state]; cur.cp_time[state] -= last.cp_time[state]; last.cp_time[state] = tmp; } busy_seconds = cur.snap_time - last.snap_time; for (dn = 0; dn < num_devices; dn++) { int di; if ((dev_select[dn].selected == 0) || (dev_select[dn].selected > maxshowdevs)) continue; di = dev_select[dn].position; if (devstat_compute_statistics(&cur.dinfo->devices[di], &last.dinfo->devices[di], busy_seconds, DSM_TRANSFERS_PER_SECOND, &transfers_per_second, DSM_NONE) != 0) errx(1, "%s", devstat_errbuf); (void)printf("%3.0Lf ", transfers_per_second); } }
static void dinfo(int dn, int lc, struct statinfo *now, struct statinfo *then) { long double transfers_per_second; long double kb_per_transfer, mb_per_second; long double elapsed_time, device_busy; int di; di = dev_select[dn].position; if (then != NULL) { /* Calculate relative to previous sample */ elapsed_time = now->snap_time - then->snap_time; } else { /* Calculate relative to device creation */ elapsed_time = now->snap_time - devstat_compute_etime( &now->dinfo->devices[di].creation_time, NULL); } if (devstat_compute_statistics(&now->dinfo->devices[di], then ? &then->dinfo->devices[di] : NULL, elapsed_time, DSM_KB_PER_TRANSFER, &kb_per_transfer, DSM_TRANSFERS_PER_SECOND, &transfers_per_second, DSM_MB_PER_SECOND, &mb_per_second, DSM_BUSY_PCT, &device_busy, DSM_NONE) != 0) errx(1, "%s", devstat_errbuf); lc = DISKCOL + lc * 6; putlongdouble(kb_per_transfer, DISKROW + 1, lc, 5, 2, 0); putlongdouble(transfers_per_second, DISKROW + 2, lc, 5, 0, 0); putlongdouble(mb_per_second, DISKROW + 3, lc, 5, 2, 0); putlongdouble(device_busy, DISKROW + 4, lc, 5, 0, 0); }
static int devstats(int row, int _col, int dn) { long double transfers_per_second; long double kb_per_transfer, mb_per_second; long double busy_seconds; int di; di = dev_select[dn].position; busy_seconds = cur.snap_time - last.snap_time; if (devstat_compute_statistics(&cur.dinfo->devices[di], &last.dinfo->devices[di], busy_seconds, DSM_KB_PER_TRANSFER, &kb_per_transfer, DSM_TRANSFERS_PER_SECOND, &transfers_per_second, DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0) errx(1, "%s", devstat_errbuf); if (numbers) { mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ", kb_per_transfer, transfers_per_second, mb_per_second); return(row); } wmove(wnd, row++, _col); histogram(mb_per_second, 50, .5); wmove(wnd, row++, _col); histogram(transfers_per_second, 50, .5); if (kbpt) { wmove(wnd, row++, _col); histogram(kb_per_transfer, 50, .5); } return(row); }
static void devstats(int perf_select, long double etime, int havelast) { int dn; long double transfers_per_second, transfers_per_second_read; long double transfers_per_second_write; long double kb_per_transfer, mb_per_second, mb_per_second_read; long double mb_per_second_write; u_int64_t total_bytes, total_transfers, total_blocks; u_int64_t total_bytes_read, total_transfers_read; u_int64_t total_bytes_write, total_transfers_write; long double busy_pct, busy_time; u_int64_t queue_len; long double total_mb, blocks_per_second, total_duration; long double ms_per_other, ms_per_read, ms_per_write, ms_per_transaction; int firstline = 1; char *devicename; if (xflag > 0) { printf(" extended device statistics "); if (Tflag > 0) printf(" tty "); if (Cflag > 0) printf(" cpu "); printf("\n"); if (Iflag == 0) { printf("device r/s w/s kr/s kw/s " " ms/r ms/w ms/o ms/t qlen %%b "); } else { printf("device r/i w/i kr/i" " kw/i qlen tsvc_t/i sb/i "); } if (Tflag > 0) printf("tin tout "); if (Cflag > 0) printf("us ni sy in id "); printf("\n"); } for (dn = 0; dn < num_devices; dn++) { int di; if (((perf_select == 0) && (dev_select[dn].selected == 0)) || (dev_select[dn].selected > maxshowdevs)) continue; di = dev_select[dn].position; if (devstat_compute_statistics(&cur.dinfo->devices[di], havelast ? &last.dinfo->devices[di] : NULL, etime, DSM_TOTAL_BYTES, &total_bytes, DSM_TOTAL_BYTES_READ, &total_bytes_read, DSM_TOTAL_BYTES_WRITE, &total_bytes_write, DSM_TOTAL_TRANSFERS, &total_transfers, DSM_TOTAL_TRANSFERS_READ, &total_transfers_read, DSM_TOTAL_TRANSFERS_WRITE, &total_transfers_write, DSM_TOTAL_BLOCKS, &total_blocks, DSM_KB_PER_TRANSFER, &kb_per_transfer, DSM_TRANSFERS_PER_SECOND, &transfers_per_second, DSM_TRANSFERS_PER_SECOND_READ, &transfers_per_second_read, DSM_TRANSFERS_PER_SECOND_WRITE, &transfers_per_second_write, DSM_MB_PER_SECOND, &mb_per_second, DSM_MB_PER_SECOND_READ, &mb_per_second_read, DSM_MB_PER_SECOND_WRITE, &mb_per_second_write, DSM_BLOCKS_PER_SECOND, &blocks_per_second, DSM_MS_PER_TRANSACTION, &ms_per_transaction, DSM_MS_PER_TRANSACTION_READ, &ms_per_read, DSM_MS_PER_TRANSACTION_WRITE, &ms_per_write, DSM_MS_PER_TRANSACTION_OTHER, &ms_per_other, DSM_BUSY_PCT, &busy_pct, DSM_QUEUE_LENGTH, &queue_len, DSM_TOTAL_DURATION, &total_duration, DSM_TOTAL_BUSY_TIME, &busy_time, DSM_NONE) != 0) errx(1, "%s", devstat_errbuf); if (perf_select != 0) { dev_select[dn].bytes = total_bytes; if ((dev_select[dn].selected == 0) || (dev_select[dn].selected > maxshowdevs)) continue; } if (Kflag > 0 || xflag > 0) { int block_size = cur.dinfo->devices[di].block_size; total_blocks = total_blocks * (block_size ? block_size : 512) / 1024; } if (xflag > 0) { if (asprintf(&devicename, "%s%d", cur.dinfo->devices[di].device_name, cur.dinfo->devices[di].unit_number) == -1) err(1, "asprintf"); /* * If zflag is set, skip any devices with zero I/O. */ if (zflag == 0 || transfers_per_second_read > 0.05 || transfers_per_second_write > 0.05 || mb_per_second_read > ((long double).0005)/1024 || mb_per_second_write > ((long double).0005)/1024 || busy_pct > 0.5) { if (Iflag == 0) printf("%-8.8s %5d %5d %8.1Lf " "%8.1Lf %5d %5d %5d %5d " "%4" PRIu64 " %3.0Lf ", devicename, (int)transfers_per_second_read, (int)transfers_per_second_write, mb_per_second_read * 1024, mb_per_second_write * 1024, (int)ms_per_read, (int)ms_per_write, (int)ms_per_other, (int)ms_per_transaction, queue_len, busy_pct); else printf("%-8.8s %11.1Lf %11.1Lf " "%12.1Lf %12.1Lf %4" PRIu64 " %10.1Lf %9.1Lf ", devicename, (long double)total_transfers_read, (long double)total_transfers_write, (long double) total_bytes_read / 1024, (long double) total_bytes_write / 1024, queue_len, total_duration, busy_time); if (firstline) { /* * If this is the first device * we're printing, also print * CPU or TTY stats if requested. */ firstline = 0; if (Tflag > 0) printf("%4.0Lf%5.0Lf", cur.tk_nin / etime, cur.tk_nout / etime); if (Cflag > 0) cpustats(); } printf("\n"); } free(devicename); } else if (oflag > 0) { int msdig = (ms_per_transaction < 100.0) ? 1 : 0; if (Iflag == 0) printf("%4.0Lf%4.0Lf%5.*Lf ", blocks_per_second, transfers_per_second, msdig, ms_per_transaction); else printf("%4.1" PRIu64 "%4.1" PRIu64 "%5.*Lf ", total_blocks, total_transfers, msdig, ms_per_transaction); } else { if (Iflag == 0) printf(" %5.2Lf %3.0Lf %5.2Lf ", kb_per_transfer, transfers_per_second, mb_per_second); else { total_mb = total_bytes; total_mb /= 1024 * 1024; printf(" %5.2Lf %3.1" PRIu64 " %5.2Lf ", kb_per_transfer, total_transfers, total_mb); } } } if (xflag > 0 && zflag > 0 && firstline == 1 && (Tflag > 0 || Cflag > 0)) { /* * If zflag is set and we did not print any device * lines I/O because they were all zero, * print TTY/CPU stats. */ printf("%52s",""); if (Tflag > 0) printf("%4.0Lf %5.0Lf", cur.tk_nin / etime, cur.tk_nout / etime); if (Cflag > 0) cpustats(); printf("\n"); } }
int main(int argc, char **argv) { int error, i, quit; int curx, cury, maxx, maxy, line_len, loop, max_flen; struct devstat *gsp, *gsq; void *sp, *sq; double dt; struct timespec tp, tq; struct gmesh gmp; 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[13]; uint64_t u64; EditLine *el; History *hist; HistEvent hist_ev; hist = NULL; el = NULL; maxx = -1; curx = -1; loop = 1; /* Turn on batch mode if output is not tty. */ if (!isatty(fileno(stdout))) flag_b = 1; f_s[0] = '\0'; while ((i = getopt(argc, argv, "abdcf:I:op")) != -1) { switch (i) { case 'a': flag_a = 1; break; case 'b': flag_b = 1; break; case 'c': flag_c = 1; break; 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 'o': flag_o = 1; break; case 'I': p = NULL; i = strtoul(optarg, &p, 0); if (p == optarg || errno == EINVAL || errno == ERANGE) { errx(1, "Invalid argument to -I"); } else if (!strcmp(p, "s")) i *= 1000000; else if (!strcmp(p, "ms")) i *= 1000; else if (!strcmp(p, "us")) i *= 1; flag_I = i; break; case 'p': flag_p = 1; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc != 0) usage(); i = geom_gettree(&gmp); if (i != 0) err(1, "geom_gettree = %d", i); error = geom_stats_open(); if (error) err(1, "geom_stats_open()"); sq = NULL; sq = geom_stats_snapshot_get(); if (sq == NULL) err(1, "geom_stats_snapshot()"); if (!flag_b) { /* Setup curses */ initscr(); start_color(); use_default_colors(); pair_content(0, &cf, &cb); init_pair(1, COLOR_GREEN, cb); init_pair(2, COLOR_MAGENTA, cb); init_pair(3, COLOR_RED, cb); cbreak(); noecho(); nonl(); 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(); if (sp == NULL) err(1, "geom_stats_snapshot()"); geom_stats_snapshot_timestamp(sp, &tp); dt = tp.tv_sec - tq.tv_sec; dt += (tp.tv_nsec - tq.tv_nsec) * 1e-9; tq = tp; geom_stats_snapshot_reset(sp); geom_stats_snapshot_reset(sq); move(0,0); PRINTMSG("dT: %5.3fs w: %.3fs", dt, (float)flag_I / 1000000); if (f_s[0] != '\0') { PRINTMSG(" filter: "); if (!flag_b) { 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'; } PRINTMSG("%s", pf_s); } PRINTMSG("\n"); PRINTMSG(" L(q) ops/s "); PRINTMSG(" r/s kBps ms/r "); PRINTMSG(" w/s kBps ms/w "); if (flag_d) PRINTMSG(" d/s kBps ms/d "); if (flag_o) PRINTMSG(" o/s ms/o "); PRINTMSG("%%busy Name\n"); for (;;) { gsp = geom_stats_snapshot_next(sp); gsq = geom_stats_snapshot_next(sq); if (gsp == NULL || gsq == NULL) break; if (gsp->id == NULL) continue; gid = geom_lookupid(&gmp, gsp->id); if (gid == NULL) { geom_deletetree(&gmp); i = geom_gettree(&gmp); if (i != 0) err(1, "geom_gettree = %d", i); gid = geom_lookupid(&gmp, gsp->id); } if (gid == NULL) continue; if (gid->lg_what == ISCONSUMER && !flag_c) continue; if (flag_p && gid->lg_what == ISPROVIDER && ((struct gprovider *)(gid->lg_ptr))->lg_geom->lg_rank != 1) continue; /* Do not print past end of window */ if (!flag_b) { 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) { PRINTMSG("*\n"); continue; } devstat_compute_statistics(gsp, gsq, dt, DSM_QUEUE_LENGTH, &u64, DSM_TRANSFERS_PER_SECOND, &ld[0], DSM_TRANSFERS_PER_SECOND_READ, &ld[1], DSM_MB_PER_SECOND_READ, &ld[2], DSM_MS_PER_TRANSACTION_READ, &ld[3], DSM_TRANSFERS_PER_SECOND_WRITE, &ld[4], DSM_MB_PER_SECOND_WRITE, &ld[5], DSM_MS_PER_TRANSACTION_WRITE, &ld[6], DSM_BUSY_PCT, &ld[7], DSM_TRANSFERS_PER_SECOND_FREE, &ld[8], DSM_MB_PER_SECOND_FREE, &ld[9], DSM_MS_PER_TRANSACTION_FREE, &ld[10], DSM_TRANSFERS_PER_SECOND_OTHER, &ld[11], DSM_MS_PER_TRANSACTION_OTHER, &ld[12], DSM_NONE); if (flag_a && ld[7] < 0.1) { *gsq = *gsp; continue; } PRINTMSG(" %4ju", (uintmax_t)u64); PRINTMSG(" %6.0f", (double)ld[0]); PRINTMSG(" %6.0f", (double)ld[1]); PRINTMSG(" %6.0f", (double)ld[2] * 1024); if (ld[3] > 1e3) PRINTMSG(" %6.0f", (double)ld[3]); else PRINTMSG(" %6.1f", (double)ld[3]); PRINTMSG(" %6.0f", (double)ld[4]); PRINTMSG(" %6.0f", (double)ld[5] * 1024); if (ld[6] > 1e3) PRINTMSG(" %6.0f", (double)ld[6]); else PRINTMSG(" %6.1f", (double)ld[6]); if (flag_d) { PRINTMSG(" %6.0f", (double)ld[8]); PRINTMSG(" %6.0f", (double)ld[9] * 1024); if (ld[10] > 1e3) PRINTMSG(" %6.0f", (double)ld[10]); else PRINTMSG(" %6.1f", (double)ld[10]); } if (flag_o) { PRINTMSG(" %6.0f", (double)ld[11]); if (ld[12] > 1e3) PRINTMSG(" %6.0f", (double)ld[12]); else PRINTMSG(" %6.1f", (double)ld[12]); } if (ld[7] > 80) i = 3; else if (ld[7] > 50) i = 2; else i = 1; if (!flag_b) attron(COLOR_PAIR(i)); PRINTMSG(" %6.1lf", (double)ld[7]); if (!flag_b) { attroff(COLOR_PAIR(i)); PRINTMSG("|"); } else PRINTMSG(" "); if (gid == NULL) { PRINTMSG(" ??"); } else if (gid->lg_what == ISPROVIDER) { pp = gid->lg_ptr; PRINTMSG(" %s", pp->lg_name); } else if (gid->lg_what == ISCONSUMER) { cp = gid->lg_ptr; PRINTMSG(" %s/%s/%s", cp->lg_geom->lg_class->lg_name, cp->lg_geom->lg_name, cp->lg_provider->lg_name); } if (!flag_b) clrtoeol(); PRINTMSG("\n"); *gsq = *gsp; } geom_stats_snapshot_free(sp); if (flag_b) { /* We loop extra to make sure we get the information. */ if (!loop) break; loop = 0; usleep(flag_I); continue; } getyx(stdscr, cury, curx); getmaxyx(stdscr, maxy, maxx); clrtobot(); if (maxy - 1 <= cury) move(maxy - 1, 0); refresh(); usleep(flag_I); 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; } } } if (!flag_b) { endwin(); el_end(el); } exit(EX_OK); }