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_a, 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, "adcI:")) != -1) { 73 switch (i) { 74 case 'a': 75 flag_a = 1; 76 break; 77 case 'c': 78 flag_c = 1; 79 break; 80 case 'd': 81 flag_d = 1; 82 break; 83 case 'I': 84 p = NULL; 85 i = strtoul(optarg, &p, 0); 86 if (p == optarg || errno == EINVAL || 87 errno == ERANGE) { 88 errx(1, "Invalid argument to -I"); 89 } else if (!strcmp(p, "s")) 90 i *= 1000000; 91 else if (!strcmp(p, "ms")) 92 i *= 1000; 93 else if (!strcmp(p, "us")) 94 i *= 1; 95 flag_I = i; 96 break; 97 case '?': 98 default: 99 usage(); 100 } 101 } 102 argc -= optind; 103 argv += optind; 104 if (argc != 0) 105 usage(); 106 107 i = geom_gettree(&gmp); 108 if (i != 0) 109 err(1, "geom_gettree = %d", i); 110 error = geom_stats_open(); 111 if (error) 112 err(1, "geom_stats_open()"); 113 sq = NULL; 114 sq = geom_stats_snapshot_get(); 115 if (sq == NULL) 116 err(1, "geom_stats_snapshot()"); 117 initscr(); 118 start_color(); 119 use_default_colors(); 120 pair_content(0, &cf, &cb); 121 init_pair(1, COLOR_GREEN, cb); 122 init_pair(2, COLOR_MAGENTA, cb); 123 init_pair(3, COLOR_RED, cb); 124 cbreak(); 125 noecho(); 126 nonl(); 127 nodelay(stdscr, 1); 128 intrflush(stdscr, FALSE); 129 keypad(stdscr, TRUE); 130 geom_stats_snapshot_timestamp(sq, &tq); 131 for (quit = 0; !quit;) { 132 sp = geom_stats_snapshot_get(); 133 if (sp == NULL) 134 err(1, "geom_stats_snapshot()"); 135 geom_stats_snapshot_timestamp(sp, &tp); 136 dt = tp.tv_sec - tq.tv_sec; 137 dt += (tp.tv_nsec - tq.tv_nsec) * 1e-9; 138 tq = tp; 139 140 geom_stats_snapshot_reset(sp); 141 geom_stats_snapshot_reset(sq); 142 move(0,0); 143 printw("dT: %5.3f flag_I %dus sizeof %d i %d\n", 144 dt, flag_I, sizeof(*gsp), i); 145 printw(" L(q) ops/s "); 146 printw(" r/s kBps ms/r "); 147 printw(" w/s kBps ms/w "); 148 if (flag_d) 149 printw(" d/s kBps ms/d "); 150 printw("%%busy Name\n"); 151 for (;;) { 152 gsp = geom_stats_snapshot_next(sp); 153 gsq = geom_stats_snapshot_next(sq); 154 if (gsp == NULL || gsq == NULL) 155 break; 156 if (gsp->id == NULL) 157 continue; 158 gid = geom_lookupid(&gmp, gsp->id); 159 if (gid == NULL) { 160 geom_deletetree(&gmp); 161 i = geom_gettree(&gmp); 162 if (i != 0) 163 err(1, "geom_gettree = %d", i); 164 gid = geom_lookupid(&gmp, gsp->id); 165 } 166 if (gid == NULL) 167 continue; 168 if (gid != NULL && gid->lg_what == ISCONSUMER && 169 !flag_c) 170 continue; 171 if (gsp->sequence0 != gsp->sequence1) { 172 printw("*\n"); 173 continue; 174 } 175 devstat_compute_statistics(gsp, gsq, dt, 176 DSM_QUEUE_LENGTH, &u64, 177 DSM_TRANSFERS_PER_SECOND, &ld[0], 178 179 DSM_TRANSFERS_PER_SECOND_READ, &ld[1], 180 DSM_MB_PER_SECOND_READ, &ld[2], 181 DSM_MS_PER_TRANSACTION_READ, &ld[3], 182 183 DSM_TRANSFERS_PER_SECOND_WRITE, &ld[4], 184 DSM_MB_PER_SECOND_WRITE, &ld[5], 185 DSM_MS_PER_TRANSACTION_WRITE, &ld[6], 186 187 DSM_BUSY_PCT, &ld[7], 188 DSM_TRANSFERS_PER_SECOND_FREE, &ld[8], 189 DSM_MB_PER_SECOND_FREE, &ld[9], 190 DSM_MS_PER_TRANSACTION_FREE, &ld[10], 191 DSM_NONE); 192 193 if (flag_a && ld[7] < 0.1) { 194 *gsq = *gsp; 195 continue; 196 } 197 198 printw(" %4ju", (uintmax_t)u64); 199 printw(" %6.0f", (double)ld[0]); 200 printw(" %6.0f", (double)ld[1]); 201 printw(" %6.0f", (double)ld[2] * 1024); 202 printw(" %6.1f", (double)ld[3]); 203 printw(" %6.0f", (double)ld[4]); 204 printw(" %6.0f", (double)ld[5] * 1024); 205 printw(" %6.1f", (double)ld[6]); 206 207 if (flag_d) { 208 printw(" %6.0f", (double)ld[8]); 209 printw(" %6.0f", (double)ld[9] * 1024); 210 printw(" %6.1f", (double)ld[10]); 211 } 212 213 if (ld[7] > 80) 214 i = 3; 215 else if (ld[7] > 50) 216 i = 2; 217 else 218 i = 1; 219 attron(COLOR_PAIR(i)); 220 printw(" %6.1lf", (double)ld[7]); 221 attroff(COLOR_PAIR(i)); 222 printw("|"); 223 if (gid == NULL) { 224 printw(" ??"); 225 } else if (gid->lg_what == ISPROVIDER) { 226 pp = gid->lg_ptr; 227 printw(" %s", pp->lg_name); 228 } else if (gid->lg_what == ISCONSUMER) { 229 cp = gid->lg_ptr; 230 printw(" %s/%s/%s", 231 cp->lg_geom->lg_class->lg_name, 232 cp->lg_geom->lg_name, 233 cp->lg_provider->lg_name); 234 } 235 clrtoeol(); 236 printw("\n"); 237 *gsq = *gsp; 238 } 239 geom_stats_snapshot_free(sp); 240 clrtobot(); 241 refresh(); 242 usleep(flag_I); 243 i = getch(); 244 switch (i) { 245 case '>': 246 flag_I *= 2; 247 break; 248 case '<': 249 flag_I /= 2; 250 if (flag_I < 1000) 251 flag_I = 1000; 252 break; 253 case 'c': 254 flag_c = !flag_c; 255 break; 256 case 'q': 257 quit = 1; 258 break; 259 default: 260 break; 261 } 262 } 263 264 endwin(); 265 exit (0); 266 } 267 268 static void 269 usage(void) 270 { 271 fprintf(stderr, "usage: gstat [-acd] [-I interval]\n"); 272 exit(1); 273 /* NOTREACHED */ 274 } 275