* Copyright (c) 1980, 1986, 1991 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
"@(#) Copyright (c) 1980, 1986, 1991 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)vmstat.c 5.31 (Berkeley) 7/2/91";
#include <vm/vm_statistics.h>
#define NEWVM /* XXX till old has been updated or purged */
{ "_cnt" }, /* XXX for now that's where it is */
#define X_HPDINIT (X_END+1)
#define X_VBDINIT (X_END+1)
#define X_CKEYSTATS (X_END+2)
#define X_DKEYSTATS (X_END+3)
#define X_MBDINIT (X_END+1)
#define X_UBDINIT (X_END+2)
{ "_vm_page_free_count" },
#define X_ACTIVE (X_END+2)
{ "_vm_page_active_count" },
#define X_INACTIVE (X_END+3)
{ "_vm_page_inactive_count" },
#define X_WIRED (X_END+4)
{ "_vm_page_wire_count" },
#define X_PAGESIZE (X_END+5)
#define X_ISA_BIO (X_END+6)
struct vm_statistics vm_stat
, ostat
;
struct vmmeter sum
, osum
;
char *vmunix
= _PATH_UNIX
;
int *dr_select
, dk_ndrive
, ndrives
;
/* to make up for statistics that don't get updated */
int size
, free_count
, active_count
, inactive
, wired
;
#include "names.c" /* disk names -- machine dependent */
void cpustats(), dkstats(), dointr(), domem(), dosum();
void dovmstat(), kread(), usage();
void dotimes(), doforkst();
interval
= reps
= todo
= 0;
while ((c
= getopt(argc
, argv
, "c:fiM:mN:stw:")) != EOF
) {
if (kvm_openfiles(vmunix
, kmem
, NULL
) < 0) {
"vmstat: kvm_openfiles: %s\n", kvm_geterr());
if ((c
= kvm_nlist(nl
)) != 0) {
"vmstat: undefined symbols in %s:", vmunix
);
for (c
= 0; c
< sizeof(nl
)/sizeof(nl
[0]); c
++)
fprintf(stderr
, " %s", nl
[c
].n_name
);
(void)fputc('\n', stderr
);
(void)fprintf(stderr
, "vmstat: kvm_nlist: %s\n",
argv
= getdrivedata(argv
);
(void) ioctl(STDOUT_FILENO
, TIOCGWINSZ
, (char *)&winsize
);
winlines
= winsize
.ws_row
;
#define BACKWARD_COMPATIBILITY
#ifdef BACKWARD_COMPATIBILITY
dovmstat(interval
, reps
);
kread(X_DK_NDRIVE
, &dk_ndrive
, sizeof(dk_ndrive
));
(void)fprintf(stderr
, "vmstat: dk_ndrive %d\n", dk_ndrive
);
dr_select
= calloc((size_t)dk_ndrive
, sizeof(int));
dr_name
= calloc((size_t)dk_ndrive
, sizeof(char *));
for (i
= 0; i
< dk_ndrive
; i
++)
cur
.xfer
= calloc((size_t)dk_ndrive
, sizeof(long));
last
.xfer
= calloc((size_t)dk_ndrive
, sizeof(long));
for (i
= 0; i
< dk_ndrive
; i
++)
if (dr_name
[i
] == NULL
) {
(void)sprintf(buf
, "??%d", i
);
dr_name
[i
] = strdup(buf
);
* Choose drives to be displayed. Priority goes to (in order) drives
* supplied as arguments, default drives. If everything isn't filled
* in and there are drives not taken care of, display the first few
#define BACKWARD_COMPATIBILITY
for (ndrives
= 0; *argv
; ++argv
) {
#ifdef BACKWARD_COMPATIBILITY
for (i
= 0; i
< dk_ndrive
; i
++) {
if (strcmp(dr_name
[i
], *argv
))
for (i
= 0; i
< dk_ndrive
&& ndrives
< 4; i
++) {
for (cp
= defdrives
; *cp
; cp
++)
if (strcmp(dr_name
[i
], *cp
) == 0) {
for (i
= 0; i
< dk_ndrive
&& ndrives
< 4; i
++) {
* Make up for the fact that under 0.1, VM doesn't update all of the
* fields in the statistics structures.
struct vm_statistics
*vm_stat
;
kread(X_FREE
, &vm_stat
->free_count
, sizeof(vm_stat
->free_count
));
kread(X_ACTIVE
, &vm_stat
->active_count
, sizeof(vm_stat
->active_count
));
kread(X_INACTIVE
, &vm_stat
->inactive_count
,
sizeof(vm_stat
->inactive_count
));
kread(X_WIRED
, &vm_stat
->wire_count
, sizeof(vm_stat
->wire_count
));
kread(X_PAGESIZE
, &vm_stat
->pagesize
, sizeof(vm_stat
->pagesize
));
static time_t now
, boottime
;
kread(X_BOOTTIME
, &boottime
, sizeof(boottime
));
if (uptime
<= 0 || uptime
> 60*60*24*365*10) {
"vmstat: time makes no sense; namelist must be wrong.\n");
time_t uptime
, halfuptime
;
(void)signal(SIGCONT
, needhdr
);
if (nl
[X_PHZ
].n_type
!= 0 && nl
[X_PHZ
].n_value
!= 0)
kread(X_PHZ
, &hz
, sizeof(hz
));
kread(X_HZ
, &hz
, sizeof(hz
));
kread(X_CPTIME
, cur
.time
, sizeof(cur
.time
));
kread(X_DKXFER
, cur
.xfer
, sizeof(*cur
.xfer
) * dk_ndrive
);
kread(X_SUM
, &sum
, sizeof(sum
));
kread(X_TOTAL
, &total
, sizeof(total
));
kread(X_VMSTAT
, &vm_stat
, sizeof(vm_stat
));
fill_in_vm_stat (&vm_stat
);
kread(X_DEFICIT
, &deficit
, sizeof(deficit
));
(void)printf("%2d %1d %1d ",
total
.t_rq
, total
.t_dw
+ total
.t_pw
, total
.t_sw
);
#define pgtok(a) ((a)*NBPG >> 10)
#define rate(x) (((x) + halfuptime) / uptime) /* round */
(void)printf("%5ld %5ld ",
pgtok(vm_stat
.active_count
), pgtok(vm_stat
.free_count
));
pgtok(total
.t_avm
), pgtok(total
.t_free
));
(void)printf("%4lu ", rate(vm_stat
.faults
- ostat
.faults
));
rate(vm_stat
.reactivations
- ostat
.reactivations
));
(void)printf("%3lu ", rate(vm_stat
.pageins
- ostat
.pageins
));
(void)printf("%3lu %3lu ",
rate(vm_stat
.pageouts
- ostat
.pageouts
), 0);
(void)printf("%3lu %2lu ",
rate(sum
.v_pgrec
- (sum
.v_xsfrec
+sum
.v_xifrec
) -
(osum
.v_pgrec
- (osum
.v_xsfrec
+osum
.v_xifrec
))),
rate(sum
.v_xsfrec
+ sum
.v_xifrec
-
osum
.v_xsfrec
- osum
.v_xifrec
));
rate(pgtok(sum
.v_pgpgin
- osum
.v_pgpgin
)));
(void)printf("%3lu %3lu ",
rate(pgtok(sum
.v_pgpgout
- osum
.v_pgpgout
)),
rate(pgtok(sum
.v_dfree
- osum
.v_dfree
)));
(void)printf("%3d ", pgtok(deficit
));
(void)printf("%3lu ", rate(sum
.v_scan
- osum
.v_scan
));
(void)printf("%4lu %4lu %3lu ",
rate(sum
.v_intr
- osum
.v_intr
),
rate(sum
.v_syscall
- osum
.v_syscall
),
rate(sum
.v_swtch
- osum
.v_swtch
));
if (reps
>= 0 && --reps
<= 0)
* We round upward to avoid losing low-frequency events
* (i.e., >= 1 per interval but < 1 per second).
halfuptime
= (uptime
+ 1) / 2;
(void)printf(" procs memory page%*s", 20, "");
(void)printf("disks %*s faults cpu\n",
(void)printf("%*s faults cpu\n", ndrives
* 3, "");
(void)printf(" r b w avm fre re at pi po fr de sr ");
(void)printf(" r b w avm fre flt re pi po fr sr ");
for (i
= 0; i
< dk_ndrive
; i
++)
(void)printf("%c%c ", dr_name
[i
][0],
dr_name
[i
][strlen(dr_name
[i
]) - 1]);
(void)printf(" in sy cs us sy id\n");
* Force a header to be prepended to the next output.
kread(X_REC
, &rectime
, sizeof(rectime
));
kread(X_PGIN
, &pgintime
, sizeof(pgintime
));
kread(X_SUM
, &sum
, sizeof(sum
));
(void)printf("%u reclaims, %u total time (usec)\n",
(void)printf("average: %u usec / reclaim\n", rectime
/ sum
.v_pgrec
);
(void)printf("%u page ins, %u total time (msec)\n",
sum
.v_pgin
, pgintime
/ 10);
(void)printf("average: %8.1f msec / page in\n",
pgintime
/ (sum
.v_pgin
* 10.0));
return((top
* 100) / bot
);
#define PCT(top, bot) pct((long)(top), (long)(bot))
struct nchstats nchstats
;
struct keystats keystats
;
kread(X_SUM
, &sum
, sizeof(sum
));
kread(X_VMSTAT
, &vm_stat
, sizeof(vm_stat
));
fill_in_vm_stat(&vm_stat
);
(void)printf("%9u swap ins\n", sum
.v_swpin
);
(void)printf("%9u swap outs\n", sum
.v_swpout
);
(void)printf("%9u pages swapped in\n", sum
.v_pswpin
/ CLSIZE
);
(void)printf("%9u pages swapped out\n", sum
.v_pswpout
/ CLSIZE
);
(void)printf("%9u total address trans. faults taken\n", sum
.v_faults
);
(void)printf("%9u page ins\n", sum
.v_pgin
);
(void)printf("%9u page outs\n", sum
.v_pgout
);
(void)printf("%9u pages paged in\n", sum
.v_pgpgin
);
(void)printf("%9u pages paged out\n", sum
.v_pgpgout
);
(void)printf("%9u sequential process pages freed\n", sum
.v_seqfree
);
(void)printf("%9u total reclaims (%d%% fast)\n", sum
.v_pgrec
,
PCT(sum
.v_fastpgrec
, sum
.v_pgrec
));
(void)printf("%9u reclaims from free list\n", sum
.v_pgfrec
);
(void)printf("%9u intransit blocking page faults\n", sum
.v_intrans
);
(void)printf("%9u zero fill pages created\n", sum
.v_nzfod
/ CLSIZE
);
(void)printf("%9u zero fill page faults\n", sum
.v_zfod
/ CLSIZE
);
(void)printf("%9u executable fill pages created\n",
(void)printf("%9u executable fill page faults\n",
(void)printf("%9u swap text pages found in free list\n",
(void)printf("%9u inode text pages found in free list\n",
(void)printf("%9u file fill pages created\n", sum
.v_nvrfod
/ CLSIZE
);
(void)printf("%9u file fill page faults\n", sum
.v_vrfod
/ CLSIZE
);
(void)printf("%9u pages examined by the clock daemon\n", sum
.v_scan
);
(void)printf("%9u revolutions of the clock hand\n", sum
.v_rev
);
(void)printf("%9u pages freed by the clock daemon\n",
(void)printf("%9u cpu context switches\n", sum
.v_swtch
);
(void)printf("%9u device interrupts\n", sum
.v_intr
);
(void)printf("%9u software interrupts\n", sum
.v_soft
);
(void)printf("%9u pseudo-dma dz interrupts\n", sum
.v_pdma
);
(void)printf("%9u traps\n", sum
.v_trap
);
(void)printf("%9u system calls\n", sum
.v_syscall
);
(void)printf("%9u bytes per page\n", vm_stat
.pagesize
);
(void)printf("%9u pages free\n", vm_stat
.free_count
);
(void)printf("%9u pages active\n", vm_stat
.active_count
);
(void)printf("%9u pages inactive\n", vm_stat
.inactive_count
);
(void)printf("%9u pages wired down\n", vm_stat
.wire_count
);
(void)printf("%9u zero-fill pages\n", vm_stat
.zero_fill_count
);
(void)printf("%9u pages reactivated\n", vm_stat
.reactivations
);
(void)printf("%9u pageins\n", vm_stat
.pageins
);
(void)printf("%9u pageouts\n", vm_stat
.pageouts
);
(void)printf("%9u VM faults\n", vm_stat
.faults
);
(void)printf("%9u copy-on-write faults\n", vm_stat
.cow_faults
);
(void)printf("%9u VM object cache lookups\n", vm_stat
.lookups
);
(void)printf("%9u VM object hits\n", vm_stat
.hits
);
kread(X_NCHSTATS
, &nchstats
, sizeof(nchstats
));
nchtotal
= nchstats
.ncs_goodhits
+ nchstats
.ncs_neghits
+
nchstats
.ncs_badhits
+ nchstats
.ncs_falsehits
+
nchstats
.ncs_miss
+ nchstats
.ncs_long
;
(void)printf("%9ld total name lookups\n", nchtotal
);
"%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
"", PCT(nchstats
.ncs_goodhits
, nchtotal
),
PCT(nchstats
.ncs_neghits
, nchtotal
),
PCT(nchstats
.ncs_pass2
, nchtotal
));
(void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
PCT(nchstats
.ncs_badhits
, nchtotal
),
PCT(nchstats
.ncs_falsehits
, nchtotal
),
PCT(nchstats
.ncs_long
, nchtotal
));
kread(X_XSTATS
, &xstats
, sizeof(xstats
));
(void)printf("%9lu total calls to xalloc (cache hits %d%%)\n",
xstats
.alloc
, PCT(xstats
.alloc_cachehit
, xstats
.alloc
));
(void)printf("%9s sticky %lu flushed %lu unused %lu\n", "",
xstats
.alloc_inuse
, xstats
.alloc_cacheflush
, xstats
.alloc_unused
);
(void)printf("%9lu total calls to xfree", xstats
.free
);
(void)printf(" (sticky %lu cached %lu swapped %lu)\n",
xstats
.free_inuse
, xstats
.free_cache
, xstats
.free_cacheswap
);
kread(X_CKEYSTATS
, &keystats
, sizeof(keystats
));
(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
keystats
.ks_allocs
, "code cache keys allocated",
PCT(keystats
.ks_allocfree
, keystats
.ks_allocs
),
PCT(keystats
.ks_norefs
, keystats
.ks_allocs
),
PCT(keystats
.ks_taken
, keystats
.ks_allocs
),
PCT(keystats
.ks_shared
, keystats
.ks_allocs
));
kread(X_DKEYSTATS
, &keystats
, sizeof(keystats
));
(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
keystats
.ks_allocs
, "data cache keys allocated",
PCT(keystats
.ks_allocfree
, keystats
.ks_allocs
),
PCT(keystats
.ks_norefs
, keystats
.ks_allocs
),
PCT(keystats
.ks_taken
, keystats
.ks_allocs
),
PCT(keystats
.ks_shared
, keystats
.ks_allocs
));
kread(X_FORKSTAT
, &fks
, sizeof(struct forkstat
));
(void)printf("%d forks, %d pages, average %.2f\n",
fks
.cntfork
, fks
.sizfork
, (double)fks
.sizfork
/ fks
.cntfork
);
(void)printf("%d vforks, %d pages, average %.2f\n",
fks
.cntvfork
, fks
.sizvfork
, (double)fks
.sizvfork
/ fks
.cntvfork
);
for (dn
= 0; dn
< dk_ndrive
; ++dn
) {
cur
.xfer
[dn
] -= last
.xfer
[dn
];
for (state
= 0; state
< CPUSTATES
; ++state
) {
cur
.time
[state
] -= last
.time
[state
];
etime
+= cur
.time
[state
];
for (dn
= 0; dn
< dk_ndrive
; ++dn
) {
(void)printf("%2.0f ", cur
.xfer
[dn
] / etime
);
for (state
= 0; state
< CPUSTATES
; ++state
)
total
+= cur
.time
[state
];
(void)printf("%2.0f ", /* user + nice */
(cur
.time
[0] + cur
.time
[1]) * pct
);
(void)printf("%2.0f ", cur
.time
[2] * pct
); /* system */
(void)printf("%2.0f", cur
.time
[3] * pct
); /* idle */
register unsigned long *intrcnt
, inttotal
, uptime
;
register int nintr
, inamlen
;
nintr
= nl
[X_EINTRCNT
].n_value
- nl
[X_INTRCNT
].n_value
;
inamlen
= nl
[X_EINTRNAMES
].n_value
- nl
[X_INTRNAMES
].n_value
;
intrcnt
= malloc((size_t)nintr
);
intrname
= malloc((size_t)inamlen
);
if (intrcnt
== NULL
|| intrname
== NULL
) {
(void)fprintf(stderr
, "vmstat: %s.\n", strerror(errno
));
kread(X_INTRCNT
, intrcnt
, (size_t)nintr
);
kread(X_INTRNAMES
, intrname
, (size_t)inamlen
);
(void)printf("%-12s %10s %8s\n", "interrupt", "count", "rate");
(void)printf("%-12s %10lu %8lu\n", intrname
,
*intrcnt
, *intrcnt
/ uptime
);
intrname
+= strlen(intrname
) + 1;
(void)printf("%-12s %10lu %8lu\n", "Total", inttotal
, inttotal
/ uptime
);
* These names are defined in <sys/malloc.h>.
char *kmemnames
[] = INITKMEMNAMES
;
register struct kmembuckets
*kp
;
register struct kmemstats
*ks
;
long totuse
= 0, totfree
= 0, totreq
= 0;
struct kmemstats kmemstats
[M_LAST
];
struct kmembuckets buckets
[MINBUCKET
+ 16];
kread(X_KMEMBUCKETS
, buckets
, sizeof(buckets
));
(void)printf("Memory statistics by bucket size\n");
" Size In Use Free Requests HighWater Couldfree\n");
for (i
= MINBUCKET
, kp
= &buckets
[i
]; i
< MINBUCKET
+ 16; i
++, kp
++) {
(void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size
,
kp
->kb_total
- kp
->kb_totalfree
,
kp
->kb_totalfree
, kp
->kb_calls
,
kp
->kb_highwat
, kp
->kb_couldfree
);
totfree
+= size
* kp
->kb_totalfree
;
kread(X_KMEMSTAT
, kmemstats
, sizeof(kmemstats
));
(void)printf("\nMemory statistics by type\n");
" Type In Use MemUse HighUse Limit Requests TypeLimit KernLimit\n");
for (i
= 0, ks
= &kmemstats
[0]; i
< M_LAST
; i
++, ks
++) {
(void)printf("%12s %7ld %7ldK %8ldK %5ldK %8ld %6u %9u\n",
kmemnames
[i
] ? kmemnames
[i
] : "undefined",
ks
->ks_inuse
, (ks
->ks_memuse
+ 1023) / 1024,
(ks
->ks_maxused
+ 1023) / 1024,
(ks
->ks_limit
+ 1023) / 1024, ks
->ks_calls
,
ks
->ks_limblocks
, ks
->ks_mapblocks
);
(void)printf("\nMemory Totals: In Use Free Requests\n");
(void)printf(" %7ldK %6ldK %8ld\n",
(totuse
+ 1023) / 1024, (totfree
+ 1023) / 1024, totreq
);
* kread reads something from the kernel, given its nlist index.
if (nl
[nlx
].n_type
== 0 || nl
[nlx
].n_value
== 0) {
"vmstat: %s: symbol %s not defined\n", vmunix
, sym
);
if (kvm_read((void *)nl
[nlx
].n_value
, addr
, size
) != size
) {
(void)fprintf(stderr
, "vmstat: %s: %s\n", sym
, kvm_geterr());
"usage: vmstat [-fimst] [-c count] [-M core] \
[-N system] [-w wait] [disks]\n");
"usage: vmstat [-ims] [-c count] [-M core] \
[-N system] [-w wait] [disks]\n");