*BSD News Article 8399


Return to BSD News archive

Newsgroups: comp.unix.bsd
Path: sserve!ccadfa.cc.adfa.oz.au!wkt
From: wkt@ccadfa.cc.adfa.oz.au (Warren Toomey)
Subject: [src] A vmstat-like program for 386BSD
Message-ID: <1992Dec2.045839.18827@sserve.cc.adfa.oz.au>
Sender: news@sserve.cc.adfa.oz.au
Organization: Australian Defence Force Academy, Canberra, Australia
Date: Wed, 2 Dec 1992 04:58:39 GMT


The vmstat ported to 386BSD doesn't give all the virtual memory statistics,
because 386BSD uses the Mach VM subsystem, and the 386BSD kernel doesn't
keep all the statistics in the right places.

Below is a simple vmstat-like program written for 386BSD that does find all
the VM statistics, except for the # of paged-out pages. Any ideas on how to
do this would be appreciated.

The first thing I noticed when using this program was that on my box with 8Meg
of real memory and 16Meg swap, running XFree86 caused the # free pages to go
from 1000 to 50. Time for another 8Meg of real memory, I think.

Cheers!

	Warren		wkt@csadfa.cs.adfa.oz.au


#	vstat.1
#	vstat.c
#
echo x - vstat.1
sed 's/^X//' >vstat.1 << 'END-of-vstat.1'
X.TH vstat 1 "December 1992"
X.SH NAME
Xvstat \- print virtual memory statistics for 386BSD
X.SH SYNOPSIS
X.B vstat
X[
X.B \-a
X]
X[
X.B interval
X]
X.SH DESCRIPTION
X.LP
X.I vstat
Xis a simple program that reads and prints the virtual memory
Xstatistics gathered by the 386BSD kernel, which uses a virtual
Xmemory subsystem taken from Mach.
X
X.SH OPTIONS
X
X.TP
X.B -a
XPrint out aggregate statistics. The default is to instead print out
Xthe differences over the given 
X.B interval.
X
X.TP
X.B interval
XCollect and print virtual memory statistics continuously at the
Xgiven
X.B interval
Xin seconds.
XThe default is no interval, i.e. a one-shot operation.
X
X.SH STATISTICS
X
X.I vstat
Xprints statistics in columns, with a heading line giving a cryptic
Xsynopsis of each column. The columns are as follows:
X
X.TP
X.B Pgsize
XThe page size in bytes. Unlikely to vary.
X
X.TP
X.B Free
XThe number of free pages in the system.
X
X.TP
X.B Actv
XThe number of active pages in the system.
X
X.TP
X.B Inactv
XThe number of inactive pages in the system.
X
X.TP
X.B Wired
XThe number of wired-down pages in the system.
X
X.TP
X.B Zero
XThe number of zero-fill pages.
X
X.TP
X.B React
XThe number of reactivated pages.
X
X.TP
X.B Ins
XThe number of pageins.
X
X.TP
X.B Outs
XThe number of pageouts.
X
X.TP
X.B Faults
XThe number of page faults.
X
X.TP
X.B COW
XThe number of copy-on-writes.
X
X.TP
X.B Looks
XThe number of object cache lookups.
X
X.TP
X.B Hits
XThe number of object cache hits.
X
X.SH SEE ALSO
X.BR vmstat(1)
X
X.SH BUGS AND OMISSIONS
X
XThe kernel doesn't collect all of the statistics yet. 
X.I vstat
Xhas been written to overcome this problem.
X
XI have no idea how to work out the number of paged pages yet.
X
X.SH AUTHOR
X.RS
XWarren Toomey
X.br
Xwkt@csadfa.cs.adfa.oz.au
END-of-vstat.1
echo x - vstat.c
sed 's/^X//' >vstat.c << 'END-of-vstat.c'
X/*
X * Vstat: Print virtual memory statistics, Version 1.0.
X *
X * Written 12/92 by Warren wkt@csadfa.cs.adfa.oz.au
X *
X * Many of the statistics fields in the _vm_stat struct are not
X * being set by the kernel. If BADSTATS is defined I attempt to
X * obtain these statistics elsewhere.
X */
X
X#define BADSTATS			/* Kernel ain't telling us all */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <nlist.h>
X#include <vm/vm_statistics.h>
X
Xchar	*fcore	= "/dev/kmem";		/* Device to read from */
Xchar	*fnlist	= "/386bsd";		/* File to nlist thru */
Xint	fc;				/* File desc of fcore */
Xint	difference = 1;			/* Should we print differences */
Xint	interval = 0;			/* Interval between updates */
X
X					/* List of kernel names we desire */
Xstruct nlist nl[] = {
X
X#define VM_STAT		0
X	{ "_vm_stat" },
X
X#ifdef BADSTATS
X#define VM_FREE		1
X	{ "_vm_page_free_count" },
X
X#define VM_ACTIVE	2
X	{ "_vm_page_active_count" },
X
X#define VM_INACTIVE	3
X	{ "_vm_page_inactive_count" },
X
X#define VM_WIRED	4
X	{ "_vm_page_wire_count" },
X
X#define VM_PAGESIZE	5
X	{ "_page_size" },
X
X#endif
X
X	{ "" }
X};
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X int i;
X
X while (argc>1)					/* Get any arguments */
X  {
X   argv++;					/* Move to next argument */
X
X   if (*argv[0] == '-')				/* Possibly -a ? */
X    {
X     if (!strcmp(argv[0],"-a")) difference=0;
X     else usage();
X    }
X   else
X    {
X     interval= atoi(argv[0]);			/* Get a possible interval */
X     if (interval==0) usage();
X    }
X   argc--;
X  }
X
X						/* Find the data structures */
X						/* in the kernel */
X i=nlist(fnlist, nl);
X if (i==-1) { perror("nlist"); exit(1); }
X
X for (i=0;nl[i].n_name;i++)
X   if (nl[0].n_type == 0)
X     { fprintf(stderr,"%s not found in namelist\n",nl[0].n_name); exit(1); }
X
X						/* Open up the kernel memory */
X fc= open(fcore,O_RDONLY);
X if (fc==-1) { perror("opening /dev/kmem"); exit(1); }
X
X						/* Print the statistics */
X dovm_stat();
X}
X
Xusage()
X{
X printf("usage: vstat [-a] [interval]\n"); exit(1);
X}
X
X
Xdovm_stat()
X{
X  vm_statistics_data_t	vmstat, old;
X  int i, count=0;
X#ifdef BADSTATS
X  int size, free, active, inactive, wired;
X
X					/* Get the page size */
X  i=lseek(fc, nl[VM_PAGESIZE].n_value, SEEK_SET);
X  if (i==-1) { perror("lseeking /dev/kmem"); exit(1); }
X  i=read(fc, &size, sizeof(size));
X  if (i!= sizeof(size)) { perror("reading /dev/kmem"); exit(1); }
X#endif
X
X/* If we're printing diffs, get values into old
X * now so that the first line will be slightly
X * meaningful.
X */
X  if (difference)
X   {
X    i=lseek(fc, nl[VM_STAT].n_value, SEEK_SET);
X    if (i==-1) { perror("lseeking /dev/kmem"); exit(1); }
X    i=read(fc, &old, sizeof(old));
X    if (i!= sizeof(old)) { perror("reading /dev/kmem"); exit(1); }
X   }
X
X  while(1)
X   {
X						/* Find and read vmstat */
X    i=lseek(fc, nl[VM_STAT].n_value, SEEK_SET);
X    if (i==-1) { perror("lseeking /dev/kmem"); exit(1); }
X    i=read(fc, &vmstat, sizeof(vmstat));
X    if (i!= sizeof(vmstat)) { perror("reading /dev/kmem"); exit(1); }
X
X#ifdef BADSTATS
X						/* Find and read freecount */
X    i=lseek(fc, nl[VM_FREE].n_value, SEEK_SET);
X    if (i==-1) { perror("lseeking /dev/kmem"); exit(1); }
X    i=read(fc, &free, sizeof(free));
X    if (i!= sizeof(free)) { perror("reading /dev/kmem"); exit(1); }
X						/* Find and read actives */
X    i=lseek(fc, nl[VM_ACTIVE].n_value, SEEK_SET);
X    if (i==-1) { perror("lseeking /dev/kmem"); exit(1); }
X    i=read(fc, &active, sizeof(active));
X    if (i!= sizeof(active)) { perror("reading /dev/kmem"); exit(1); }
X						/* Find and read inactives */
X    i=lseek(fc, nl[VM_INACTIVE].n_value, SEEK_SET);
X    if (i==-1) { perror("lseeking /dev/kmem"); exit(1); }
X    i=read(fc, &inactive, sizeof(inactive));
X    if (i!= sizeof(inactive)) { perror("reading /dev/kmem"); exit(1); }
X						/* Find and read wireds */
X    i=lseek(fc, nl[VM_WIRED].n_value, SEEK_SET);
X    if (i==-1) { perror("lseeking /dev/kmem"); exit(1); }
X    i=read(fc, &wired, sizeof(wired));
X    if (i!= sizeof(wired)) { perror("reading /dev/kmem"); exit(1); }
X#endif
X						/* Print header if needed */
X    if (count % 20 == 0)
X      printf("\nPgsize Free  Actv Inactv Wired Zero React   Ins  Outs Faults  COW Looks  Hits\n");
X
X#ifdef BADSTATS
X    printf("%5d ",size);
X    printf("%5d ",free);
X    printf("%5d ",active);
X    printf("%5d ",inactive);
X    printf("%5d ",wired);
X#else
X    printf("%5d ",vmstat.pagesize);
X    printf("%5d ",vmstat.free_count);
X    printf("%5d ",vmstat.active_count);
X    printf("%5d ",vmstat.inactive_count);
X    printf("%5d ",vmstat.wire_count);
X#endif
X						/* Print diffs or aggregate */
X    if (difference)
X     {
X      printf("%5d ",vmstat.zero_fill_count - old.zero_fill_count);
X      printf("%5d ",vmstat.reactivations - old.reactivations);
X      printf("%5d ",vmstat.pageins - old.pageins);
X      printf("%5d ",vmstat.pageouts - old.pageouts);
X      printf("%5d ",vmstat.faults - old.faults);
X      printf("%5d ",vmstat.cow_faults - old.cow_faults);
X      printf("%5d ",vmstat.lookups - old.lookups);
X      printf("%5d",vmstat.hits - old.hits);
X						/* Save for next diff round */
X      memcpy(&old, &vmstat, sizeof(vmstat));
X     }
X    else
X     {
X      printf("%5d ",vmstat.zero_fill_count);
X      printf("%5d ",vmstat.reactivations);
X      printf("%5d ",vmstat.pageins);
X      printf("%5d ",vmstat.pageouts);
X      printf("%5d ",vmstat.faults);
X      printf("%5d ",vmstat.cow_faults);
X      printf("%5d ",vmstat.lookups);
X      printf("%5d",vmstat.hits);
X     }
X    printf("\n");
X    if (interval==0) exit(0);			/* Give up if once only */
X    sleep(interval);
X    count++;
X   }
X}
END-of-vstat.c
exit

-- 
      Warren Toomey VK1XWT, still around.
    Deep in the bowels of ADFA Comp Science.
`[of Fred Astaire:] He'd look good in a dress'