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