iostat.c revision 1.22 1 /* $NetBSD: iostat.c,v 1.22 2002/09/25 13:50:39 christos 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.22 2002/09/25 13:50:39 christos 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) - 1) / 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)) {
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 = cur.cp_etime;
194 row = 1;
195
196 /*
197 * Interrupt CPU state not calculated yet.
198 */
199 for (i = 0; i < CPUSTATES; i++)
200 stat1(row++, i);
201 if (!numbers) {
202 row += 2;
203 for (i = 0; i < dk_ndrive; i++)
204 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
205 if (row > getmaxy(wnd) - linesperregion)
206 break;
207 row = stats(row, INSET, i);
208 }
209 return;
210 }
211 col = 0;
212 wmove(wnd, row + linesperregion, 0);
213 wdeleteln(wnd);
214 wmove(wnd, row + 3, 0);
215 winsertln(wnd);
216 for (i = 0; i < dk_ndrive; i++)
217 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
218 if (col + COLWIDTH > getmaxx(wnd)) {
219 col = 0, row += linesperregion + 1;
220 if (row > getmaxy(wnd) - (linesperregion + 1))
221 break;
222 wmove(wnd, row + linesperregion, 0);
223 wdeleteln(wnd);
224 wmove(wnd, row + 3, 0);
225 winsertln(wnd);
226 }
227 (void) stats(row + 3, col, i);
228 col += COLWIDTH;
229 }
230 }
231
232 static int
233 stats(int row, int col, int dn)
234 {
235 double atime, words;
236
237 /* time busy in disk activity */
238 atime = (double)cur.dk_time[dn].tv_sec +
239 ((double)cur.dk_time[dn].tv_usec / (double)1000000);
240
241 words = cur.dk_bytes[dn] / 1024.0; /* # of k transferred */
242 if (numbers) {
243 mvwprintw(wnd, row, col, " %3.0f%4.0f%5.1f",
244 words / etime, cur.dk_xfer[dn] / etime, atime / etime);
245 return (row);
246 }
247 wmove(wnd, row++, col);
248 histogram(words / etime, 50, 0.5);
249 wmove(wnd, row++, col);
250 histogram(cur.dk_xfer[dn] / etime, 50, 0.5);
251 if (secs) {
252 wmove(wnd, row++, col);
253 atime *= 1000; /* In milliseconds */
254 histogram(atime / etime, 50, 0.5);
255 }
256 return (row);
257 }
258
259 static void
260 stat1(int row, int o)
261 {
262 int i;
263 double time;
264
265 time = 0;
266 for (i = 0; i < CPUSTATES; i++)
267 time += cur.cp_time[i];
268 if (time == 0.0)
269 time = 1.0;
270 wmove(wnd, row, INSET);
271 #define CPUSCALE 0.5
272 histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE);
273 }
274
275 static void
276 histogram(double val, int colwidth, double scale)
277 {
278 char buf[10];
279 int k;
280 int v = (int)(val * scale) + 0.5;
281
282 k = MIN(v, colwidth);
283 if (v > colwidth) {
284 snprintf(buf, sizeof buf, "%4.1f", val);
285 k -= strlen(buf);
286 while (k--)
287 waddch(wnd, 'X');
288 waddstr(wnd, buf);
289 wclrtoeol(wnd);
290 return;
291 }
292 wclrtoeol(wnd);
293 whline(wnd, 'X', k);
294 }
295
296 void
297 iostat_bars(char *args)
298 {
299 numbers = 0;
300 wclear(wnd);
301 labeliostat();
302 refresh();
303 }
304
305 void
306 iostat_numbers(char *args)
307 {
308 numbers = 1;
309 wclear(wnd);
310 labeliostat();
311 refresh();
312 }
313
314 void
315 iostat_secs(char *args)
316 {
317 secs = !secs;
318 wclear(wnd);
319 labeliostat();
320 refresh();
321 }
322