iostat.c revision 1.15 1 /* $NetBSD: iostat.c,v 1.15 2000/06/04 18:29:13 mycroft 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.15 2000/06/04 18:29:13 mycroft Exp $");
42 #endif not lint
43
44 #include <sys/param.h>
45 #include <sys/sched.h>
46 #include <sys/dkstat.h>
47 #include <sys/buf.h>
48 #include <sys/time.h>
49
50 #include <string.h>
51 #include <stdlib.h>
52 #include <nlist.h>
53 #include <paths.h>
54 #include "systat.h"
55 #include "extern.h"
56
57 #include "dkstats.h"
58 extern struct _disk cur;
59
60 static int linesperregion;
61 static double etime;
62 static int numbers = 0; /* default display bar graphs */
63 static int secs = 0; /* default seconds shown */
64
65 static int barlabels __P((int));
66 static void histogram __P((double, int, double));
67 static int numlabels __P((int));
68 static int stats __P((int, int, int));
69 static void stat1 __P((int, int));
70
71
72 WINDOW *
73 openiostat()
74 {
75
76 return (subwin(stdscr, LINES-1-5, 0, 5, 0));
77 }
78
79 void
80 closeiostat(w)
81 WINDOW *w;
82 {
83
84 if (w == NULL)
85 return;
86 wclear(w);
87 wrefresh(w);
88 delwin(w);
89 }
90
91 int
92 initiostat()
93 {
94 extern gid_t egid;
95
96 dkinit(1, egid);
97 dkreadstats();
98 return(1);
99 }
100
101 void
102 fetchiostat()
103 {
104
105 if (dk_ndrive == 0)
106 return;
107 dkreadstats();
108 }
109
110 #define INSET 14
111
112 void
113 labeliostat()
114 {
115 int row;
116
117 if (dk_ndrive == 0) {
118 error("No drives defined.");
119 return;
120 }
121 row = 0;
122 wmove(wnd, row, 0); wclrtobot(wnd);
123 mvwaddstr(wnd, row++, INSET,
124 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
125 mvwaddstr(wnd, row++, 0, " cpu user|");
126 mvwaddstr(wnd, row++, 0, " nice|");
127 mvwaddstr(wnd, row++, 0, " system|");
128 mvwaddstr(wnd, row++, 0, " interrupt|");
129 mvwaddstr(wnd, row++, 0, " idle|");
130 if (numbers)
131 row = numlabels(row + 1);
132 else
133 row = barlabels(row + 1);
134 }
135
136 static int
137 numlabels(row)
138 int row;
139 {
140 int i, col, regions, ndrives;
141
142 #define COLWIDTH 14
143 #define DRIVESPERLINE ((getmaxx(wnd) - INSET) / COLWIDTH)
144 for (ndrives = 0, i = 0; i < dk_ndrive; i++)
145 if (cur.dk_select[i])
146 ndrives++;
147 regions = howmany(ndrives, DRIVESPERLINE);
148 /*
149 * Deduct -regions for blank line after each scrolling region.
150 */
151 linesperregion = (getmaxy(wnd) - row - regions) / regions;
152 /*
153 * Minimum region contains space for two
154 * label lines and one line of statistics.
155 */
156 if (linesperregion < 3)
157 linesperregion = 3;
158 col = 0;
159 for (i = 0; i < dk_ndrive; i++)
160 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
161 if (col + COLWIDTH >= getmaxx(wnd) - INSET) {
162 col = 0, row += linesperregion + 1;
163 if (row > getmaxy(wnd) - (linesperregion + 1))
164 break;
165 }
166 mvwaddstr(wnd, row, col + 4, cur.dk_name[i]);
167 mvwaddstr(wnd, row + 1, col, "KBps tps sec");
168 col += COLWIDTH;
169 }
170 if (col)
171 row += linesperregion + 1;
172 return (row);
173 }
174
175 static int
176 barlabels(row)
177 int row;
178 {
179 int i;
180
181 mvwaddstr(wnd, row++, INSET,
182 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
183 linesperregion = 2 + secs;
184 for (i = 0; i < dk_ndrive; i++)
185 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
186 if (row > getmaxy(wnd) - linesperregion)
187 break;
188 mvwprintw(wnd, row++, 0, "%7.7s KBps|", cur.dk_name[i]);
189 mvwaddstr(wnd, row++, 0, " tps|");
190 if (secs)
191 mvwaddstr(wnd, row++, 0, " msec|");
192 }
193 return (row);
194 }
195
196
197 void
198 showiostat()
199 {
200 int i, row, col;
201
202 if (dk_ndrive == 0)
203 return;
204 dkswap();
205
206 etime = 0;
207 for(i = 0; i < CPUSTATES; i++) {
208 etime += cur.cp_time[i];
209 }
210 if (etime == 0.0)
211 etime = 1.0;
212 etime /= (float) hz;
213 row = 1;
214
215 /*
216 * Interrupt CPU state not calculated yet.
217 */
218 for (i = 0; i < CPUSTATES; i++)
219 stat1(row++, i);
220 if (!numbers) {
221 row += 2;
222 for (i = 0; i < dk_ndrive; i++)
223 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
224 if (row > getmaxy(wnd) - linesperregion)
225 break;
226 row = stats(row, INSET, i);
227 }
228 return;
229 }
230 col = 0;
231 wmove(wnd, row + linesperregion, 0);
232 wdeleteln(wnd);
233 wmove(wnd, row + 3, 0);
234 winsertln(wnd);
235 for (i = 0; i < dk_ndrive; i++)
236 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
237 if (col + COLWIDTH >= getmaxx(wnd)) {
238 col = 0, row += linesperregion + 1;
239 if (row > getmaxy(wnd) - (linesperregion + 1))
240 break;
241 wmove(wnd, row + linesperregion, 0);
242 wdeleteln(wnd);
243 wmove(wnd, row + 3, 0);
244 winsertln(wnd);
245 }
246 (void) stats(row + 3, col, i);
247 col += COLWIDTH;
248 }
249 }
250
251 static int
252 stats(row, col, dn)
253 int row, col, dn;
254 {
255 double atime, words;
256
257 /* time busy in disk activity */
258 atime = (double)cur.dk_time[dn].tv_sec +
259 ((double)cur.dk_time[dn].tv_usec / (double)1000000);
260
261 words = cur.dk_bytes[dn] / 1024.0; /* # of K transferred */
262 if (numbers) {
263 mvwprintw(wnd, row, col, " %3.0f%4.0f%5.1f",
264 words / etime, cur.dk_xfer[dn] / etime, atime / etime);
265 return (row);
266 }
267 wmove(wnd, row++, col);
268 histogram(words / etime, 50, 0.5);
269 wmove(wnd, row++, col);
270 histogram(cur.dk_xfer[dn] / etime, 50, 0.5);
271 if (secs) {
272 wmove(wnd, row++, col);
273 atime *= 1000; /* In milliseconds */
274 histogram(atime / etime, 50, 0.5);
275 }
276 return (row);
277 }
278
279 static void
280 stat1(row, o)
281 int row, o;
282 {
283 int i;
284 double time;
285
286 time = 0;
287 for (i = 0; i < CPUSTATES; i++)
288 time += cur.cp_time[i];
289 if (time == 0.0)
290 time = 1.0;
291 wmove(wnd, row, INSET);
292 #define CPUSCALE 0.5
293 histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE);
294 }
295
296 static void
297 histogram(val, colwidth, scale)
298 double val;
299 int colwidth;
300 double scale;
301 {
302 char buf[10];
303 int k;
304 int v = (int)(val * scale) + 0.5;
305
306 k = MIN(v, colwidth);
307 if (v > colwidth) {
308 snprintf(buf, sizeof buf, "%4.1f", val);
309 k -= strlen(buf);
310 while (k--)
311 waddch(wnd, 'X');
312 waddstr(wnd, buf);
313 wclrtoeol(wnd);
314 return;
315 }
316 wclrtoeol(wnd);
317 whline(wnd, 'X', k);
318 }
319
320 void
321 iostat_bars (args)
322 char *args;
323 {
324 numbers = 0;
325 wclear(wnd);
326 labeliostat();
327 refresh();
328 }
329
330 void
331 iostat_numbers (args)
332 char *args;
333 {
334 numbers = 1;
335 wclear(wnd);
336 labeliostat();
337 refresh();
338 }
339
340 void
341 iostat_secs (args)
342 char *args;
343 {
344 secs = !secs;
345 wclear(wnd);
346 labeliostat();
347 refresh();
348 }
349