2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 1980 Regents of the University of California.
8 * All rights reserved. The Berkeley software License Agreement
9 * specifies the terms and conditions for redistribution.
12 /* from UCB 5.4 5/17/86 */
13 /* from SunOS 4.1, SID 1.31 */
29 #include "statcommon.h"
31 char *cmdname
= "vmstat";
34 extern uint_t timestamp_fmt
;
40 static int swflag
= 0, cflag
= 0, pflag
= 0;
41 static int suppress_state
;
43 static hrtime_t period_n
= 0;
44 static struct snapshot
*ss
;
46 struct iodev_filter df
;
48 #define pgtok(a) ((a) * (pagesize >> 10))
49 #define denom(x) ((x) ? (x) : 1)
52 static void dovmstats(struct snapshot
*old
, struct snapshot
*new);
53 static void printhdr(int);
54 static void dosum(struct sys_snapshot
*ss
);
55 static void dointr(struct snapshot
*ss
);
56 static void docachestats(kstat_ctl_t
*kc
, hrtime_t interval
, int forever
);
57 static void usage(void);
60 main(int argc
, char **argv
)
62 struct snapshot
*old
= NULL
;
63 enum snapshot_types types
= SNAP_SYSTEM
;
71 (void) setlocale(LC_ALL
, "");
72 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
73 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
75 (void) textdomain(TEXT_DOMAIN
);
77 pagesize
= sysconf(_SC_PAGESIZE
);
78 hz
= sysconf(_SC_CLK_TCK
);
80 while ((c
= getopt(argc
, argv
, "cipqsST:")) != EOF
)
98 pflag
++; /* detailed paging info */
103 timestamp_fmt
= UDATE
;
104 else if (*optarg
== 'd')
105 timestamp_fmt
= DDATE
;
119 /* consistency with iostat */
123 types
|= SNAP_INTERRUPTS
;
125 types
|= SNAP_FLUSHES
;
127 types
|= SNAP_IODEVS
;
129 /* max to fit in less than 80 characters */
130 df
.if_max_iodevs
= 4;
131 df
.if_allowed_types
= IODEV_DISK
;
133 df
.if_names
= safe_alloc(df
.if_max_iodevs
* sizeof (char *));
134 (void) memset(df
.if_names
, 0, df
.if_max_iodevs
* sizeof (char *));
136 while (argc
> 0 && !isdigit(argv
[0][0]) &&
137 df
.if_nr_names
< df
.if_max_iodevs
) {
138 df
.if_names
[df
.if_nr_names
] = *argv
;
145 start_n
= gethrtime();
147 ss
= acquire_snapshot(kc
, types
, &df
);
149 /* time, in seconds, since boot */
150 etime
= ss
->s_sys
.ss_ticks
/ hz
;
168 interval
= strtol(argv
[0], &endptr
, 10);
170 if (errno
> 0 || *endptr
!= '\0' || interval
<= 0 ||
173 period_n
= (hrtime_t
)interval
* NANOSEC
;
178 iter
= strtol(argv
[1], NULL
, 10);
179 if (errno
> 0 || *endptr
!= '\0' || iter
<= 0)
189 docachestats(kc
, period_n
, forever
);
193 (void) sigset(SIGCONT
, printhdr
);
196 while (forever
|| --iter
> 0) {
197 /* (void) poll(NULL, 0, poll_interval); */
200 sleep_until(&start_n
, period_n
, forever
, &caught_cont
);
204 ss
= acquire_snapshot(kc
, types
, &df
);
207 snapshot_report_changes(old
, ss
);
209 /* if config changed, show stats from boot */
210 if (snapshot_has_changed(old
, ss
)) {
221 (void) kstat_close(kc
);
225 #define DELTA(v) (new->v - (old ? old->v : 0))
226 #define ADJ(n) ((adj <= 0) ? n : (adj >= n) ? 1 : n - adj)
227 #define adjprintf(fmt, n, val) adj -= (n + 1) - printf(fmt, ADJ(n), val)
229 static int adj
; /* number of excess columns */
233 show_disk(void *v1
, void *v2
, void *d
)
235 struct iodev_snapshot
*old
= (struct iodev_snapshot
*)v1
;
236 struct iodev_snapshot
*new = (struct iodev_snapshot
*)v2
;
237 hrtime_t oldtime
= new->is_crtime
;
239 double reads
, writes
;
245 oldtime
= old
->is_stats
.wlastupdate
;
246 hr_etime
= new->is_stats
.wlastupdate
- oldtime
;
249 reads
= new->is_stats
.reads
- (old
? old
->is_stats
.reads
: 0);
250 writes
= new->is_stats
.writes
- (old
? old
->is_stats
.writes
: 0);
251 adjprintf(" %*.0f", 2, (reads
+ writes
) / hr_etime
* NANOSEC
);
255 dovmstats(struct snapshot
*old
, struct snapshot
*new)
257 kstat_t
*oldsys
= NULL
;
258 kstat_t
*newsys
= &new->s_sys
.ss_agg_sys
;
259 kstat_t
*oldvm
= NULL
;
260 kstat_t
*newvm
= &new->s_sys
.ss_agg_vm
;
261 double percent_factor
;
268 oldsys
= &old
->s_sys
.ss_agg_sys
;
269 oldvm
= &old
->s_sys
.ss_agg_vm
;
272 etime
= cpu_ticks_delta(oldsys
, newsys
);
274 percent_factor
= 100.0 / denom(etime
);
276 * If any time has passed, convert etime to seconds per CPU
278 etime
= etime
>= 1.0 ? (etime
/ nr_active_cpus(new)) / hz
: 1.0;
279 updates
= denom(DELTA(s_sys
.ss_sysinfo
.updates
));
281 if (timestamp_fmt
!= NODATE
) {
293 pgtok((int)(DELTA(s_sys
.ss_vminfo
.swap_avail
) / updates
)));
295 pgtok((int)(DELTA(s_sys
.ss_vminfo
.freemem
) / updates
)));
296 adjprintf(" %*.0f", 3, kstat_delta(oldvm
, newvm
, "pgrec")
298 adjprintf(" %*.0f", 3, (kstat_delta(oldvm
, newvm
, "hat_fault") +
299 kstat_delta(oldvm
, newvm
, "as_fault")) / etime
);
300 adjprintf(" %*.0f", 3, pgtok(kstat_delta(oldvm
, newvm
, "dfree"))
302 adjprintf(" %*ld", 3, pgtok(new->s_sys
.ss_deficit
));
303 adjprintf(" %*.0f", 3, kstat_delta(oldvm
, newvm
, "scan")
305 adjprintf(" %*.0f", 4,
306 pgtok(kstat_delta(oldvm
, newvm
, "execpgin")) / etime
);
307 adjprintf(" %*.0f", 4,
308 pgtok(kstat_delta(oldvm
, newvm
, "execpgout")) / etime
);
309 adjprintf(" %*.0f", 4,
310 pgtok(kstat_delta(oldvm
, newvm
, "execfree")) / etime
);
311 adjprintf(" %*.0f", 4,
312 pgtok(kstat_delta(oldvm
, newvm
, "anonpgin")) / etime
);
313 adjprintf(" %*.0f", 4,
314 pgtok(kstat_delta(oldvm
, newvm
, "anonpgout")) / etime
);
315 adjprintf(" %*.0f", 4,
316 pgtok(kstat_delta(oldvm
, newvm
, "anonfree")) / etime
);
317 adjprintf(" %*.0f", 4,
318 pgtok(kstat_delta(oldvm
, newvm
, "fspgin")) / etime
);
319 adjprintf(" %*.0f", 4,
320 pgtok(kstat_delta(oldvm
, newvm
, "fspgout")) / etime
);
321 adjprintf(" %*.0f\n", 4,
322 pgtok(kstat_delta(oldvm
, newvm
, "fsfree")) / etime
);
323 (void) fflush(stdout
);
327 adjprintf(" %*lu", 1, DELTA(s_sys
.ss_sysinfo
.runque
) / updates
);
328 adjprintf(" %*lu", 1, DELTA(s_sys
.ss_sysinfo
.waiting
) / updates
);
329 adjprintf(" %*lu", 1, DELTA(s_sys
.ss_sysinfo
.swpque
) / updates
);
330 adjprintf(" %*u", 6, pgtok((int)(DELTA(s_sys
.ss_vminfo
.swap_avail
)
332 adjprintf(" %*u", 5, pgtok((int)(DELTA(s_sys
.ss_vminfo
.freemem
)
334 adjprintf(" %*.0f", 3, swflag
?
335 kstat_delta(oldvm
, newvm
, "swapin") / etime
:
336 kstat_delta(oldvm
, newvm
, "pgrec") / etime
);
337 adjprintf(" %*.0f", 3, swflag
?
338 kstat_delta(oldvm
, newvm
, "swapout") / etime
:
339 (kstat_delta(oldvm
, newvm
, "hat_fault")
340 + kstat_delta(oldvm
, newvm
, "as_fault"))
342 adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm
, newvm
, "pgpgin"))
344 adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm
, newvm
, "pgpgout"))
346 adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm
, newvm
, "dfree"))
348 adjprintf(" %*ld", 2, pgtok(new->s_sys
.ss_deficit
));
349 adjprintf(" %*.0f", 2, kstat_delta(oldvm
, newvm
, "scan") / etime
);
351 (void) snapshot_walk(SNAP_IODEVS
, old
, new, show_disk
, NULL
);
353 count
= df
.if_max_iodevs
- new->s_nr_iodevs
;
355 adjprintf(" %*d", 2, 0);
357 adjprintf(" %*.0f", 4, kstat_delta(oldsys
, newsys
, "intr") / etime
);
358 adjprintf(" %*.0f", 4, kstat_delta(oldsys
, newsys
, "syscall") / etime
);
359 adjprintf(" %*.0f", 4, kstat_delta(oldsys
, newsys
, "pswitch") / etime
);
360 adjprintf(" %*.0f", 2,
361 kstat_delta(oldsys
, newsys
, "cpu_ticks_user") * percent_factor
);
362 adjprintf(" %*.0f", 2, kstat_delta(oldsys
, newsys
, "cpu_ticks_kernel")
364 adjprintf(" %*.0f\n", 2, (kstat_delta(oldsys
, newsys
, "cpu_ticks_idle")
365 + kstat_delta(oldsys
, newsys
, "cpu_ticks_wait"))
367 (void) fflush(stdout
);
372 print_disk(void *v
, void *v2
, void *d
)
374 struct iodev_snapshot
*iodev
= (struct iodev_snapshot
*)v2
;
379 (void) printf("%c%c ", iodev
->is_name
[0], iodev
->is_name
[2]);
386 int i
= df
.if_max_iodevs
- ss
->s_nr_iodevs
;
392 (void) printf(" memory page ");
393 (void) printf("executable anonymous filesystem \n");
394 (void) printf(" swap free re mf fr de sr ");
395 (void) printf("epi epo epf api apo apf fpi fpo fpf\n");
400 (void) printf(" kthr memory page ");
401 (void) printf("disk faults cpu\n");
404 (void) printf(" r b w swap free si so pi po fr de sr ");
406 (void) printf(" r b w swap free re mf pi po fr de sr ");
408 (void) snapshot_walk(SNAP_IODEVS
, NULL
, ss
, print_disk
, NULL
);
411 (void) printf("-- ");
413 (void) printf(" in sy cs us sy id\n");
418 sum_out(char const *pretty
, kstat_t
*ks
, char *name
)
420 kstat_named_t
*ksn
= kstat_data_lookup(ks
, name
);
422 fail(0, "kstat_data_lookup('%s', '%s') failed",
426 (void) printf("%9llu %s\n", ksn
->value
.ui64
, pretty
);
430 dosum(struct sys_snapshot
*ss
)
432 uint64_t total_faults
;
434 long double nchtotal
;
437 sum_out("swap ins", &ss
->ss_agg_vm
, "swapin");
438 sum_out("swap outs", &ss
->ss_agg_vm
, "swapout");
439 sum_out("pages swapped in", &ss
->ss_agg_vm
, "pgswapin");
440 sum_out("pages swapped out", &ss
->ss_agg_vm
, "pgswapout");
442 ksn
= kstat_data_lookup(&ss
->ss_agg_vm
, "hat_fault");
444 fail(0, "kstat_data_lookup('%s', 'hat_fault') failed",
445 ss
->ss_agg_vm
.ks_name
);
447 total_faults
= ksn
->value
.ui64
;
448 ksn
= kstat_data_lookup(&ss
->ss_agg_vm
, "as_fault");
450 fail(0, "kstat_data_lookup('%s', 'as_fault') failed",
451 ss
->ss_agg_vm
.ks_name
);
453 total_faults
+= ksn
->value
.ui64
;
455 (void) printf("%9llu total address trans. faults taken\n",
458 sum_out("page ins", &ss
->ss_agg_vm
, "pgin");
459 sum_out("page outs", &ss
->ss_agg_vm
, "pgout");
460 sum_out("pages paged in", &ss
->ss_agg_vm
, "pgpgin");
461 sum_out("pages paged out", &ss
->ss_agg_vm
, "pgpgout");
462 sum_out("total reclaims", &ss
->ss_agg_vm
, "pgrec");
463 sum_out("reclaims from free list", &ss
->ss_agg_vm
, "pgfrec");
464 sum_out("micro (hat) faults", &ss
->ss_agg_vm
, "hat_fault");
465 sum_out("minor (as) faults", &ss
->ss_agg_vm
, "as_fault");
466 sum_out("major faults", &ss
->ss_agg_vm
, "maj_fault");
467 sum_out("copy-on-write faults", &ss
->ss_agg_vm
, "cow_fault");
468 sum_out("zero fill page faults", &ss
->ss_agg_vm
, "zfod");
469 sum_out("pages examined by the clock daemon", &ss
->ss_agg_vm
, "scan");
470 sum_out("revolutions of the clock hand", &ss
->ss_agg_vm
, "rev");
471 sum_out("pages freed by the clock daemon", &ss
->ss_agg_vm
, "dfree");
472 sum_out("forks", &ss
->ss_agg_sys
, "sysfork");
473 sum_out("vforks", &ss
->ss_agg_sys
, "sysvfork");
474 sum_out("execs", &ss
->ss_agg_sys
, "sysexec");
475 sum_out("cpu context switches", &ss
->ss_agg_sys
, "pswitch");
476 sum_out("device interrupts", &ss
->ss_agg_sys
, "intr");
477 sum_out("traps", &ss
->ss_agg_sys
, "trap");
478 sum_out("system calls", &ss
->ss_agg_sys
, "syscall");
480 nchtotal
= (long double) ss
->ss_nc
.ncs_hits
.value
.ui64
+
481 (long double) ss
->ss_nc
.ncs_misses
.value
.ui64
;
482 nchhits
= ss
->ss_nc
.ncs_hits
.value
.ui64
;
483 (void) printf("%9.0Lf total name lookups (cache hits %.0Lf%%)\n",
484 nchtotal
, nchhits
/ denom(nchtotal
) * 100);
486 sum_out("user cpu", &ss
->ss_agg_sys
, "cpu_ticks_user");
487 sum_out("system cpu", &ss
->ss_agg_sys
, "cpu_ticks_kernel");
488 sum_out("idle cpu", &ss
->ss_agg_sys
, "cpu_ticks_idle");
489 sum_out("wait cpu", &ss
->ss_agg_sys
, "cpu_ticks_wait");
493 dointr(struct snapshot
*ss
)
498 (void) printf("interrupt total rate\n");
499 (void) printf("--------------------------------\n");
501 for (i
= 0; i
< ss
->s_nr_intrs
; i
++) {
502 (void) printf("%-12.8s %10lu %8.0f\n",
503 ss
->s_intrs
[i
].is_name
, ss
->s_intrs
[i
].is_total
,
504 ss
->s_intrs
[i
].is_total
/ etime
);
505 total
+= ss
->s_intrs
[i
].is_total
;
508 (void) printf("--------------------------------\n");
509 (void) printf("Total %10lu %8.0f\n", total
, total
/ etime
);
513 docachestats(kstat_ctl_t
*kc
, hrtime_t interval
, int forever
)
515 struct snapshot
*old
;
516 struct snapshot
*new;
521 old
= acquire_snapshot(kc
, SNAP_FLUSHES
, NULL
);
524 (void) printf("flush statistics: (totals)\n");
525 (void) printf("%8s%8s%8s%8s%8s%8s\n",
526 "usr", "ctx", "rgn", "seg", "pag", "par");
527 (void) printf(" %7d %7d %7d %7d %7d %7d\n",
528 old
->s_flushes
.f_usr
, old
->s_flushes
.f_ctx
,
529 old
->s_flushes
.f_region
, old
->s_flushes
.f_segment
,
530 old
->s_flushes
.f_page
, old
->s_flushes
.f_partial
);
534 (void) printf("flush statistics: (interval based)\n");
535 for (i
= 0; i
< iter
; i
++) {
536 if (i
% REPRINT
== 0)
537 (void) printf("%8s%8s%8s%8s%8s%8s\n",
538 "usr", "ctx", "rgn", "seg", "pag", "par");
541 sleep_until(&start
, interval
, forever
, &caught_cont
);
543 new = acquire_snapshot(kc
, SNAP_FLUSHES
, NULL
);
545 (void) printf(" %7d %7d %7d %7d %7d %7d\n",
546 new->s_flushes
.f_usr
- old
->s_flushes
.f_usr
,
547 new->s_flushes
.f_ctx
- old
->s_flushes
.f_ctx
,
548 new->s_flushes
.f_region
- old
->s_flushes
.f_region
,
549 new->s_flushes
.f_segment
- old
->s_flushes
.f_segment
,
550 new->s_flushes
.f_page
- old
->s_flushes
.f_page
,
551 new->s_flushes
.f_partial
- old
->s_flushes
.f_partial
);
552 (void) fflush(stdout
);
561 (void) fprintf(stderr
,
562 "Usage: vmstat [-cipqsS] [-T d|u] [disk ...] "
563 "[interval [count]]\n");