2 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
6 * Copyright (c) 1980 Regents of the University of California.
7 * All rights reserved. The Berkeley software License Agreement
8 * specifies the terms and conditions for redistribution.
11 /* from UCB 5.4 5/17/86 */
12 /* from SunOS 4.1, SID 1.31 */
28 #include "statcommon.h"
30 char *cmdname
= "vmstat";
33 static uint_t timestamp_fmt
= NODATE
;
39 static int swflag
= 0, pflag
= 0;
40 static int suppress_state
;
42 static hrtime_t period_n
= 0;
43 static struct snapshot
*ss
;
45 struct iodev_filter df
;
47 #define pgtok(a) ((a) * (pagesize >> 10))
48 #define denom(x) ((x) ? (x) : 1)
51 static void dovmstats(struct snapshot
*old
, struct snapshot
*new);
52 static void printhdr(int);
53 static void dosum(struct sys_snapshot
*ss
);
54 static void dointr(struct snapshot
*ss
);
55 static void usage(void);
58 main(int argc
, char **argv
)
60 struct snapshot
*old
= NULL
;
61 enum snapshot_types types
= SNAP_SYSTEM
;
69 (void) setlocale(LC_ALL
, "");
70 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
71 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
73 (void) textdomain(TEXT_DOMAIN
);
75 pagesize
= sysconf(_SC_PAGESIZE
);
76 hz
= sysconf(_SC_CLK_TCK
);
78 while ((c
= getopt(argc
, argv
, "ipqsST:")) != EOF
)
93 pflag
++; /* detailed paging info */
98 timestamp_fmt
= UDATE
;
99 else if (*optarg
== 'd')
100 timestamp_fmt
= DDATE
;
114 /* consistency with iostat */
118 types
|= SNAP_INTERRUPTS
;
120 types
|= SNAP_IODEVS
;
122 /* max to fit in less than 80 characters */
123 df
.if_max_iodevs
= 4;
124 df
.if_allowed_types
= IODEV_DISK
;
126 df
.if_names
= safe_alloc(df
.if_max_iodevs
* sizeof (char *));
127 (void) memset(df
.if_names
, 0, df
.if_max_iodevs
* sizeof (char *));
129 while (argc
> 0 && !isdigit(argv
[0][0]) &&
130 df
.if_nr_names
< df
.if_max_iodevs
) {
131 df
.if_names
[df
.if_nr_names
] = *argv
;
138 start_n
= gethrtime();
140 ss
= acquire_snapshot(kc
, types
, &df
);
142 /* time, in seconds, since boot */
143 etime
= ss
->s_sys
.ss_ticks
/ hz
;
161 interval
= strtol(argv
[0], &endptr
, 10);
163 if (errno
> 0 || *endptr
!= '\0' || interval
<= 0 ||
166 period_n
= (hrtime_t
)interval
* NANOSEC
;
171 iter
= strtol(argv
[1], NULL
, 10);
172 if (errno
> 0 || *endptr
!= '\0' || iter
<= 0)
180 (void) sigset(SIGCONT
, printhdr
);
183 while (forever
|| --iter
> 0) {
184 /* (void) poll(NULL, 0, poll_interval); */
187 sleep_until(&start_n
, period_n
, forever
, &caught_cont
);
191 ss
= acquire_snapshot(kc
, types
, &df
);
194 snapshot_report_changes(old
, ss
);
196 /* if config changed, show stats from boot */
197 if (snapshot_has_changed(old
, ss
)) {
208 (void) kstat_close(kc
);
212 #define DELTA(v) (new->v - (old ? old->v : 0))
213 #define ADJ(n) ((adj <= 0) ? n : (adj >= n) ? 1 : n - adj)
214 #define adjprintf(fmt, n, val) adj -= (n + 1) - printf(fmt, ADJ(n), val)
216 static int adj
; /* number of excess columns */
220 show_disk(void *v1
, void *v2
, void *d
)
222 struct iodev_snapshot
*old
= (struct iodev_snapshot
*)v1
;
223 struct iodev_snapshot
*new = (struct iodev_snapshot
*)v2
;
224 hrtime_t oldtime
= new->is_crtime
;
226 double reads
, writes
;
232 oldtime
= old
->is_stats
.wlastupdate
;
233 hr_etime
= new->is_stats
.wlastupdate
- oldtime
;
236 reads
= new->is_stats
.reads
- (old
? old
->is_stats
.reads
: 0);
237 writes
= new->is_stats
.writes
- (old
? old
->is_stats
.writes
: 0);
238 adjprintf(" %*.0f", 2, (reads
+ writes
) / hr_etime
* NANOSEC
);
242 dovmstats(struct snapshot
*old
, struct snapshot
*new)
244 kstat_t
*oldsys
= NULL
;
245 kstat_t
*newsys
= &new->s_sys
.ss_agg_sys
;
246 kstat_t
*oldvm
= NULL
;
247 kstat_t
*newvm
= &new->s_sys
.ss_agg_vm
;
248 double percent_factor
;
249 ulong_t sys_updates
, vm_updates
;
255 oldsys
= &old
->s_sys
.ss_agg_sys
;
256 oldvm
= &old
->s_sys
.ss_agg_vm
;
259 etime
= cpu_ticks_delta(oldsys
, newsys
);
261 percent_factor
= 100.0 / denom(etime
);
263 * If any time has passed, convert etime to seconds per CPU
265 etime
= etime
>= 1.0 ? (etime
/ nr_active_cpus(new)) / hz
: 1.0;
266 sys_updates
= denom(DELTA(s_sys
.ss_sysinfo
.updates
));
267 vm_updates
= denom(DELTA(s_sys
.ss_vminfo
.updates
));
269 if (timestamp_fmt
!= NODATE
) {
270 print_timestamp(timestamp_fmt
);
281 pgtok((int)(DELTA(s_sys
.ss_vminfo
.swap_avail
)
284 pgtok((int)(DELTA(s_sys
.ss_vminfo
.freemem
) / vm_updates
)));
285 adjprintf(" %*.0f", 3, kstat_delta(oldvm
, newvm
, "pgrec")
287 adjprintf(" %*.0f", 3, (kstat_delta(oldvm
, newvm
, "hat_fault") +
288 kstat_delta(oldvm
, newvm
, "as_fault")) / etime
);
289 adjprintf(" %*.0f", 3, pgtok(kstat_delta(oldvm
, newvm
, "dfree"))
291 adjprintf(" %*ld", 3, pgtok(new->s_sys
.ss_deficit
));
292 adjprintf(" %*.0f", 3, kstat_delta(oldvm
, newvm
, "scan")
294 adjprintf(" %*.0f", 4,
295 pgtok(kstat_delta(oldvm
, newvm
, "execpgin")) / etime
);
296 adjprintf(" %*.0f", 4,
297 pgtok(kstat_delta(oldvm
, newvm
, "execpgout")) / etime
);
298 adjprintf(" %*.0f", 4,
299 pgtok(kstat_delta(oldvm
, newvm
, "execfree")) / etime
);
300 adjprintf(" %*.0f", 4,
301 pgtok(kstat_delta(oldvm
, newvm
, "anonpgin")) / etime
);
302 adjprintf(" %*.0f", 4,
303 pgtok(kstat_delta(oldvm
, newvm
, "anonpgout")) / etime
);
304 adjprintf(" %*.0f", 4,
305 pgtok(kstat_delta(oldvm
, newvm
, "anonfree")) / etime
);
306 adjprintf(" %*.0f", 4,
307 pgtok(kstat_delta(oldvm
, newvm
, "fspgin")) / etime
);
308 adjprintf(" %*.0f", 4,
309 pgtok(kstat_delta(oldvm
, newvm
, "fspgout")) / etime
);
310 adjprintf(" %*.0f\n", 4,
311 pgtok(kstat_delta(oldvm
, newvm
, "fsfree")) / etime
);
312 (void) fflush(stdout
);
316 adjprintf(" %*lu", 1, DELTA(s_sys
.ss_sysinfo
.runque
) / sys_updates
);
317 adjprintf(" %*lu", 1, DELTA(s_sys
.ss_sysinfo
.waiting
) / sys_updates
);
318 adjprintf(" %*lu", 1, DELTA(s_sys
.ss_sysinfo
.swpque
) / sys_updates
);
319 adjprintf(" %*u", 6, pgtok((int)(DELTA(s_sys
.ss_vminfo
.swap_avail
)
321 adjprintf(" %*u", 5, pgtok((int)(DELTA(s_sys
.ss_vminfo
.freemem
)
323 adjprintf(" %*.0f", 3, swflag
?
324 kstat_delta(oldvm
, newvm
, "swapin") / etime
:
325 kstat_delta(oldvm
, newvm
, "pgrec") / etime
);
326 adjprintf(" %*.0f", 3, swflag
?
327 kstat_delta(oldvm
, newvm
, "swapout") / etime
:
328 (kstat_delta(oldvm
, newvm
, "hat_fault")
329 + kstat_delta(oldvm
, newvm
, "as_fault"))
331 adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm
, newvm
, "pgpgin"))
333 adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm
, newvm
, "pgpgout"))
335 adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm
, newvm
, "dfree"))
337 adjprintf(" %*ld", 2, pgtok(new->s_sys
.ss_deficit
));
338 adjprintf(" %*.0f", 2, kstat_delta(oldvm
, newvm
, "scan") / etime
);
340 (void) snapshot_walk(SNAP_IODEVS
, old
, new, show_disk
, NULL
);
342 count
= df
.if_max_iodevs
- new->s_nr_iodevs
;
344 adjprintf(" %*d", 2, 0);
346 adjprintf(" %*.0f", 4, kstat_delta(oldsys
, newsys
, "intr") / etime
);
347 adjprintf(" %*.0f", 4, kstat_delta(oldsys
, newsys
, "syscall") / etime
);
348 adjprintf(" %*.0f", 4, kstat_delta(oldsys
, newsys
, "pswitch") / etime
);
349 adjprintf(" %*.0f", 2,
350 kstat_delta(oldsys
, newsys
, "cpu_ticks_user") * percent_factor
);
351 adjprintf(" %*.0f", 2, kstat_delta(oldsys
, newsys
, "cpu_ticks_kernel")
353 adjprintf(" %*.0f\n", 2, (kstat_delta(oldsys
, newsys
, "cpu_ticks_idle")
354 + kstat_delta(oldsys
, newsys
, "cpu_ticks_wait"))
356 (void) fflush(stdout
);
361 print_disk(void *v
, void *v2
, void *d
)
363 struct iodev_snapshot
*iodev
= (struct iodev_snapshot
*)v2
;
368 (void) printf("%c%c ", iodev
->is_name
[0], iodev
->is_name
[2]);
375 int i
= df
.if_max_iodevs
- ss
->s_nr_iodevs
;
381 (void) printf(" memory page ");
382 (void) printf("executable anonymous filesystem \n");
383 (void) printf(" swap free re mf fr de sr ");
384 (void) printf("epi epo epf api apo apf fpi fpo fpf\n");
389 (void) printf(" kthr memory page ");
390 (void) printf("disk faults cpu\n");
393 (void) printf(" r b w swap free si so pi po fr de sr ");
395 (void) printf(" r b w swap free re mf pi po fr de sr ");
397 (void) snapshot_walk(SNAP_IODEVS
, NULL
, ss
, print_disk
, NULL
);
400 (void) printf("-- ");
402 (void) printf(" in sy cs us sy id\n");
407 sum_out(char const *pretty
, kstat_t
*ks
, char *name
)
409 kstat_named_t
*ksn
= kstat_data_lookup(ks
, name
);
411 fail(0, "kstat_data_lookup('%s', '%s') failed",
415 (void) printf("%9llu %s\n", ksn
->value
.ui64
, pretty
);
419 dosum(struct sys_snapshot
*ss
)
421 uint64_t total_faults
;
423 long double nchtotal
;
426 sum_out("swap ins", &ss
->ss_agg_vm
, "swapin");
427 sum_out("swap outs", &ss
->ss_agg_vm
, "swapout");
428 sum_out("pages swapped in", &ss
->ss_agg_vm
, "pgswapin");
429 sum_out("pages swapped out", &ss
->ss_agg_vm
, "pgswapout");
431 ksn
= kstat_data_lookup(&ss
->ss_agg_vm
, "hat_fault");
433 fail(0, "kstat_data_lookup('%s', 'hat_fault') failed",
434 ss
->ss_agg_vm
.ks_name
);
436 total_faults
= ksn
->value
.ui64
;
437 ksn
= kstat_data_lookup(&ss
->ss_agg_vm
, "as_fault");
439 fail(0, "kstat_data_lookup('%s', 'as_fault') failed",
440 ss
->ss_agg_vm
.ks_name
);
442 total_faults
+= ksn
->value
.ui64
;
444 (void) printf("%9llu total address trans. faults taken\n",
447 sum_out("page ins", &ss
->ss_agg_vm
, "pgin");
448 sum_out("page outs", &ss
->ss_agg_vm
, "pgout");
449 sum_out("pages paged in", &ss
->ss_agg_vm
, "pgpgin");
450 sum_out("pages paged out", &ss
->ss_agg_vm
, "pgpgout");
451 sum_out("total reclaims", &ss
->ss_agg_vm
, "pgrec");
452 sum_out("reclaims from free list", &ss
->ss_agg_vm
, "pgfrec");
453 sum_out("micro (hat) faults", &ss
->ss_agg_vm
, "hat_fault");
454 sum_out("minor (as) faults", &ss
->ss_agg_vm
, "as_fault");
455 sum_out("major faults", &ss
->ss_agg_vm
, "maj_fault");
456 sum_out("copy-on-write faults", &ss
->ss_agg_vm
, "cow_fault");
457 sum_out("zero fill page faults", &ss
->ss_agg_vm
, "zfod");
458 sum_out("pages examined by the clock daemon", &ss
->ss_agg_vm
, "scan");
459 sum_out("revolutions of the clock hand", &ss
->ss_agg_vm
, "rev");
460 sum_out("pages freed by the clock daemon", &ss
->ss_agg_vm
, "dfree");
461 sum_out("forks", &ss
->ss_agg_sys
, "sysfork");
462 sum_out("vforks", &ss
->ss_agg_sys
, "sysvfork");
463 sum_out("execs", &ss
->ss_agg_sys
, "sysexec");
464 sum_out("cpu context switches", &ss
->ss_agg_sys
, "pswitch");
465 sum_out("device interrupts", &ss
->ss_agg_sys
, "intr");
466 sum_out("traps", &ss
->ss_agg_sys
, "trap");
467 sum_out("system calls", &ss
->ss_agg_sys
, "syscall");
469 nchtotal
= (long double) ss
->ss_nc
.ncs_hits
.value
.ui64
+
470 (long double) ss
->ss_nc
.ncs_misses
.value
.ui64
;
471 nchhits
= ss
->ss_nc
.ncs_hits
.value
.ui64
;
472 (void) printf("%9.0Lf total name lookups (cache hits %.0Lf%%)\n",
473 nchtotal
, nchhits
/ denom(nchtotal
) * 100);
475 sum_out("user cpu", &ss
->ss_agg_sys
, "cpu_ticks_user");
476 sum_out("system cpu", &ss
->ss_agg_sys
, "cpu_ticks_kernel");
477 sum_out("idle cpu", &ss
->ss_agg_sys
, "cpu_ticks_idle");
478 sum_out("wait cpu", &ss
->ss_agg_sys
, "cpu_ticks_wait");
482 dointr(struct snapshot
*ss
)
487 (void) printf("interrupt total rate\n");
488 (void) printf("--------------------------------\n");
490 for (i
= 0; i
< ss
->s_nr_intrs
; i
++) {
491 (void) printf("%-12.8s %10lu %8.0f\n",
492 ss
->s_intrs
[i
].is_name
, ss
->s_intrs
[i
].is_total
,
493 ss
->s_intrs
[i
].is_total
/ etime
);
494 total
+= ss
->s_intrs
[i
].is_total
;
497 (void) printf("--------------------------------\n");
498 (void) printf("Total %10lu %8.0f\n", total
, total
/ etime
);
504 (void) fprintf(stderr
,
505 "Usage: vmstat [-ipqsS] [-T d|u] [disk ...] "
506 "[interval [count]]\n");