v05i066: Program to Display Memory Allocation in System V
Michael J. Young
mjy at sdti.sdti.com
Sat Dec 3 10:36:04 AEST 1988
Posting-number: Volume 5, Issue 66
Submitted-by: "Michael J. Young" <mjy at sdti.sdti.com>
Archive-name: mapmem
Mapmem displays a visual map of physical memory and swap device allocation
for System V Unix. The map is updated at 1 second intervals, providing a
real-time view of system memory utilization.
I'm sure there are lots of utilities out there that do things like this,
but I don't have them here. I hope someone else finds it useful as well.
Please send bug reports/fixes, etc., to me.
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 1 (of 1)."
# Contents: Makefile README mapmem.8 mapmem.c
# Wrapped by mjy at sdti on Wed Nov 30 16:04:20 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Makefile -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(733 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X## @(#)$Id: Makefile, V1.1.1.3 88/11/30 16:03:44 $
X##
X## MAPMEM makefile
X## Version : 1.1.1.3 - 88/11/30 16:03:44
X##
X
X## edit as appropriate...
XCFLAGS = -g -O
XLDFLAGS =
XLIBFLAGS = -lcurses
X
X## Directory in which executable should be placed:
XDESTDIR = /usr/local/bin
X
X## Directory in which man page should be placed:
XMANDIR = /usr/man/l_man/man8
X
X## MAPMEM must have read access to /dev/kmem. Therefore, it must be
X## setgid to some group with the appropriate privilege.
XGRPID = sys
X
Xmapmem : mapmem.c
X $(CC) $(LDFLAGS) $(CFLAGS) -o mapmem mapmem.c $(LIBFLAGS)
X
Xinstall: mapmem
X cp mapmem $(DESTDIR)/mapmem
X chgrp $(GRPID) $(DESTDIR)/mapmem
X chmod g+s $(DESTDIR)/mapmem
X cp mapmem.8 $(MANDIR)/mapmem.8
X chmod 444 $(MANDIR)/mapmem.8
END_OF_Makefile
if test 733 -ne `wc -c <Makefile`; then
echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f README -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(501 characters\)
sed "s/^X//" >README <<'END_OF_README'
XMAPMEM displays a visual map of physical memory and swap device allocations
Xfor a swapping (i.e., non-paged) Unix system. The map is updated at 1 second
Xintervals, providing a real-time indication of system memory utilization.
X
XTo install, simply edit the makefile and type 'make'. Typing 'make install'
Xwill install the executable with the appropriate privileges.
X
XMAPMEM requires read access to /dev/kmem, and must therefore be run as
Xsetgid to some group with the appropriate access (e.g., sys).
END_OF_README
if test 501 -ne `wc -c <README`; then
echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mapmem.8 -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"mapmem.8\"
else
echo shar: Extracting \"mapmem.8\" \(943 characters\)
sed "s/^X//" >mapmem.8 <<'END_OF_mapmem.8'
X.\" @(#)$ mapmem.8, Version 1.1.1.1 - 88/11/28 18:16:51
X.TH MAPMEM 8
X.ad b
X.SH NAME
Xmapmem \- display map of core and swap allocation.
X.SH SYNOPSIS
X.B mapmem
X[
X.B \-d #
X] [
X.B \-vh?
X]
X.SH DESCRIPTION
X.I Mapmem
Xdisplays a visual map of physical memory and swap device
Xallocation of a swapping (i.e., non-paged) Unix system. The map display is
Xupdated at periodic intervals, providing a real-time indication of system
Xmemory utilization.
X.I Mapmem
Xuses
X.I curses(3x)
Xfor its screen output, based on the \fBTERM\fR environment variable.
X.SH OPTIONS
X.IP \fB-d#\fR
XDelay '\fB#\fR' seconds between updates. Defaults to 1 second.
X.IP \fB-h\fR
XDisplay a short usage message.
X.IP \fB-v\fR
XDisplay version and patch level of
X.I mapmem .
X.IP \fB-?\fR
XSame as \fB-h\fR.
X.SH BUGS
XProbably.
X.SH "SEE ALSO"
X.I curses(3x) ,
X.I terminfo(4)
X.SH AUTHOR
XMichael J. Young
X.br
Xharvard!sdti!mjy
X.br
XInternet : mjy at sdti.SDTI.COM
X.SH VERSION
X1.1 - 88/11/28 18:16:51
END_OF_mapmem.8
if test 943 -ne `wc -c <mapmem.8`; then
echo shar: \"mapmem.8\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mapmem.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"mapmem.c\"
else
echo shar: Extracting \"mapmem.c\" \(12856 characters\)
sed "s/^X//" >mapmem.c <<'END_OF_mapmem.c'
Xstatic char sccsid[] = "@(#)$Id: mapmem.c, V1.1.1.2 88/11/28 18:16:45 $";
X
X/*
X * map.c - display kernel allocation map information
X * Version : 1.1.1.2 - 88/11/28 18:16:45
X * Author : Michael J. Young
X * USmail : Software Development Technologies, Inc.
X * 375 Dutton Rd
X * Sudbury MA 01776
X * UUCP : harvard!sdti!mjy
X * Internet : mjy at sdti.SDTI.COM
X *
X * =========================================================================
X * Copyright (C) 1988, Michael J. Young.
X * Permission is hereby granted to copy and distribute this program for
X * non-commercial purposes, provided that this notice is not removed.
X *
X * This program is being provided "as is", with no warrantee as to safety or
X * accuracy of results.
X *
X * Please send bug reports and enhancements to me at the above address.
X * =========================================================================
X */
X
X/*
X * Modification History:
X *
X * Wed Nov 23 09:39:01 EST 1988 - M. Young (mjy at sdti.SDTI.COM),
X * Originated.
X */
X
X#define patch_level 0
X
X#include <nlist.h>
X#include <stdio.h>
X#include <sys/map.h>
X#include <sys/param.h>
X#include <fcntl.h>
X#include <curses.h>
X#include <sys/types.h>
X#include <time.h>
X#include <varargs.h>
X#include <signal.h>
X
X/*
X * sizes of the two major allocation maps maintained by the kernel. These
X * values are actually contained in the linkkit config.h. If that file is
X * not available, they must be set here.
X */
X#ifdef SMAPSIZ
X# define SMAPSIZE SMAPSIZ
X#else
X# define SMAPSIZE 75
X#endif
X
X#ifdef CMAPSIZ
X# define CMAPSIZE CMAPSIZ
X#else
X# define CMAPSIZE 150
X#endif
X
X/*
X * The following definitions specify the dimensions of the display map.
X * Change to suit your tastes.
X */
X#define MAX_ROWS 20
X#define MAX_COLUMNS 64
X#define MAX_ENTRIES (MAX_ROWS*MAX_COLUMNS)
X
X/*
X * the following defines are used to index the namelist array. Their
X * definitions must be consistent with the order of the namelist array.
X */
X#define CORE_MAP 0
X#define SWAP_MAP 1
X#define MAX_MEM 2
X#define N_SWAP 3
X#define PHYS_MEM 4
X
X/*
X * namelist array : contains a list of names to be extracted from the kernel
X * image using the nlist function.
X */
Xstruct nlist namelist[] = {
X { "coremap", 0, 0, 0, 0, 0 },
X { "swapmap", 0, 0, 0, 0, 0 },
X { "maxmem", 0, 0, 0, 0, 0 },
X { "nswap", 0, 0, 0, 0, 0 },
X { "physmem", 0, 0, 0, 0, 0 },
X { "", 0, 0, 0, 0, 0 }
X};
X
Xstruct map smapbf[SMAPSIZE]; /* local copy of swap allocation map */
Xstruct map cmapbf[CMAPSIZE]; /* local copy of core allocation map */
Xint kmaxmem = 0; /* local copy of maxmem */
Xint kphysmem = 0; /* local copy of physmem */
Xint knswap = 0; /* local copy of nswap */
X
Xint kmem = 0; /* file handle for kernel memory */
Xint delay = 1; /* seconds between screen updates */
X
Xchar dmap[MAX_ENTRIES] = 0; /* display map */
X
Xint swap_scale = 1; /* scale factor for swap map display */
Xint core_scale = 1; /* scale factor for core map display */
X
X/*
X * various useful definitions
X */
Xtypedef int boolean;
X
X/*#define FALSE 0 /* defined in curses.h */
X/*#define TRUE 1 /* defined in curses.h */
X
X/*
X * various function declarations
X */
Xextern long lseek();
Xextern int read();
Xextern time_t time();
X
X/*
X * interface to system error messages
X */
Xchar *prog_name = NULL;
X
Xextern char *sys_errlist[];
Xextern int sys_nerr;
Xextern int errno;
X
X/*
X * error : performs a function similar to perror(3), but supports variable
X * argument lists. Prints out a formatted error string to stderr, followed if
X * possible by an appropriate system error message. Control is then
X * returned to the system with an error status. This function does not
X * return.
X */
X/* VARARGS0 */
Xvoid error (va_alist)
Xva_dcl /* varargs */
X{
X int err; /* 1st arg - error number */
X char *str; /* 2nd arg - error format string */
X va_list args;
X va_start(args);
X err = va_arg (args, int);
X str = va_arg (args, char *);
X fprintf (stderr, "%s: ", prog_name);
X vfprintf (stderr, str, args);
X if (err != 0){
X if (err <= sys_nerr && err > 0)
X fprintf (stderr, " : %s\n", sys_errlist[err]);
X else
X fprintf (stderr, " : unknown error : %d\n", err);
X }
X va_end(args);
X endwin();
X exit(1);
X}
X
Xvoid version (){
X printf ("\nKernel Allocation Map Display\n");
X printf ("Version : 1.1 - 88/11/28 18:16:45, Patch Level %d\n", patch_level);
X}
X
Xvoid usage(){
X version();
X printf ("Usage : map [-[?h]] [-d#]\n\n");
X printf ("\t-d#\tDelay '#' seconds between screen updates. Defaults\n");
X printf ("\t\tto 1 second.\n");
X printf ("\t-h\tDisplays this message.\n");
X printf ("\t-v\tDisplays version and patch level of program.\n");
X printf ("\t-?\tDisplays this message.\n");
X}
X
X/*
X * get_nlist : fetches the required namelist from the kernel image
X */
Xvoid get_nlist(){
X if (nlist ("/unix", namelist) != 0){
X error (errno, "could not get namelist");
X }
X}
X
X/*
X * open_kmem : opens kernel memory
X */
Xvoid open_kmem(){
X
X /*
X * open kernel memory
X */
X if ((kmem=open ("/dev/kmem", O_RDONLY)) == -1){
X error (errno, "could not open /dev/kmem");
X }
X}
X
X/*
X * init_kmem : reads kernel memory to initialize various static values
X * that are important for future processing.
X */
Xvoid init_kmem (){
X /*
X * fetch maxmem (maximum free memory available to a process)
X */
X if (lseek (kmem, namelist[MAX_MEM].n_value, 0) != namelist[MAX_MEM].n_value){
X error (errno, "could not seek maxmem");
X }
X if (read (kmem, &kmaxmem, sizeof (int)) != sizeof (int)){
X error (errno, "could not read maxmem");
X }
X
X /*
X * fetch physmem (maximum physical memory present in the system)
X */
X if (lseek (kmem, namelist[PHYS_MEM].n_value, 0) != namelist[PHYS_MEM].n_value){
X error (errno, "could not seek physmem");
X }
X if (read (kmem, &kphysmem, sizeof (int)) != sizeof (int)){
X error (errno, "could not read physmem");
X }
X
X /*
X * fetch nswap (total blocks in the swap device)
X */
X if (lseek (kmem, namelist[N_SWAP].n_value, 0) != namelist[N_SWAP].n_value){
X error (errno, "could not seek nswap");
X }
X if (read (kmem, &knswap, sizeof (int)) != sizeof (int)){
X error (errno, "could not read nswap");
X }
X
X /*
X * calculate the scale factor for the display maps. The scale
X * factors should be set in such a way that a single screen can
X * display the entire map. The scale factors are then massaged to
X * ensure that they are always even. This is done in multiple
X * statements to ensure that smart compilers don't optimize the
X * multiplies and divides away. I'm sure there's a more elegant
X * and reliable way, but this seems to work.
X */
X swap_scale = (knswap + MAX_ENTRIES - 1) / MAX_ENTRIES;
X swap_scale = (swap_scale + 1) / 2;
X swap_scale *= 2;
X core_scale = (kphysmem + MAX_ENTRIES - 1) / MAX_ENTRIES;
X core_scale = (core_scale + 1) / 2;
X core_scale *= 2;
X}
X
X/*
X * read_map : copies the specified kernel allocation map into local memory
X * for future processing.
X */
Xvoid read_map(loc, buf, size)
Xdaddr_t loc; /* location in kernel to be read */
Xstruct map *buf; /* buffer in which to place copy */
Xunsigned size; /* number of map entries to read */
X{
X if (lseek (kmem, loc, 0) != loc){
X error (errno, "could not seek kernel map");
X }
X if (read (kmem, buf, size*sizeof (struct map)) != size*sizeof (struct map)){
X error (errno, "could not read kernel map");
X }
X}
X
X/*
X * update_map : modifies all of the appropriate display map cells according
X * that are affected by the specified kernel allocation map item.
X */
Xvoid update_map (dmap, mp, scale)
Xchar dmap[];
Xstruct map *mp;
Xint scale;
X{
X int entry;
X int map_index;
X int size;
X size = mp->m_size;
X for (entry = mp->m_addr; size; entry++){
X map_index = entry / scale;
X dmap[map_index] = 0;
X size--;
X }
X}
X
X/*
X * interpret_map : scans through the copy of the kernel allocation map and
X * updates the specified display map accordingly. The total number of free
X * blocks in the map are returned.
X */
Xint interpret_map(dmap, kmp, scale)
Xchar dmap[];
Xstruct map *kmp;
Xint scale;
X{
X int total_free = 0;
X struct map *mp;
X memset (dmap, 1, MAX_ENTRIES);
X for (mp = kmp; mp->m_size; mp++){
X total_free += mp->m_size;
X update_map (dmap, mp, scale);
X }
X return total_free;
X}
X
X/*
X * print_map : scans the allocation map, displaying it in the standard
X * window. Allocated cells are marked with an asterisk ('*'), and free
X * cells are marked with a period ('.').
X */
Xvoid print_map(dmap, scale, total_size)
Xchar dmap[];
Xint scale;
Xlong total_size;
X{
X int i, j, k;
X int entry;
X move (2,0);
X for (i = 0; i < MAX_ROWS; i++){
X k = i*MAX_COLUMNS;
X if (((long)k*scale) >= total_size)break;
X printw ("%08lx: ", (long)k * scale);
X for (j = 0; j < MAX_COLUMNS; j++){
X if ((((long)k+j)*scale) >= total_size)break;
X entry = (i*MAX_COLUMNS+j);
X if (dmap[entry] != 0)addch ('*');
X else addch ('.');
X }
X addch ('\n');
X }
X}
X
Xvoid interrupt (sig)
Xint sig;
X{
X move (0,0);
X clrtobot();
X refresh();
X endwin();
X exit(0);
X}
X
X/*
X * init : performs system and curses initialization
X */
Xvoid init (argc, argv)
Xint argc;
Xchar *argv[];
X{
X int i;
X boolean done;
X char *cp;
X
X /*
X * before we go any further, disable interrupts
X */
X signal (SIGINT, SIG_IGN);
X signal (SIGQUIT, SIG_IGN);
X signal (SIGHUP, SIG_IGN);
X signal (SIGTERM, SIG_IGN);
X
X /*
X * save program name for future reference
X */
X prog_name = argv[0];
X
X for (i = 1; i < argc; i++){
X cp = argv[i];
X if (*cp == '-'){
X done = FALSE;
X while (*++cp && !done){
X switch (*cp){
X
X case 'd': /* delay */
X if (cp[1]){
X delay = atoi (++cp);
X done = TRUE;
X }
X else {
X delay = atoi (argv[++i]);
X }
X break;
X
X case 'v': /* display version */
X version();
X exit(0);
X
X case '?': /* usage */
X case 'h':
X usage();
X exit(0);
X
X default:
X fprintf (stderr, "illegal option : %c; ignored.\n", *cp);
X break;
X }
X }
X }
X }
X
X /*
X * curses initialization
X */
X initscr();
X cbreak();
X noecho();
X nodelay (stdscr, 1);
X
X /*
X * print out a simple command menu
X */
X mvaddch (23, 0, '[');
X attrset (A_BOLD);
X addch ('m');
X attroff (A_BOLD);
X addch (',');
X attrset (A_BOLD);
X addch ('c');
X attroff (A_BOLD);
X addstr ("]=memory allocation map [");
X attrset (A_BOLD);
X addch ('s');
X attroff (A_BOLD);
X addstr ("]=swap allocation map [");
X attrset (A_BOLD);
X addch ('q');
X attroff (A_BOLD);
X addch (',');
X attrset (A_BOLD);
X addch ('x');
X attroff (A_BOLD);
X addch (',');
X attrset (A_BOLD);
X addch ('e');
X attrset (A_NORMAL);
X addstr ("]=exit");
X
X /*
X * now that curses is initialized, catch the interrupt signal
X * so we can die gracefully
X */
X signal (SIGINT, interrupt);
X signal (SIGQUIT, interrupt);
X signal (SIGHUP, interrupt);
X signal (SIGTERM, interrupt);
X
X /*
X * get ready to access kernel memory
X */
X open_kmem();
X get_nlist ();
X init_kmem();
X}
X
Xint main (argc, argv)
Xint argc;
Xchar *argv[];
X{
X struct tm *tmbuf; /* to hold current time */
X time_t tm;
X boolean done = FALSE; /* will be nonzero when ready to quit */
X int mem_or_swap = 0; /* 0 = display core map, 1 = swap map */
X int free = 0; /* free items in allocation map */
X
X init (argc, argv);
X while (!done){
X
X /*
X * get and display current time
X */
X time (&tm);
X tmbuf = localtime (&tm);
X move (0,0);
X clrtoeol();
X mvprintw (0, 67, "%02d:%02d:%02d", tmbuf->tm_hour, tmbuf->tm_min, tmbuf->tm_sec);
X
X if (mem_or_swap == 0){
X
X /*
X * update and display core map
X */
X read_map (namelist[CORE_MAP].n_value, cmapbf, CMAPSIZE);
X free = interpret_map (dmap, cmapbf, core_scale);
X standout();
X mvaddstr (0, 31, "Memory Allocation");
X standend();
X move (1,0);
X clrtoeol();
X mvprintw (1, 0, "Total Memory = %ld KBytes, %ld Kernel, %ld Free",
X ((long)kphysmem*NBPC)/1024,
X ((long)(kphysmem-kmaxmem)*NBPC)/1024,
X ((long)free*NBPC)/1024);
X mvprintw (1, 58, "Scale Factor = %2d", core_scale);
X print_map (dmap, core_scale*NBPC, (long)kphysmem*NBPC);
X }
X else {
X
X /*
X * update and display swap map
X */
X read_map (namelist[SWAP_MAP].n_value, smapbf, SMAPSIZE);
X free = interpret_map (dmap, smapbf, swap_scale);
X standout();
X mvaddstr (0, 29, "Swap Device Allocation");
X standend();
X move (1,0);
X clrtoeol();
X mvprintw (1, 0, "Total swap space = %d Blocks, %d Free", knswap, free);
X mvprintw (1, 58, "Scale Factor = % d", swap_scale);
X print_map (dmap, swap_scale, (long)knswap);
X }
X
X /*
X * refresh the screen and wait a while
X */
X refresh();
X sleep (delay);
X
X /*
X * look for any new commands
X */
X switch (getch()){
X case 'c': /* switch to core (memory) map */
X case 'm':
X mem_or_swap = 0;
X break;
X
X case 's': /* switch to swap map */
X mem_or_swap = 1;
X break;
X
X case 'q': /* quit */
X case 'e':
X case 'x':
X done = TRUE;
X break;
X
X default: /* illegal command, ignore it */
X break;
X }
X
X }
X move (0,0);
X clrtobot();
X refresh();
X endwin();
X}
X
END_OF_mapmem.c
if test 12856 -ne `wc -c <mapmem.c`; then
echo shar: \"mapmem.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 1 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mike Young
Software Development Technologies, Inc., Sudbury MA Tel: +1 508 443 5779
Internet: mjy at sdti.sdti.com UUCP: {harvard,mit-eddie}!sdti!mjy
More information about the Comp.sources.misc
mailing list