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'