[comp.unix.i386] core and swap map program needed

scottc@bnlux0.bnl.gov (david scott coburn) (06/12/90)

I am looking for a program that will display information on how core
and swap memory is being used.  I am about to increase the disk capacity
on my system, so I would like to know if I need to allocate more (or
less, if possible) swap space.  I am also considering increasing the
ram size, and I would like to know if this is really neccesary.

A nice visual representation of the allocations would be nice, but not
neccesary.  I saw a program called 'mapmem' or such go by in comp.unix.
sources (I think).  It was exactly what I wanted, but it only worked
on an AT&T 3B2 or such...

I would also be interested in any information on where and how the kernel
stores the lists of available and used core and swap memory.

I am running INTERACTIVE UNIX 386/ix version 2.0.2 (UNIX V.3.2) on an
Intel 302-25.  Any info would be welcome.

Thanks,

scott coburn                                brookhaven national laboratory
scottc@max.bnl.gov [130.199.128.6]                          upton, ny, usa

cpcahil@virtech.uucp (Conor P. Cahill) (06/13/90)

In article <1929@bnlux0.bnl.gov> scottc@bnlux0.bnl.gov (david scott coburn) writes:
>I am looking for a program that will display information on how core
>and swap memory is being used.  I am about to increase the disk capacity
>on my system, so I would like to know if I need to allocate more (or
>less, if possible) swap space.  I am also considering increasing the
>ram size, and I would like to know if this is really neccesary.

First off, changing the amount of disk capacity has no effect on the swap
requirements for your system (unless you didn't allocate the proper 
amount of swap when you initially setup your system).  

Placing the following commands into a crontab for "sys" will get you
a nightly report of all of the system activity on you system.  Feel
free to modify the arguments as you feel fit (be sure to read the 
sar and sadp man pages).

	0,15,30,45 * * * * /usr/lib/sa/sa1
	30 23 * * * /usr/lib/sa/sa2 -ubycwaqvmpr

The first line takes samples every 15 minutes and the second line
prints out the nightly report.


-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

staceyc@sco.COM (Stacey Campbell) (06/15/90)

In article <1929@bnlux0.bnl.gov> scottc@bnlux0.bnl.gov (david scott coburn) writes:
>I am looking for a program that will display information on how core
>and swap memory is being used.
>
>A nice visual representation of the allocations would be nice, but not
>neccesary.
>
>I would also be interested in any information on where and how the kernel
>stores the lists of available and used core and swap memory.

Here's a program to display such things.  It uses the latest color curses
on System V.3.2, and compiles and runs on an AT&T 3b2 and SCO Unix/386.
It will almost certainly run under Interactive's 386 V.3.2 port.
The program is pre-pre-alpha, the code's not buggy, just ugly in spots.
Eventually a rewrite with bulk extensions will be submitted to one of
the source groups, so comments on this sucker would be appreciated.

It displays cpu usage, free RAM, free swap pages, pages swapped in
since boot, maximum RAM, size of runqueue etc.  It looks good on a
color terminal or console, but is also quite presentable on a normal
terminal.

It needs to read /unix and /dev/kmem which are nicely hardwired into
the code.  It does updates every 5 seconds (also hardwired), you may
want to increase that to at least 10+.

Have fun,

Stacey Campbell

