iostat.c revision 1.25 1 /* $NetBSD: iostat.c,v 1.25 2002/12/29 19:03:56 kristerw Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93";
40 #endif
41 __RCSID("$NetBSD: iostat.c,v 1.25 2002/12/29 19:03:56 kristerw Exp $");
42 #endif /* not lint */
43
44 #include <sys/param.h>
45
46 #include <string.h>
47
48 #include "systat.h"
49 #include "extern.h"
50 #include "dkstats.h"
51
52 static int linesperregion;
53 static double etime;
54 static int numbers = 0; /* default display bar graphs */
55 static int secs = 0; /* default seconds shown */
56 static int read_write = 0; /* default read/write shown */
57
58 static int barlabels(int);
59 static void histogram(double, int, double);
60 static int numlabels(int);
61 static int stats(int, int, int);
62 static void stat1(int, int);
63
64
65 WINDOW *
66 openiostat(void)
67 {
68
69 return (subwin(stdscr, LINES-1-5, 0, 5, 0));
70 }
71
72 void
73 closeiostat(WINDOW *w)
74 {
75
76 if (w == NULL)
77 return;
78 wclear(w);
79 wrefresh(w);
80 delwin(w);
81 }
82
83 int
84 initiostat(void)
85 {
86
87 dkinit(1);
88 dkreadstats();
89 return(1);
90 }
91
92 void
93 fetchiostat(void)
94 {
95
96 if (dk_ndrive == 0)
97 return;
98 dkreadstats();
99 }
100
101 #define INSET 14
102
103 void
104 labeliostat(void)
105 {
106 int row;
107
108 if (dk_ndrive == 0) {
109 error("No drives defined.");
110 return;
111 }
112 row = 0;
113 wmove(wnd, row, 0); wclrtobot(wnd);
114 mvwaddstr(wnd, row++, INSET,
115 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
116 mvwaddstr(wnd, row++, 0, " cpu user|");
117 mvwaddstr(wnd, row++, 0, " nice|");
118 mvwaddstr(wnd, row++, 0, " system|");
119 mvwaddstr(wnd, row++, 0, " interrupt|");
120 mvwaddstr(wnd, row++, 0, " idle|");
121 if (numbers)
122 row = numlabels(row + 1);
123 else
124 row = barlabels(row + 1);
125 }
126
127 static int
128 numlabels(int row)
129 {
130 int i, col, regions, ndrives;
131
132 #define COLWIDTH (read_write ? 24 : 14)
133 #define DRIVESPERLINE ((getmaxx(wnd) - 1) / COLWIDTH)
134 for (ndrives = 0, i = 0; i < dk_ndrive; i++)
135 if (cur.dk_select[i])
136 ndrives++;
137 regions = howmany(ndrives, DRIVESPERLINE);
138 /*
139 * Deduct -regions for blank line after each scrolling region.
140 */
141 linesperregion = (getmaxy(wnd) - row - regions) / regions;
142 /*
143 * Minimum region contains space for two
144 * label lines and one line of statistics.
145 */
146 if (linesperregion < 3)
147 linesperregion = 3;
148 col = 0;
149 for (i = 0; i < dk_ndrive; i++)
150 if (cur.dk_select[i]) {
151 if (col + COLWIDTH > getmaxx(wnd)) {
152 col = 0, row += linesperregion + 1;
153 if (row > getmaxy(wnd) - (linesperregion + 1))
154 break;
155 }
156 mvwprintw(wnd, row, col + 4, "%s%s",
157 cur.dk_name[i], read_write ? " (write)" : "");
158 if (read_write)
159 mvwaddstr(wnd, row + 1, col,
160 "kBps r/s sec kBps w/s");
161 else
162 mvwaddstr(wnd, row + 1, col, "kBps tps sec");
163 col += COLWIDTH;
164 }
165 if (col)
166 row += linesperregion + 1;
167 return (row);
168 }
169
170 static int
171 barlabels(int row)
172 {
173 int i;
174
175 mvwaddstr(wnd, row++, INSET,
176 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
177 linesperregion = 2 + secs + (read_write ? 2 : 0);
178 for (i = 0; i < dk_ndrive; i++)
179 if (cur.dk_select[i]) {
180 if (row > getmaxy(wnd) - linesperregion)
181 break;
182 mvwprintw(wnd, row++, 0, "%7.7s kBps|",
183 cur.dk_name[i]);
184 mvwaddstr(wnd, row++, 0, " tps|");
185 if (read_write) {
186 mvwprintw(wnd, row++, 0, " (write) kBps|");
187 mvwaddstr(wnd, row++, 0, " tps|");
188 }
189 if (secs)
190 mvwaddstr(wnd, row++, 0, " msec|");
191 }
192 return (row);
193 }
194
195 void
196 showiostat(void)
197 {
198 int i, row, col;
199
200 if (dk_ndrive == 0)
201 return;
202 dkswap();
203
204 etime = cur.cp_etime;
205 row = 1;
206
207 /*
208 * Interrupt CPU state not calculated yet.
209 */
210 for (i = 0; i < CPUSTATES; i++)
211 stat1(row++, i);
212 if (!numbers) {
213 row += 2;
214 for (i = 0; i < dk_ndrive; i++)
215 if (cur.dk_select[i]) {
216 if (row > getmaxy(wnd) - linesperregion)
217 break;
218 row = stats(row, INSET, i);
219 }
220 return;
221 }
222 col = 0;
223 wmove(wnd, row + linesperregion, 0);
224 wdeleteln(wnd);
225 wmove(wnd, row + 3, 0);
226 winsertln(wnd);
227 for (i = 0; i < dk_ndrive; i++)
228 if (cur.dk_select[i]) {
229 if (col + COLWIDTH > getmaxx(wnd)) {
230 col = 0, row += linesperregion + 1;
231 if (row > getmaxy(wnd) - (linesperregion + 1))
232 break;
233 wmove(wnd, row + linesperregion, 0);
234 wdeleteln(wnd);
235 wmove(wnd, row + 3, 0);
236 winsertln(wnd);
237 }
238 (void) stats(row + 3, col, i);
239 col += COLWIDTH;
240 }
241 }
242
243 static int
244 stats(int row, int col, int dn)
245 {
246 double atime, rwords, wwords;
247
248 /* time busy in disk activity */
249 atime = (double)cur.dk_time[dn].tv_sec +
250 ((double)cur.dk_time[dn].tv_usec / (double)1000000);
251
252 /* # of k transferred */
253 rwords = cur.dk_rbytes[dn] / 1024.0;
254 wwords = cur.dk_wbytes[dn] / 1024.0;
255 if (numbers) {
256 if (read_write)
257 mvwprintw(wnd, row, col, "%4.0f%4.0f%5.1f %3.0f%4.0f",
258 rwords / etime, cur.dk_rxfer[dn] / etime,
259 atime / etime,
260 wwords / etime, cur.dk_wxfer[dn] / etime);
261 else
262 mvwprintw(wnd, row, col, "%4.0f%4.0f%5.1f",
263 (rwords + wwords) / etime,
264 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime,
265 atime / etime);
266 return (row);
267 }
268
269 if (read_write) {
270 wmove(wnd, row++, col);
271 histogram(rwords / etime, 50, 0.5);
272 wmove(wnd, row++, col);
273 histogram(cur.dk_rxfer[dn] / etime, 50, 0.5);
274 wmove(wnd, row++, col);
275 histogram(wwords / etime, 50, 0.5);
276 wmove(wnd, row++, col);
277 histogram(cur.dk_wxfer[dn] / etime, 50, 0.5);
278 } else {
279 wmove(wnd, row++, col);
280 histogram((rwords + wwords) / etime, 50, 0.5);
281 wmove(wnd, row++, col);
282 histogram((cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime, 50, 0.5);
283 }
284
285 if (secs) {
286 wmove(wnd, row++, col);
287 atime *= 1000; /* In milliseconds */
288 histogram(atime / etime, 50, 0.5);
289 }
290 return (row);
291 }
292
293 static void
294 stat1(int row, int o)
295 {
296 int i;
297 double time;
298
299 time = 0;
300 for (i = 0; i < CPUSTATES; i++)
301 time += cur.cp_time[i];
302 if (time == 0.0)
303 time = 1.0;
304 wmove(wnd, row, INSET);
305 #define CPUSCALE 0.5
306 histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE);
307 }
308
309 static void
310 histogram(double val, int colwidth, double scale)
311 {
312 char buf[10];
313 int k;
314 int v = (int)(val * scale) + 0.5;
315
316 k = MIN(v, colwidth);
317 if (v > colwidth) {
318 snprintf(buf, sizeof buf, "%4.1f", val);
319 k -= strlen(buf);
320 while (k--)
321 waddch(wnd, 'X');
322 waddstr(wnd, buf);
323 wclrtoeol(wnd);
324 return;
325 }
326 wclrtoeol(wnd);
327 whline(wnd, 'X', k);
328 }
329
330 void
331 iostat_bars(char *args)
332 {
333 numbers = 0;
334 wclear(wnd);
335 labeliostat();
336 refresh();
337 }
338
339 void
340 iostat_numbers(char *args)
341 {
342 numbers = 1;
343 wclear(wnd);
344 labeliostat();
345 refresh();
346 }
347
348 void
349 iostat_secs(char *args)
350 {
351 secs = !secs;
352 wclear(wnd);
353 labeliostat();
354 refresh();
355 }
356
357 void
358 iostat_rw(char *args)
359 {
360 read_write = 1;
361 wclear(wnd);
362 labeliostat();
363 refresh();
364 }
365
366 void
367 iostat_all(char *args)
368 {
369 read_write = 0;
370 wclear(wnd);
371 labeliostat();
372 refresh();
373 }
374