]> git.saurik.com Git - apple/system_cmds.git/blame - iostat.tproj/iostat.c
system_cmds-175.tar.gz
[apple/system_cmds.git] / iostat.tproj / iostat.c
CommitLineData
1815bff5
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*-
25 * Copyright (c) 1986, 1991, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57#ifndef lint
58static char copyright[] =
59"@(#) Copyright (c) 1986, 1991, 1993\n\
60 The Regents of the University of California. All rights reserved.\n";
61#endif /* not lint */
62
63#ifndef lint
64static char sccsid[] = "@(#)iostat.c 8.3 (Berkeley) 4/28/95";
65#endif /* not lint */
66
67#include <sys/param.h>
68#include <sys/buf.h>
69#include <sys/dkstat.h>
70
71#include <err.h>
72#include <ctype.h>
73#include <fcntl.h>
74#include <kvm.h>
75#include <limits.h>
76#include <nlist.h>
77#include <paths.h>
78#include <signal.h>
79#include <stdio.h>
80#include <stdlib.h>
81#include <string.h>
82#include <unistd.h>
83
84struct nlist namelist[] = {
85#define X_DK_TIME 0
86 { "_dk_time" },
87#define X_DK_XFER 1
88 { "_dk_xfer" },
89#define X_DK_WDS 2
90 { "_dk_wds" },
91#define X_TK_NIN 3
92 { "_tk_nin" },
93#define X_TK_NOUT 4
94 { "_tk_nout" },
95#define X_DK_SEEK 5
96 { "_dk_seek" },
97#define X_CP_TIME 6
98 { "_cp_time" },
99#define X_DK_WPMS 7
100 { "_dk_wpms" },
101#define X_HZ 8
102 { "_hz" },
103#define X_STATHZ 9
104 { "_stathz" },
105#define X_DK_NDRIVE 10
106 { "_dk_ndrive" },
107#define X_END 10
108#if defined(hp300) || defined(luna68k)
109#define X_HPDINIT (X_END+1)
110 { "_hp_dinit" },
111#endif
112#ifdef mips
113#define X_SCSI_DINIT (X_END+1)
114 { "_scsi_dinit" },
115#endif
116#ifdef tahoe
117#define X_VBDINIT (X_END+1)
118 { "_vbdinit" },
119#endif
120#ifdef vax
121 { "_mbdinit" },
122#define X_MBDINIT (X_END+1)
123 { "_ubdinit" },
124#define X_UBDINIT (X_END+2)
125#endif
126 { NULL },
127};
128
129struct _disk {
130 long cp_time[CPUSTATES];
131 long *dk_time;
132 long *dk_wds;
133 long *dk_seek;
134 long *dk_xfer;
135 long tk_nin;
136 long tk_nout;
137} cur, last;
138
139kvm_t *kd;
140double etime;
141long *dk_wpms;
142int dk_ndrive, *dr_select, hz, kmemfd, ndrives;
143char **dr_name;
144
145#define nlread(x, v) \
146 kvm_read(kd, namelist[x].n_value, &(v), sizeof(v))
147
148#include "names.c" /* XXX */
149
150void cpustats __P((void));
151void dkstats __P((void));
152void phdr __P((int));
153void usage __P((void));
154
155int
156main(argc, argv)
157 int argc;
158 char *argv[];
159{
160 register int i;
161 long tmp;
162 int ch, hdrcnt, reps, interval, stathz, ndrives;
163 char **cp, *memf, *nlistf, buf[30];
164 char errbuf[_POSIX2_LINE_MAX];
165
166 interval = reps = 0;
167 nlistf = memf = NULL;
168 while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF)
169 switch(ch) {
170 case 'c':
171 if ((reps = atoi(optarg)) <= 0)
172 errx(1, "repetition count <= 0.");
173 break;
174 case 'M':
175 memf = optarg;
176 break;
177 case 'N':
178 nlistf = optarg;
179 break;
180 case 'w':
181 if ((interval = atoi(optarg)) <= 0)
182 errx(1, "interval <= 0.");
183 break;
184 case '?':
185 default:
186 usage();
187 }
188 argc -= optind;
189 argv += optind;
190
191 /*
192 * Discard setgid privileges if not the running kernel so that bad
193 * guys can't print interesting stuff from kernel memory.
194 */
195 if (nlistf != NULL || memf != NULL)
196 setgid(getgid());
197
198 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
199 if (kd == 0)
200 errx(1, "kvm_openfiles: %s", errbuf);
201 if (kvm_nlist(kd, namelist) == -1)
202 errx(1, "kvm_nlist: %s", kvm_geterr(kd));
203 if (namelist[X_DK_NDRIVE].n_type == 0)
204 errx(1, "dk_ndrive not found in namelist");
205 (void)nlread(X_DK_NDRIVE, dk_ndrive);
206 if (dk_ndrive <= 0)
207 errx(1, "invalid dk_ndrive %d\n", dk_ndrive);
208
209 cur.dk_time = calloc(dk_ndrive, sizeof(long));
210 cur.dk_wds = calloc(dk_ndrive, sizeof(long));
211 cur.dk_seek = calloc(dk_ndrive, sizeof(long));
212 cur.dk_xfer = calloc(dk_ndrive, sizeof(long));
213 last.dk_time = calloc(dk_ndrive, sizeof(long));
214 last.dk_wds = calloc(dk_ndrive, sizeof(long));
215 last.dk_seek = calloc(dk_ndrive, sizeof(long));
216 last.dk_xfer = calloc(dk_ndrive, sizeof(long));
217 dr_select = calloc(dk_ndrive, sizeof(int));
218 dr_name = calloc(dk_ndrive, sizeof(char *));
219 dk_wpms = calloc(dk_ndrive, sizeof(long));
220
221 for (i = 0; i < dk_ndrive; i++) {
222 (void)sprintf(buf, "dk%d", i);
223 dr_name[i] = strdup(buf);
224 }
225 if (!read_names())
226 exit(1);
227 (void)nlread(X_HZ, hz);
228 (void)nlread(X_STATHZ, stathz);
229 if (stathz)
230 hz = stathz;
231 (void)kvm_read(kd, namelist[X_DK_WPMS].n_value, dk_wpms,
232 dk_ndrive * sizeof(dk_wpms));
233
234 /*
235 * Choose drives to be displayed. Priority goes to (in order) drives
236 * supplied as arguments and default drives. If everything isn't
237 * filled in and there are drives not taken care of, display the first
238 * few that fit.
239 *
240 * The backward compatibility #ifdefs permit the syntax:
241 * iostat [ drives ] [ interval [ count ] ]
242 */
243#define BACKWARD_COMPATIBILITY
244 for (ndrives = 0; *argv; ++argv) {
245#ifdef BACKWARD_COMPATIBILITY
246 if (isdigit(**argv))
247 break;
248#endif
249 for (i = 0; i < dk_ndrive; i++) {
250 if (strcmp(dr_name[i], *argv))
251 continue;
252 dr_select[i] = 1;
253 ++ndrives;
254 }
255 }
256#ifdef BACKWARD_COMPATIBILITY
257 if (*argv) {
258 interval = atoi(*argv);
259 if (*++argv)
260 reps = atoi(*argv);
261 }
262#endif
263
264 if (interval) {
265 if (!reps)
266 reps = -1;
267 } else
268 if (reps)
269 interval = 1;
270
271 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
272 if (dr_select[i] || dk_wpms[i] == 0)
273 continue;
274 for (cp = defdrives; *cp; cp++)
275 if (strcmp(dr_name[i], *cp) == 0) {
276 dr_select[i] = 1;
277 ++ndrives;
278 break;
279 }
280 }
281 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
282 if (dr_select[i])
283 continue;
284 dr_select[i] = 1;
285 ++ndrives;
286 }
287
288 (void)signal(SIGCONT, phdr);
289
290 for (hdrcnt = 1;;) {
291 if (!--hdrcnt) {
292 phdr(0);
293 hdrcnt = 20;
294 }
295 (void)kvm_read(kd, namelist[X_DK_TIME].n_value,
296 cur.dk_time, dk_ndrive * sizeof(long));
297 (void)kvm_read(kd, namelist[X_DK_XFER].n_value,
298 cur.dk_xfer, dk_ndrive * sizeof(long));
299 (void)kvm_read(kd, namelist[X_DK_WDS].n_value,
300 cur.dk_wds, dk_ndrive * sizeof(long));
301 (void)kvm_read(kd, namelist[X_DK_SEEK].n_value,
302 cur.dk_seek, dk_ndrive * sizeof(long));
303 (void)kvm_read(kd, namelist[X_TK_NIN].n_value,
304 &cur.tk_nin, sizeof(cur.tk_nin));
305 (void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
306 &cur.tk_nout, sizeof(cur.tk_nout));
307 (void)kvm_read(kd, namelist[X_CP_TIME].n_value,
308 cur.cp_time, sizeof(cur.cp_time));
309 for (i = 0; i < dk_ndrive; i++) {
310 if (!dr_select[i])
311 continue;
312#define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp
313 X(dk_xfer);
314 X(dk_seek);
315 X(dk_wds);
316 X(dk_time);
317 }
318 tmp = cur.tk_nin;
319 cur.tk_nin -= last.tk_nin;
320 last.tk_nin = tmp;
321 tmp = cur.tk_nout;
322 cur.tk_nout -= last.tk_nout;
323 last.tk_nout = tmp;
324 etime = 0;
325 for (i = 0; i < CPUSTATES; i++) {
326 X(cp_time);
327 etime += cur.cp_time[i];
328 }
329 if (etime == 0.0)
330 etime = 1.0;
331 etime /= (float)hz;
332 (void)printf("%4.0f%5.0f",
333 cur.tk_nin / etime, cur.tk_nout / etime);
334 dkstats();
335 cpustats();
336 (void)printf("\n");
337 (void)fflush(stdout);
338
339 if (reps >= 0 && --reps <= 0)
340 break;
341 (void)sleep(interval);
342 }
343 exit(0);
344}
345
346/* ARGUSED */
347void
348phdr(signo)
349 int signo;
350{
351 register int i;
352
353 (void)printf(" tty");
354 for (i = 0; i < dk_ndrive; i++)
355 if (dr_select[i])
356 (void)printf(" %3.3s ", dr_name[i]);
357 (void)printf(" cpu\n tin tout");
358 for (i = 0; i < dk_ndrive; i++)
359 if (dr_select[i])
360 (void)printf(" sps tps msps ");
361 (void)printf(" us ni sy in id\n");
362}
363
364void
365dkstats()
366{
367 register int dn;
368 double atime, itime, msps, words, xtime;
369
370 for (dn = 0; dn < dk_ndrive; ++dn) {
371 if (!dr_select[dn])
372 continue;
373 words = cur.dk_wds[dn] * 32; /* words xfer'd */
374 (void)printf("%4.0f", /* sectors */
375 words / (DEV_BSIZE / 2) / etime);
376
377 (void)printf("%4.0f", cur.dk_xfer[dn] / etime);
378
379 if (dk_wpms[dn] && cur.dk_xfer[dn]) {
380 atime = cur.dk_time[dn]; /* ticks disk busy */
381 atime /= (float)hz; /* ticks to seconds */
382 xtime = words / dk_wpms[dn]; /* transfer time */
383 itime = atime - xtime; /* time not xfer'ing */
384 if (itime < 0)
385 msps = 0;
386 else
387 msps = itime * 1000 / cur.dk_xfer[dn];
388 } else
389 msps = 0;
390 (void)printf("%5.1f ", msps);
391 }
392}
393
394void
395cpustats()
396{
397 register int state;
398 double time;
399
400 time = 0;
401 for (state = 0; state < CPUSTATES; ++state)
402 time += cur.cp_time[state];
403 for (state = 0; state < CPUSTATES; ++state)
404 (void)printf("%3.0f",
405 100. * cur.cp_time[state] / (time ? time : 1));
406}
407
408void
409usage()
410{
411 (void)fprintf(stderr,
412"usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n");
413 exit(1);
414}