#!/bin/sh
# this is a shell archive
#
# This archive contains:
#	Makefile
#	mon.c
#	color.c
#	consts.h
#	funcs.h
#
PATH=/bin:$PATH
echo 'mshar: extracting Makefile (size: 146)'
sed 's/^X//' << 'GURK' > Makefile &&
XOBJS= mon.o color.o
XEXE= mon
XCFLAGS= -g
XLDLIBS= -lcurses
X
X$(EXE): $(OBJS)
X	cc $(CFLAGS) $(OBJS) -o $(EXE) $(LDLIBS)
X
Xclean:
X	rm -f $(EXE) $(OBJS)
GURK
chmod 0644 Makefile || echo 'restore of Makefile fails'
echo 'mshar: extracting mon.c (size: 10687)'
sed 's/^X//' << 'GURK' > mon.c &&
X#include <fcntl.h>
X#include <a.out.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/sysinfo.h>
X#include <sys/sysmacros.h>
X#include <sys/immu.h>
X#include <sys/utsname.h>
X#include <errno.h>
X#include <curses.h>
X#include "consts.h"
X
X#define CPU_INFO_SZ (sizeof(sysinfo.cpu) / sizeof(sysinfo.cpu[0]))
X#define DEFAULT_HZ "60"
X
X#define GRPH_LINES 9
X#define GRPH_COLS 20
X#define MAP_LINES (GRPH_LINES - 2)
X#define MAP_COLS (GRPH_COLS - 1)
X
X#define DEFAULT_REFRESH 5
X#define HEADER "Monitor"
X
Xextern long lseek();
Xextern char *getenv();
X
Xextern int GreenBlackPair;
Xextern int RedBlackPair;
X
X
Xstruct sysinfo sysinfo;  /* need to declare these to deal with sys/sysinfo.h */
Xtime_t lbolt;            /* extern declarations */
Xstruct minfo minfo;
Xint nswap;
Xint maxmem;
Xint freemem;
X
Xstatic struct nlist NlistInfo[] = {
X#define NL_SYSINFO 0
X	{"sysinfo"},
X#define NL_LBOLT 1
X	{"lbolt"},
X#define NL_MINFO 2
X	{"minfo"},
X#define NL_NSWAP 3
X	{"nswap"},
X#define NL_FREEMEM 4
X	{"freemem"},
X#define NL_MAXMEM 5
X	{"maxmem"},
X	{0}};
X
Xtypedef WINDOW * display_t;
Xtypedef struct cpu_stats_t {
X	double user;
X	double kernel;
X	double idle;
X	} cpu_stats_t;
Xtypedef struct grph_win_t {
X	WINDOW *back;
X	WINDOW *top;
X	int col;
X	} grph_win_t;
X
X#ifdef DEBUG
X#define sleep(n) {time_t d = time((time_t *)0) + n ; while\
X    (d >= time((time_t *)0));}
X#endif
X
Xstatic int NlistLoaded = 0;
Xstatic int KmemFd;
Xstatic time_t SavedCpu[CPU_INFO_SZ];
Xstatic time_t BootTime;
Xstatic int Hertz;
Xstatic time_t Now;
Xstatic int OptNoColor = 0;
X
Xstatic void DisplayAdd();
Xstatic void InitGraphWin();
Xstatic void UpdateGraph();
Xstatic void XtraInfoFn();
X
Xint main(argc, argv)
X
Xint argc;
Xchar *argv[];
X
X	{
X	char head[sizeof(HEADER) + sizeof(struct utsname) + 32];
X	struct utsname name;
X	grph_win_t user_win, kernel_win, swap_win, mem_win;
X	cpu_stats_t cpu_stats;
X	double free_swap;
X	double free_memory;
X
X	if (uname(&name) == -1)
X		{
X		perror(argv[0]);
X		exit(1);
X		}
X	initscr();
X	waddstr(stdscr, "initialising...");
X	wrefresh(stdscr);
X	if (start_color() != OK)
X		OptNoColor = 1;
X	else
X		if (! has_colors())
X			OptNoColor = 1;
X		else
X			ColorMapInit();
X	Now = time((time_t *)0);
X	if (! NlistFnInit(stdscr))
X		exit(1);
X	wmove(stdscr, 0, 0);
X	wclrtoeol(stdscr);
X	mvwaddstr(stdscr, 0, 0, "wait...");
X	wrefresh(stdscr);
X	InitGraphWin(&user_win, 2, 0, "User CPU %");
X	InitGraphWin(&kernel_win, 2, GRPH_COLS + 2, "Kernel CPU %");
X	InitGraphWin(&swap_win, 2, (GRPH_COLS + 2) * 2, "Free swap pages %");
X	InitGraphWin(&mem_win, 2 + GRPH_LINES + 1, 0, "Free memory %");
X	sleep(2);
X	curs_set(FALSE);
X	werase(stdscr);
X	sprintf(head, "%s - %s %s Unix %s.%s", HEADER, name.sysname,
X	    name.machine, name.release, name.version);
X	wstandout(stdscr);
X	mvwaddstr(stdscr, 0, (COLS - strlen(head)) / 2 - 1, head);
X	wstandend(stdscr);
X	wrefresh(stdscr);
X	wrefresh(user_win.back);
X	wrefresh(kernel_win.back);
X	wrefresh(swap_win.back);
X	wrefresh(mem_win.back);
X	for (;;)
X		{
X		Now = time((time_t *)0);
X		(void)NlistFn(stdscr, &cpu_stats);
X		XtraInfoFn(stdscr, &free_swap, &free_memory);
X		UpdateGraph(&user_win, cpu_stats.user, FIELD_HOT);
X		UpdateGraph(&kernel_win, cpu_stats.kernel, FIELD_HOT);
X		UpdateGraph(&swap_win, free_swap, FIELD_COLD);
X		UpdateGraph(&mem_win, free_memory, FIELD_COLD);
X		wmove(stdscr, LINES - 1, 0);
X		wrefresh(stdscr);
X		sleep(DEFAULT_REFRESH);
X		}
X	endwin();
X	}
X
Xstatic void XtraInfoFn(win, free_swap, free_memory)
X
XWINDOW *win;
Xdouble *free_swap;
Xdouble *free_memory;
X
X	{
X	if (lseek(KmemFd, NlistInfo[NL_MINFO].n_value, 0) == -1L)
X		{
X		DisplayAdd(win, "kmem lseek error ");
X		flash();
X		return;
X		}
X	if (read(KmemFd, (char *)&minfo, sizeof(minfo)) < 0)
X		{
X		DisplayAdd(win, "kmem read error ");
X		flash();
X		return;
X		}
X	if (lseek(KmemFd, NlistInfo[NL_FREEMEM].n_value, 0) == -1L)
X		{
X		DisplayAdd(win, "kmem lseek error ");
X		flash();
X		return;
X		}
X	if (read(KmemFd, (char *)&freemem, sizeof(freemem)) < 0)
X		{
X		DisplayAdd(win, "kmem read error ");
X		flash();
X		return;
X		}
X	wmove(win, LINES - 3, 0);
X	wprintw(win, "free swap: %ld nswap: %ld maxmem: %ld freemem: %ld      ",
X	    minfo.freeswap, nswap, ctob(maxmem) / NBPP, freemem);
X	*free_swap = minfo.freeswap / (double)nswap;
X	*free_memory = freemem / (double)(ctob(maxmem) / NBPP);
X	wrefresh(win);
X	}
X
Xstatic void UpdateGraph(grph_win, level, field)
X
Xgrph_win_t *grph_win;
Xdouble level;
Xint field;
X
X	{
X	int i;
X	int spot_y, spot_x;
X	double scale;
X
X	spot_y = (double)MAP_LINES - (level * (double)MAP_LINES)
X	    + 0.5;
X	if (spot_y >= MAP_LINES)
X		spot_y = MAP_LINES - 1;
X	else
X		if (spot_y < 0)
X			spot_y = 0;
X	spot_x = grph_win->col;
X	if (spot_x >= MAP_COLS)
X		{
X		spot_x = MAP_COLS - 1;
X		for (i = 0; i < MAP_LINES; ++i)
X			mvwdelch(grph_win->top, i, 0);
X		}
X	grph_win->col = spot_x + 1;
X	if (OptNoColor)
X		{
X		wstandout(grph_win->top);
X		for (i = spot_y; i < MAP_LINES; ++i)
X			mvwaddch(grph_win->top, i, spot_x, ' ');
X		wstandend(grph_win->top);
X		}
X	else
X		for (i = spot_y; i < MAP_LINES; ++i)
X			{
X			scale = 1.0 - i / (double)(MAP_LINES - 1);
X			FillColor(grph_win->top, scale, i, spot_x, field);
X			}
X	wrefresh(grph_win->top);
X	}
X
Xint NlistFnInit(display)
X
Xdisplay_t *display;
X
X	{
X	int i;
X	char *hz_str;
X	struct sysinfo sysinfo;
X	static int kmem_status = 0;
X
X	if (! NlistLoaded)
X		{
X		NlistLoaded = 1;
X		if (nlist("/unix", NlistInfo) < 0)
X			{
X			DisplayAdd(display, "nlist error ");
X			return 0;
X			}
X		if (NlistInfo[NL_SYSINFO].n_value == 0)
X			{
X			DisplayAdd(display, "bad sysinfo offset ");
X			flash();
X			return 0;
X			}
X		if (NlistInfo[NL_LBOLT].n_value == 0)
X			{
X			DisplayAdd(display, "bad lbolt offset ");
X			flash();
X			return 0;
X			}
X		if (! (hz_str = getenv("HZ")))
X			hz_str = DEFAULT_HZ;
X		Hertz = atoi(hz_str);
X		if ((KmemFd = open("/dev/kmem", O_RDONLY)) < 0)
X			{
X			DisplayAdd(display, "cannot open kmem ");
X			return 0;
X			}
X		if (lseek(KmemFd, NlistInfo[NL_SYSINFO].n_value, 0) == -1L)
X			{
X			char buf[128];
X			extern char *sys_errlist[];
X
X			sprintf(buf, "kmem lseek error %d %s %u ", errno,
X			    sys_errlist[errno], NlistInfo[NL_SYSINFO].n_value);
X			DisplayAdd(display, buf);
X			flash();
X			return 0;
X			}
X		if (read(KmemFd, (char *)&sysinfo, sizeof(sysinfo)) < 0)
X			{
X			DisplayAdd(display, "kmem read error ");
X			flash();
X			return 0;
X			}
X		for (i = 0; i < CPU_INFO_SZ; ++i)
X			SavedCpu[i] = sysinfo.cpu[i];
X		if (lseek(KmemFd, NlistInfo[NL_MINFO].n_value, 0) == -1L)
X			{
X			char buf[128];
X			extern char *sys_errlist[];
X
X			sprintf(buf, "kmem lseek error %d %s %u ", errno,
X			    sys_errlist[errno], NlistInfo[NL_MINFO].n_value);
X			DisplayAdd(display, buf);
X			flash();
X			return 0;
X			}
X		if (read(KmemFd, (char *)&minfo, sizeof(minfo)) < 0)
X			{
X			DisplayAdd(display, "kmem read error ");
X			flash();
X			return 0;
X			}
X		if (lseek(KmemFd, NlistInfo[NL_NSWAP].n_value, 0) == -1L)
X			{
X			char buf[128];
X			extern char *sys_errlist[];
X
X			sprintf(buf, "kmem lseek error %d %s %u ", errno,
X			    sys_errlist[errno], NlistInfo[NL_NSWAP].n_value);
X			DisplayAdd(display, buf);
X			flash();
X			return 0;
X			}
X		if (read(KmemFd, (char *)&nswap, sizeof(nswap)) < 0)
X			{
X			DisplayAdd(display, "kmem read error ");
X			flash();
X			return 0;
X			}
X		if (lseek(KmemFd, NlistInfo[NL_MAXMEM].n_value, 0) == -1L)
X			{
X			char buf[128];
X			extern char *sys_errlist[];
X
X			sprintf(buf, "kmem lseek error %d %s %u ", errno,
X			    sys_errlist[errno], NlistInfo[NL_MAXMEM].n_value);
X			DisplayAdd(display, buf);
X			flash();
X			return 0;
X			}
X		if (read(KmemFd, (char *)&maxmem, sizeof(maxmem)) < 0)
X			{
X			DisplayAdd(display, "kmem read error ");
X			flash();
X			return 0;
X			}
X
X		kmem_status = 1;
X		}
X
X	return kmem_status;
X	}
X
Xint NlistFn(display, cpu_stats)
X
Xdisplay_t *display;
Xcpu_stats_t *cpu_stats;
X
X	{
X	int i;
X	time_t all_krn;
X	struct sysinfo sysinfo;
X	time_t new_cpu[CPU_INFO_SZ];
X	double total_cpu;
X
X	if (lseek(KmemFd, NlistInfo[NL_SYSINFO].n_value, 0) == -1L)
X		{
X		DisplayAdd(display, "kmem lseek error ");
X		flash();
X		return 0;
X		}
X	if (read(KmemFd, (char *)&sysinfo, sizeof(sysinfo)) < 0)
X		{
X		DisplayAdd(display, "kmem read error ");
X		flash();
X		return 0;
X		}
X
X	total_cpu = 0.0;
X	for (i = 0; i < CPU_INFO_SZ; ++i)
X		{
X		total_cpu += new_cpu[i] = sysinfo.cpu[i] - SavedCpu[i];
X		SavedCpu[i] = sysinfo.cpu[i];
X		}
X
X	cpu_stats->user = new_cpu[CPU_USER] / total_cpu;
X#ifndef PARTIAL
X	all_krn = new_cpu[CPU_KERNEL] + new_cpu[CPU_WAIT] + new_cpu[CPU_SXBRK];
X#else
X	all_krn = new_cpu[CPU_KERNEL];
X#endif
X	cpu_stats->kernel = all_krn / total_cpu;
X	cpu_stats->idle = new_cpu[CPU_IDLE] / total_cpu;
X	wmove(stdscr, LINES - 2, 0);
X	wprintw(stdscr, "swapin: %ld", sysinfo.swapin);
X	wmove(stdscr, LINES - 1, 0);
X	wprintw(stdscr, "runque: %ld", sysinfo.runque);
X	wrefresh(stdscr);
X
X	return 1;
X	}
X
Xint UptimeFnInit(display)
X
Xdisplay_t *display;
X
X	{
X	time_t lbolt;                     /* a contraction of lightning bolt */
X
X	if (NlistFnInit(display) == 0)
X		return 0;
X
X	if (lseek(KmemFd, NlistInfo[NL_LBOLT].n_value, 0) == -1L)
X		{
X		DisplayAdd(display, "kmem lbolt lseek error ");
X		flash();
X		return 0;
X		}
X	if (read(KmemFd, (char *)&lbolt , sizeof(lbolt)) < 0)
X		{
X		DisplayAdd(display, "kmem lbolt read error ");
X		flash();
X		return 0;
X		}
X
X	BootTime = Now - lbolt / Hertz;
X	if (BootTime < 0)
X		DisplayAdd(display, "very strange boottime ");
X
X	return 1;
X	}
X
Xint UptimeFn(display)
X
Xdisplay_t *display;
X
X	{
X	time_t lbolt;
X	time_t uptime;
X	int days, hours, minutes, seconds;
X	char buf[64];
X
X	uptime = Now - BootTime;
X	days = uptime / (60 * 60 * 24);
X	uptime -= days * (60 * 60 * 24);
X	hours = uptime / (60 * 60);
X	uptime -= hours * (60 * 60);
X	minutes = uptime / 60;
X	uptime -= minutes * 60;
X	seconds = uptime;
X	sprintf(buf, "ut: %d+%.2d:%.2d:%.2d ", days, hours, minutes, seconds);
X	DisplayAdd(display, buf);
X
X	return 1;
X	}
X
Xstatic void DisplayAdd(display, msg)
X
XWINDOW *display;
Xchar *msg;
X
X	{
X	wprintw(stdscr, "%s\n", msg);
X	wrefresh(stdscr);
X	}
X
Xstatic void InitGraphWin(win, start_y, start_x, label)
X
Xgrph_win_t *win;
Xint start_y;
Xint start_x;
Xchar *label;
X
X	{
X	int i, j;
X	int len;
X
X	win->back = newwin(GRPH_LINES, GRPH_COLS, start_y, start_x);
X	if (! OptNoColor)
X		wattron(win->back, COLOR_PAIR(GreenBlackPair));
X	for (i = 0; i < MAP_LINES + 1; ++i)
X		mvwaddch(win->back, i, 0, ACS_VLINE);
X	for (i = 0; i < MAP_COLS + 1; ++i)
X		mvwaddch(win->back, MAP_LINES, i, ACS_HLINE);
X	mvwaddch(win->back, MAP_LINES, 0, ACS_LLCORNER);
X	if (! OptNoColor)
X		wattroff(win->back, COLOR_PAIR(GreenBlackPair));
X	win->top = newwin(MAP_LINES, MAP_COLS, start_y, start_x + GRPH_COLS
X	    - MAP_COLS);
X	win->col = 0;
X	len = strlen(label);
X	if (! OptNoColor)
X		wattron(win->back, COLOR_PAIR(RedBlackPair));
X	mvwaddstr(win->back, GRPH_LINES - 1, (GRPH_COLS - len) / 2, label);
X	if (! OptNoColor)
X		wattroff(win->back, COLOR_PAIR(RedBlackPair));
X	}
GURK
chmod 0644 mon.c || echo 'restore of mon.c fails'
echo 'mshar: extracting color.c (size: 1688)'
sed 's/^X//' << 'GURK' > color.c &&
X#include <curses.h>
X#include "consts.h"
X
X#define PAIR_COUNT (sizeof(PairsList) / sizeof(PairsList[0]))
X#define PR_CNT2ID(pair) ((pair) + 1)
X
Xextern char *malloc();
X
Xint GreenBlackPair;
Xint RedBlackPair;
Xstatic int ColdPair;
X
Xtypedef struct pairs_t {
X	unsigned long fg;
X	unsigned long bg;
X	} pairs_t;
X
Xstatic pairs_t PairsList[] = {
X	{COLOR_BLACK, COLOR_YELLOW},
X	{COLOR_BLACK, COLOR_RED},
X	{COLOR_BLACK, COLOR_MAGENTA}};
X
Xvoid ColorMapInit()
X
X	{
X	int i;
X	int id;
X
X	for (i = 0; i < PAIR_COUNT; ++i)
X		{
X		id = PR_CNT2ID(i);
X		if (init_pair(id, PairsList[i].fg, PairsList[i].bg) != OK)
X			{
X			endwin();
X			fprintf(stderr, "init_pair: %d failed\n", id);
X			exit(0);
X			}
X		}
X	GreenBlackPair = PR_CNT2ID(PAIR_COUNT);
X	if (init_pair(GreenBlackPair, COLOR_GREEN, COLOR_BLACK) != OK)
X		{
X		endwin();
X		fprintf(stderr, "init_pair: %d failed\n", GreenBlackPair);
X		exit(0);
X		}
X	ColdPair = PR_CNT2ID(PAIR_COUNT + 1);
X	if (init_pair(ColdPair, COLOR_BLACK, COLOR_CYAN) != OK)
X		{
X		endwin();
X		fprintf(stderr, "init_pair: %d failed\n", ColdPair);
X		exit(0);
X		}
X	RedBlackPair = PR_CNT2ID(PAIR_COUNT + 2);
X	if (init_pair(RedBlackPair, COLOR_RED, COLOR_BLACK) != OK)
X		{
X		endwin();
X		fprintf(stderr, "init_pair: %d failed\n", RedBlackPair);
X		exit(0);
X		}
X	}
X
Xint FillColor(win, scale, y, x, field)
X
XWINDOW *win;
Xdouble scale;
Xint y, x;
Xint field;
X
X	{
X	int pair;
X	int pair_id;
X
X	if (field == FIELD_HOT)
X		{
X		pair = scale * (double)PAIR_COUNT;
X		if (pair >= PAIR_COUNT)
X			pair = PAIR_COUNT - 1;
X		else
X			if (pair < 0)
X				pair = 0;
X		pair_id = PR_CNT2ID(pair);
X		}
X	else
X		pair_id = ColdPair;
X
X	wattron(win, COLOR_PAIR(pair_id));
X	mvwaddch(win, y, x, ' ');
X	wattroff(win, COLOR_PAIR(pair_id));
X	}
GURK
chmod 0644 color.c || echo 'restore of color.c fails'
echo 'mshar: extracting consts.h (size: 41)'
sed 's/^X//' << 'GURK' > consts.h &&
X#define FIELD_HOT 0
X#define FIELD_COLD 1
GURK
chmod 0644 consts.h || echo 'restore of consts.h fails'
echo 'mshar: extracting funcs.h (size: 39)'
sed 's/^X//' << 'GURK' > funcs.h &&
Xvoid ColorMapInit();
Xvoid FillColor();
GURK
chmod 0644 funcs.h || echo 'restore of funcs.h fails'
exit 0
-- 
Stacey Campbell       staceyc@sco.com
{uunet,decwrl,ucscc,att,sq,altos,lotus,phoenix,sun,microsoft,xbs}!sco!staceyc