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