1 /*- 2 * Copyright (c) 2003 Poul-Henning Kamp 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The names of the authors may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 33 #include <stdio.h> 34 #include <stdint.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <paths.h> 38 #include <curses.h> 39 #include <unistd.h> 40 #include <fcntl.h> 41 #include <errno.h> 42 #include <err.h> 43 #include <sys/mman.h> 44 #include <sys/time.h> 45 #include <libgeom.h> 46 #include <sys/resource.h> 47 #include <devstat.h> 48 #include <sys/devicestat.h> 49 50 static int flag_c, flag_d; 51 static int flag_I = 500000; 52 53 static void usage(void); 54 55 int 56 main(int argc, char **argv) 57 { 58 int error, i, quit; 59 struct devstat *gsp, *gsq; 60 void *sp, *sq; 61 double dt; 62 struct timespec tp, tq; 63 struct gmesh gmp; 64 struct gprovider *pp; 65 struct gconsumer *cp; 66 struct gident *gid; 67 short cf, cb; 68 char *p; 69 long double ld[11]; 70 uint64_t u64; 71 72 while ((i = getopt(argc, argv, "dcI:")) != -1) { 73 switch (i) { 74 case 'c': 75 flag_c = 1; 76 break; 77 case 'd': 78 flag_d = 1; 79 break; 80 case 'I': 81 p = NULL; 82 i = strtoul(optarg, &p, 0); 83 if (p == optarg || errno == EINVAL || 84 errno == ERANGE) { 85 errx(1, "Invalid argument to -I"); 86 } else if (!strcmp(p, "s")) 87 i *= 1000000; 88 else if (!strcmp(p, "ms")) 89 i *= 1000; 90 else if (!strcmp(p, "us")) 91 i *= 1; 92 flag_I = i; 93 break; 94 case '?': 95 default: 96 usage(); 97 } 98 } 99 argc -= optind; 100 argv += optind; 101 if (argc != 0) 102 usage(); 103 104 i = geom_gettree(&gmp); 105 if (i != 0) 106 err(1, "geom_gettree = %d", i); 107 error = geom_stats_open(); 108 if (error) 109 err(1, "geom_stats_open()"); 110 sq = NULL; 111 sq = geom_stats_snapshot_get(); 112 if (sq == NULL) 113 err(1, "geom_stats_snapshot()"); 114 initscr(); 115 start_color(); 116 use_default_colors(); 117 pair_content(0, &cf, &cb); 118 init_pair(1, COLOR_GREEN, cb); 119 init_pair(2, COLOR_MAGENTA, cb); 120 init_pair(3, COLOR_RED, cb); 121 cbreak(); 122 noecho(); 123 nonl(); 124 nodelay(stdscr, 1); 125 intrflush(stdscr, FALSE); 126 keypad(stdscr, TRUE); 127 geom_stats_snapshot_timestamp(sq, &tq); 128 for (quit = 0; !quit;) { 129 sp = geom_stats_snapshot_get(); 130 if (sp == NULL) 131 err(1, "geom_stats_snapshot()"); 132 geom_stats_snapshot_timestamp(sp, &tp); 133 dt = tp.tv_sec - tq.tv_sec; 134 dt += (tp.tv_nsec - tq.tv_nsec) * 1e-9; 135 tq = tp; 136 137 geom_stats_snapshot_reset(sp); 138 geom_stats_snapshot_reset(sq); 139 move(0,0); 140 printw("dT: %5.3f flag_I %dus sizeof %d i %d\n", 141 dt, flag_I, sizeof(*gsp), i); 142 printw(" L(q) ops/s "); 143 printw(" r/s kBps ms/r "); 144 printw(" w/s kBps ms/w "); 145 if (flag_d) 146 printw(" d/s kBps ms/d "); 147 printw("%%busy Name\n"); 148 for (;;) { 149 gsp = geom_stats_snapshot_next(sp); 150 gsq = geom_stats_snapshot_next(sq); 151 if (gsp == NULL || gsq == NULL) 152 break; 153 if (gsp->id == NULL) 154 continue; 155 gid = geom_lookupid(&gmp, gsp->id); 156 if (gid == NULL) { 157 geom_deletetree(&gmp); 158 i = geom_gettree(&gmp); 159 if (i != 0) 160 err(1, "geom_gettree = %d", i); 161 gid = geom_lookupid(&gmp, gsp->id); 162 } 163 if (gid == NULL) 164 continue; 165 if (gid != NULL && gid->lg_what == ISCONSUMER && 166 !flag_c) 167 continue; 168 if (gsp->sequence0 != gsp->sequence1) { 169 printw("*\n"); 170 continue; 171 } 172 devstat_compute_statistics(gsp, gsq, dt, 173 DSM_QUEUE_LENGTH, &u64, 174 DSM_TRANSFERS_PER_SECOND, &ld[0], 175 176 DSM_TRANSFERS_PER_SECOND_READ, &ld[1], 177 DSM_MB_PER_SECOND_READ, &ld[2], 178 DSM_MS_PER_TRANSACTION_READ, &ld[3], 179 180 DSM_TRANSFERS_PER_SECOND_WRITE, &ld[4], 181 DSM_MB_PER_SECOND_WRITE, &ld[5], 182 DSM_MS_PER_TRANSACTION_WRITE, &ld[6], 183 184 DSM_BUSY_PCT, &ld[7], 185 DSM_TRANSFERS_PER_SECOND_FREE, &ld[8], 186 DSM_MB_PER_SECOND_FREE, &ld[9], 187 DSM_MS_PER_TRANSACTION_FREE, &ld[10], 188 DSM_NONE); 189 190 printw(" %4ju", (uintmax_t)u64); 191 printw(" %6.0f", (double)ld[0]); 192 printw(" %6.0f", (double)ld[1]); 193 printw(" %6.0f", (double)ld[2] * 1024); 194 printw(" %6.1f", (double)ld[3]); 195 printw(" %6.0f", (double)ld[4]); 196 printw(" %6.0f", (double)ld[5] * 1024); 197 printw(" %6.1f", (double)ld[6]); 198 199 if (flag_d) { 200 printw(" %6.0f", (double)ld[8]); 201 printw(" %6.0f", (double)ld[9] * 1024); 202 printw(" %6.1f", (double)ld[10]); 203 } 204 205 if (ld[7] > 80) 206 i = 3; 207 else if (ld[7] > 50) 208 i = 2; 209 else 210 i = 1; 211 attron(COLOR_PAIR(i)); 212 printw(" %6.1lf", (double)ld[7]); 213 attroff(COLOR_PAIR(i)); 214 printw("|"); 215 if (gid == NULL) { 216 printw(" ??"); 217 } else if (gid->lg_what == ISPROVIDER) { 218 pp = gid->lg_ptr; 219 printw(" %s", pp->lg_name); 220 } else if (gid->lg_what == ISCONSUMER) { 221 cp = gid->lg_ptr; 222 printw(" %s/%s/%s", 223 cp->lg_geom->lg_class->lg_name, 224 cp->lg_geom->lg_name, 225 cp->lg_provider->lg_name); 226 } 227 clrtoeol(); 228 printw("\n"); 229 *gsq = *gsp; 230 } 231 geom_stats_snapshot_free(sp); 232 clrtobot(); 233 refresh(); 234 usleep(flag_I); 235 i = getch(); 236 switch (i) { 237 case '>': 238 flag_I *= 2; 239 break; 240 case '<': 241 flag_I /= 2; 242 if (flag_I < 1000) 243 flag_I = 1000; 244 break; 245 case 'c': 246 flag_c = !flag_c; 247 break; 248 case 'q': 249 quit = 1; 250 break; 251 default: 252 break; 253 } 254 } 255 256 endwin(); 257 exit (0); 258 } 259 260 static void 261 usage(void) 262 { 263 fprintf(stderr, "usage: gstat [-cd] [-I interval]\n"); 264 exit(1); 265 /* NOTREACHED */ 266 } 267