1 /* $OpenBSD: iostat.c,v 1.50 2021/08/14 14:22:26 millert Exp $ */ 2 /* $NetBSD: iostat.c,v 1.5 1996/05/10 23:16:35 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1980, 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/mount.h> 35 #include <sys/signal.h> 36 #include <sys/sched.h> 37 #include <sys/sysctl.h> 38 #include <sys/time.h> 39 40 #include <string.h> 41 #include <stdlib.h> 42 #include <paths.h> 43 #include "systat.h" 44 45 #include "dkstats.h" 46 extern struct _disk cur, last; 47 struct bcachestats bclast, bccur; 48 49 static double etime; 50 51 void showtotal(void); 52 void showdrive(int); 53 void print_io(void); 54 int read_io(void); 55 int select_io(void); 56 void showbcache(void); 57 58 #define ATIME(x,y) ((double)x[y].tv_sec + \ 59 ((double)x[y].tv_usec / (double)1000000)) 60 61 62 field_def fields_io[] = { 63 {"DEVICE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 64 {"READ", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 65 {"WRITE", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 66 {"RTPS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 67 {"WTPS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 68 {"SEC", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 69 {"", 8, 19, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 70 {"STATS", 12, 15, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0} 71 }; 72 73 #define FLD_IO_DEVICE FIELD_ADDR(fields_io,0) 74 #define FLD_IO_READ FIELD_ADDR(fields_io,1) 75 #define FLD_IO_WRITE FIELD_ADDR(fields_io,2) 76 #define FLD_IO_RTPS FIELD_ADDR(fields_io,3) 77 #define FLD_IO_WTPS FIELD_ADDR(fields_io,4) 78 #define FLD_IO_SEC FIELD_ADDR(fields_io,5) 79 80 /* This is a hack that stuffs bcache statistics to the last two columns! */ 81 #define FLD_IO_SVAL FIELD_ADDR(fields_io,6) 82 #define FLD_IO_SSTR FIELD_ADDR(fields_io,7) 83 84 /* Define views */ 85 field_def *view_io_0[] = { 86 FLD_IO_DEVICE, FLD_IO_READ, FLD_IO_WRITE, FLD_IO_RTPS, 87 FLD_IO_WTPS, FLD_IO_SEC, FLD_IO_SVAL, FLD_IO_SSTR, NULL 88 }; 89 90 static enum state { BOOT, TIME } state = TIME; 91 92 static int 93 io_keyboard_callback(int ch) 94 { 95 switch (ch) { 96 case 'b': 97 state = BOOT; 98 break; 99 case 't': 100 state = TIME; 101 break; 102 default: 103 return keyboard_callback(ch); 104 } 105 return 0; 106 } 107 108 /* Define view managers */ 109 struct view_manager iostat_mgr = { 110 "Iostat", select_io, read_io, NULL, print_header, 111 print_io, io_keyboard_callback, NULL, NULL 112 }; 113 114 115 field_view views_io[] = { 116 {view_io_0, "iostat", '2', &iostat_mgr}, 117 {NULL, NULL, 0, NULL} 118 }; 119 120 121 int 122 select_io(void) 123 { 124 num_disp = cur.dk_ndrive + 1; 125 return (0); 126 } 127 128 int 129 read_io(void) 130 { 131 int mib[3]; 132 size_t size; 133 134 dkreadstats(); 135 if (state == BOOT) { 136 unsigned int dn; 137 for (dn = 0; dn < last.dk_ndrive; dn++) { 138 last.dk_rbytes[dn] = 0; 139 last.dk_wbytes[dn] = 0; 140 last.dk_rxfer[dn] = 0; 141 last.dk_wxfer[dn] = 0; 142 } 143 } 144 dkswap(); 145 num_disp = cur.dk_ndrive + 1; 146 147 bclast = bccur; 148 mib[0] = CTL_VFS; 149 mib[1] = VFS_GENERIC; 150 mib[2] = VFS_BCACHESTAT; 151 size = sizeof(bccur); 152 153 if (sysctl(mib, 3, &bccur, &size, NULL, 0) == -1) 154 error("cannot get vfs.bcachestat"); 155 156 if (bclast.numbufs == 0) 157 bclast = bccur; 158 159 if (state == BOOT) 160 memset(&bclast, 0, sizeof(bclast)); 161 162 return 0; 163 } 164 165 166 void 167 print_io(void) 168 { 169 int n, count = 0; 170 int curr; 171 172 if (state == BOOT) 173 etime = 1.0; 174 else 175 etime = naptime; 176 177 /* XXX engine internals: save and restore curr_line for bcache */ 178 curr = curr_line; 179 180 for (n = dispstart; n < num_disp - 1; n++) { 181 showdrive(n); 182 count++; 183 if (maxprint > 0 && count >= maxprint) 184 break; 185 } 186 187 188 if (maxprint == 0 || count < maxprint) 189 showtotal(); 190 191 curr_line = curr; 192 showbcache(); 193 } 194 195 int 196 initiostat(void) 197 { 198 field_view *v; 199 200 dkinit(1); 201 dkreadstats(); 202 203 bzero(&bccur, sizeof(bccur)); 204 205 for (v = views_io; v->name != NULL; v++) 206 add_view(v); 207 208 return (1); 209 } 210 211 void 212 showtotal(void) 213 { 214 double rsum, wsum, rtsum, wtsum, mssum; 215 int dn; 216 217 rsum = wsum = rtsum = wtsum = mssum = 0.0; 218 219 for (dn = 0; dn < cur.dk_ndrive; dn++) { 220 rsum += cur.dk_rbytes[dn] / etime; 221 wsum += cur.dk_wbytes[dn] / etime; 222 rtsum += cur.dk_rxfer[dn] / etime; 223 wtsum += cur.dk_wxfer[dn] / etime; 224 mssum += ATIME(cur.dk_time, dn) / etime; 225 } 226 227 print_fld_str(FLD_IO_DEVICE, "Totals"); 228 print_fld_size(FLD_IO_READ, rsum); 229 print_fld_size(FLD_IO_WRITE, wsum); 230 print_fld_size(FLD_IO_RTPS, rtsum); 231 print_fld_size(FLD_IO_WTPS, wtsum); 232 print_fld_float(FLD_IO_SEC, mssum, 1); 233 234 end_line(); 235 } 236 237 void 238 showdrive(int dn) 239 { 240 print_fld_str(FLD_IO_DEVICE, cur.dk_name[dn]); 241 print_fld_size(FLD_IO_READ, cur.dk_rbytes[dn] / etime); 242 print_fld_size(FLD_IO_WRITE, cur.dk_wbytes[dn] / etime); 243 print_fld_size(FLD_IO_RTPS, cur.dk_rxfer[dn] / etime); 244 print_fld_size(FLD_IO_WTPS, cur.dk_wxfer[dn] / etime); 245 print_fld_float(FLD_IO_SEC, ATIME(cur.dk_time, dn) / etime, 1); 246 247 end_line(); 248 } 249 250 void 251 showbcache(void) 252 { 253 print_fld_str(FLD_IO_SSTR, "total pages"); 254 print_fld_ssize(FLD_IO_SVAL, bccur.numbufpages); 255 end_line(); 256 257 print_fld_str(FLD_IO_SSTR, "dma pages"); 258 print_fld_ssize(FLD_IO_SVAL, bccur.dmapages); 259 end_line(); 260 261 print_fld_str(FLD_IO_SSTR, "dirty pages"); 262 print_fld_ssize(FLD_IO_SVAL, bccur.numdirtypages); 263 end_line(); 264 265 print_fld_str(FLD_IO_SSTR, "delwri bufs"); 266 print_fld_ssize(FLD_IO_SVAL, bccur.delwribufs); 267 end_line(); 268 269 print_fld_str(FLD_IO_SSTR, "busymap bufs"); 270 print_fld_ssize(FLD_IO_SVAL, bccur.busymapped); 271 end_line(); 272 273 print_fld_str(FLD_IO_SSTR, "avail kvaslots"); 274 print_fld_ssize(FLD_IO_SVAL, bccur.kvaslots_avail); 275 end_line(); 276 277 print_fld_str(FLD_IO_SSTR, "kvaslots"); 278 print_fld_ssize(FLD_IO_SVAL, bccur.kvaslots); 279 end_line(); 280 281 print_fld_str(FLD_IO_SSTR, "pending writes"); 282 print_fld_ssize(FLD_IO_SVAL, bccur.pendingwrites); 283 end_line(); 284 285 print_fld_str(FLD_IO_SSTR, "pending reads"); 286 print_fld_ssize(FLD_IO_SVAL, bccur.pendingreads); 287 end_line(); 288 289 print_fld_str(FLD_IO_SSTR, "cache hits"); 290 print_fld_ssize(FLD_IO_SVAL, bccur.cachehits - bclast.cachehits); 291 end_line(); 292 293 print_fld_str(FLD_IO_SSTR, "high flips"); 294 print_fld_ssize(FLD_IO_SVAL, bccur.highflips - bclast.highflips); 295 end_line(); 296 297 print_fld_str(FLD_IO_SSTR, "high flops"); 298 print_fld_ssize(FLD_IO_SVAL, bccur.highflops - bclast.highflops); 299 end_line(); 300 301 print_fld_str(FLD_IO_SSTR, "dma flips"); 302 print_fld_ssize(FLD_IO_SVAL, bccur.dmaflips - bclast.dmaflips); 303 end_line(); 304 } 305