*BSD News Article 12302


Return to BSD News archive

Path: sserve!manuel.anu.edu.au!munnari.oz.au!spool.mu.edu!howland.reston.ans.net!gatech!nanovx!dragon!rokkaku!kml
Newsgroups: comp.os.386bsd.apps
Subject: [source] swapinfo -- swap information reporter
Message-ID: <C3E4IE.JuG@rokkaku.atl.ga.us>
From: kml@rokkaku.atl.ga.us (Kevin Lahey)
Date: Fri, 5 Mar 1993 00:39:49 GMT
Organization: Geeks-R-Us
Summary: another status program for 386bsd
Lines: 418


This program provides some interesting information about swap space usage
under 386bsd.  Here's some sample output:

rokkaku:361% swapinfo -k
Device      Kilobytes       Used  Available   Capacity
/dev/as0b       12284       5600       6684      46%
/dev/as1b       16384       4080      12304      25%
Total           28668       9680      18988      34%

Give it a shot!  More information (including a disclaimer about the 
accuracy of the output) can be found in the attached README.

Kevin
kml@rokkaku.atl.ga.us

--------------------------->8  cut here 8<----------------------------------
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	README
#	swapinfo.c
#	devname.c
#	swapinfo.1
#	Makefile
#
echo x - README
sed 's/^X//' >README << 'END-of-README'
Xswapinfo
X========
X
XSwapinfo is designed to provide some information to the user about the
Xstate of the swap space on the system.  I've written it based on a 
Xbrief (!) perusal of the VM code in 386BSD.  I could be pretty confused
Xabout how it all fits together, and perhaps this is totally bogus.
XIt seems to work for me, though.
X
XHow it works:
X
XDuring startup, the system traverses the list of configured swap partitions,
Xand determines the size of the various partitions.  As each new partition
Xis added for swapping (via swapon), the free space on that disk is added
Xto a linked list of free space.  Adjacent areas are coalesced to form
Xlarger areas.  The swapping algorithm seems to take the first free section
Xthat it finds [?].
X
XSwapinfo reads in the list of configured swap partitions from the /dev/kmem,
Xto determine the size of the partitions.  It then traverses the list
Xof free space, figuring up how much is still available and how much
Xhas therefore been used.  Things get a little hairy in that the swap space
Xis divided amongst the configured swap partitions so that the first
X4096 blocks of swap go on the first swap partition, the second 4096 on
Xthe second swap partition, and so on.  This works out to be a fairly
Xsimple bit of code, though.
X
XMore caveats:
X
XThis works on my system.  Your milage may vary.  Since I'm reading /dev/kmem
Xto follow a linked list, the program could easily get lost looking for
Xsome free space if anything got changed between reads of /dev/kmem.
XIf you get occasional inconsistant results, ignore 'em.
X
XFeel free to send bug reports, flames, etc., to:
X
XKevin Lahey
Xkml@rokkaku.atl.ga.us
END-of-README
echo x - swapinfo.c
sed 's/^X//' >swapinfo.c << 'END-of-swapinfo.c'
X/*
X * swapinfo
X *
X * Swapinfo will provide some information about the state of the swap
X * space for the system.  It'll determine the number of swap areas,
X * their original size, and their utilization.
X *
X * Kevin Lahey, February 16, 1993
X */
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <sys/types.h>
X#include <sys/ioctl.h>
X#include <sys/termios.h>
X#include <sys/stat.h>
X#include <sys/tty.h>
X#include <sys/uio.h>
X#include <sys/buf.h>
X#include <sys/conf.h>
X#include <sys/rlist.h>  /* swapmap defined here... */
X#include <nlist.h>
X
X
Xstatic struct nlist nl[] = {{"_swapmap"},  /* list of free swap areas */
X#define VM_SWAPMAP	0
X			    {"_swdevt"},   /* list of swap devices and sizes */
X#define VM_SWDEVT	1
X			    {"_nswap"},    /* size of largest swap device */
X#define VM_NSWAP	2
X			    {"_nswdev"},   /* number of swap devices */
X#define VM_NSWDEV	3
X			    {"_dmmax"},    /* maximum size of a swap block */
X#define VM_DMMAX	4
X			    {""}};
X
X
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	int	i, total_avail, total_free, total_partitions, *by_device, 
X		use_k = 1,  /* used as a divisor, so 1 == blocks, 2 == K */
X		nswap, nswdev, dmmax;
X	struct swdevt	*swdevt;
X	struct rlist	head;
X
X	/* We are trying to be simple here: */
X
X	if (argc > 1)
X		if (strcmp (argv [1], "-k") == 0) {
X			use_k = 2;
X		} else {
X			fprintf (stderr, "Usage:  swapinfo [-k]\n");
X			exit (1);
X		}
X
X	/* Open up /dev/kmem for reading. */
X	
X	if (kvm_openfiles (NULL, NULL, NULL) == -1) {
X		fprintf (stderr, "%s: kvm_openfiles:  %s\n", 
X			 argv [0], kvm_geterr());
X		exit (1);
X	}
X
X	/* Figure out the offset of the various structures we'll need. */
X
X	if (kvm_nlist (nl) == -1) {
X		fprintf (stderr, "%s: kvm_nlist:  %s\n", 
X			 argv [0], kvm_geterr());
X		exit (1);
X	}
X
X	if (kvm_read (nl [VM_NSWAP].n_value, &nswap, sizeof (nswap)) !=
X	    sizeof (nswap)) {
X		fprintf (stderr, "%s:  didn't read all of nswap\n", 
X			 argv [0]);
X		exit (5);
X	}
X
X	if (kvm_read (nl [VM_NSWDEV].n_value, &nswdev, sizeof (nswdev)) !=
X	    sizeof (nswdev)) {
X		fprintf (stderr, "%s:  didn't read all of nswdev\n", 
X			 argv [0]);
X		exit (5);
X	}
X
X	if (kvm_read (nl [VM_DMMAX].n_value, &dmmax, sizeof (dmmax)) !=
X	    sizeof (dmmax)) {
X		fprintf (stderr, "%s:  didn't read all of dmmax\n", 
X			 argv [0]);
X		exit (5);
X	}
X
X	if ((swdevt = malloc (sizeof (struct swdevt) * nswdev)) == NULL ||
X	    (by_device = calloc (sizeof (*by_device), nswdev)) == NULL) {
X		perror ("malloc");
X		exit (5);
X	}
X
X	if (kvm_read (nl [VM_SWDEVT].n_value, swdevt, 
X		      sizeof (struct swdevt) * nswdev) !=
X	    sizeof (struct swdevt) * nswdev) {
X		fprintf (stderr, "%s:  didn't read all of swdevt\n", 
X			 argv [0]);
X		exit (5);
X	}
X
X	if (kvm_read (nl [0].n_value, &swapmap, sizeof (struct rlist *)) !=
X	    sizeof (struct rlist *)) {
X		fprintf (stderr, "%s:  didn't read all of swapmap\n", 
X			 argv [0]);
X		exit (5);
X	}
X
X	/* Traverse the list of free swap space... */
X
X	total_free = 0;
X    	while (swapmap) {
X		int	top, bottom, next_block;
X
X		if (kvm_read ((long) swapmap, &head, sizeof (struct rlist )) !=
X		    sizeof (struct rlist )) {
X			fprintf (stderr, "%s:  didn't read all of head\n", 
X				 argv [0]);
X			exit (5);
X		}
X
X		top = head.rl_end;
X		bottom = head.rl_start;
X
X		total_free += top - bottom + 1;
X
X		/*
X		 * Swap space is split up among the configured disk.
X		 * The first dmmax blocks of swap space some from the
X		 * first disk, the next dmmax blocks from the next, 
X		 * and so on.  The list of free space joins adjacent
X		 * free blocks, ignoring device boundries.  If we want
X		 * to keep track of this information per device, we'll
X		 * just have to extract it ourselves.
X		 */
X
X		while (top / dmmax != bottom / dmmax) {
X			next_block = ((bottom + dmmax) / dmmax);
X			by_device [(bottom / dmmax) % nswdev] +=
X				next_block * dmmax - bottom;
X			bottom = next_block * dmmax;
X		}
X
X		by_device [(bottom / dmmax) % nswdev] +=
X			top - bottom + 1;
X
X		swapmap = head.rl_next;
X	}
X
X	printf ("%-10s %10s %10s %10s %10s\n",
X		"Device", use_k == 1 ? "512-blks" : "Kilobytes", 
X		"Used", "Available", "Capacity");
X	for (total_avail = total_partitions = i = 0; i < nswdev; i++) {
X		printf ("/dev/%-5s %10d ",
X			devname (swdevt [i].sw_dev, S_IFBLK), 
X			swdevt [i].sw_nblks / use_k);
X
X		/*
X		 * Don't report statistics for partitions which have not
X		 * yet been activated via swapon(8).
X		 */
X
X		if (!swdevt [i].sw_freed) {
X			printf (" *** not available for swapping ***\n");
X		} else {
X			total_partitions++;
X			total_avail += swdevt [i].sw_nblks;
X			printf ("%10d %10d %7.0f%%\n", 
X				(swdevt [i].sw_nblks - by_device [i]) / use_k,
X				by_device [i] / use_k,
X				(double) (swdevt [i].sw_nblks - 
X					  by_device [i]) / 
X				(double) swdevt [i].sw_nblks * 100.0);
X		}
X	}
X
X	/* 
X	 * If only one partition has been set up via swapon(8), we don't
X	 * need to bother with totals.
X	 */
X
X	if (total_partitions > 1)
X		printf ("%-10s %10d %10d %10d %7.0f%%\n", "Total", 
X			total_avail / use_k, 
X			(total_avail - total_free) / use_k, 
X			total_free / use_k,
X			(double) (total_avail - total_free) / 
X			(double) total_avail * 100.0);
X
X	exit (0);
X}
END-of-swapinfo.c
echo x - devname.c
sed 's/^X//' >devname.c << 'END-of-devname.c'
X/*
X * Copyright (c) 1989 The Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)devname.c	5.14 (Berkeley) 5/6/91";
X#endif /* LIBC_SCCS and not lint */
X
X#include <sys/types.h>
X#include <fcntl.h>
X#include <db.h>
X#include <stdio.h>
X#include <paths.h>
X
Xchar *
Xdevname(dev, type)
X	dev_t dev;
X	mode_t type;
X{
X	struct {
X		mode_t type;
X		dev_t dev;
X	} bkey;
X	static DB *db;
X	static int failure;
X	DBT data, key;
X
X	if (!db && !failure &&
X	    !(db = hash_open(_PATH_DEVDB, O_RDONLY, 0, NULL))) {
X		(void)fprintf(stderr,
X		    "warning: no device database %s\n", _PATH_DEVDB);
X		failure = 1;
X	}
X	if (failure)
X		return("??");
X
X	/*
X	 * Keys are a mode_t followed by a dev_t.  The former is the type of
X	 * the file (mode & S_IFMT), the latter is the st_rdev field.
X	 */
X	bkey.dev = dev;
X	bkey.type = type;
X	key.data = &bkey;
X	key.size = sizeof(bkey);
X	return((db->get)(db, &key, &data, 0L) ? "??" : (char *)data.data);
X}
END-of-devname.c
echo x - swapinfo.1
sed 's/^X//' >swapinfo.1 << 'END-of-swapinfo.1'
X.\"
X.\"   swapinfo
X.\"
X.Dd February 23, 1993
X.Dt SWAPINFO 1
X.Sh NAME
X.Nm swapinfo
X.Nd display free swap space
X.Sh SYNOPSIS
X.Nm swapinfo
X.Op Fl k
X.Sh DESCRIPTION
X.Nm Swapinfo
Xdisplays statistics about the amount of free swap space on all of the 
Xswap areas compiled into the kernel.
X.Pp
XThe following options are available:
X.Bl -tag -width Ds
X.It Fl k
XBy default, all sizes are reported in 512-byte block counts.
XThe
X.Fl k
Xoption causes the numbers to be reported in kilobyte counts.
X.El
X.Sh STATISTICS
XStatistics are reported for all swap partitions configured into the kernel.
XThe first column is the device name of the partition.  The next column is
Xthe total space available in the partition.  The 
X.Ar Used
Xcolumn indicates the total blocks used so far;  the 
X.Ar Available
Xcolumn indicates how much space is remaining on each partition.
XThe
X.Ar Capacity
Xreports the percentage of space used.
X.Pp
XIf more than one partition is configured into the system, totals for all
Xof the statistics will be reported in the final line of the report.
X.Sh "BUGS AND CAVEATS"
XThe information reported by
X.Nm swapinfo
Xis stored in the kernel in a linked list.  Since we are merely reading
Xthis list out of kernel memory, it is entirely possible that the list could
Xchange as we try to read it.  Suspicious and unrepeatable values are probably
Xincorrect.
X.Pp
XStatistics are reported for all swap partitions compiled into the kernel,
Xregardless of whether those partitions are being used.
X.Sh AUTHOR
X.RS
XKevin Lahey
X.br
Xkml@rokkaku.atl.ga.us
END-of-swapinfo.1
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X#
X# build swapinfo
X#
X
XCFLAGS = -g 
Xswapinfo:	swapinfo.o devname.o
X	cc -o swapinfo swapinfo.o devname.o -lutil
END-of-Makefile
exit