MEMAP: 11/70 RealTime Memory Map

5 views
Skip to first unread message

we13!rjk

unread,
Apr 19, 1982, 2:45:39 PM4/19/82
to
/***********************************************************************
* 11/70 MEMAP - REAL TIME MEMORY MAP
* FILE 1 of 5 - README
***********************************************************************
*/
Memap is an active real-time (?) UNIX memory map. It displays the
locations of processes in memory, updating changes once per second.
A DEC VT100 with advanced video option is required for this program.

Memaptest is a little demo program for memap. It is compiled with
separate I/D space.

Read the comment lines in the makefile; they tell you how to make
the files. When completed, type the following for a demonstration:

for X in 1 2 3
do sleep 10
/etc/memaptest
done & /etc/memap

This starts three of the demo programs so that the shared text segment
can be seen. When all but the last one dies, the shared text will
start flashing, then it will disappear with the death of the last one.

For more info: Randy King WECo-Montgomery 8=392-4556 (we13!rjk)
/***********************************************************************
* 11/70 MEMAP - REAL TIME MEMORY MAP
* FILE 2 of 5 - Makefile
***********************************************************************
*/
#
# Memap Makefile: `Make' must be executed as root.
#
# Specify your system maximum memory in the command line as:
# make MEMORY=XXXXXXX
# Where the X's are the decimal number of bytes of physical REAL
# memory (printed at boot time as: real mem=XXXXXXX bytes). The
# default size will be 11/70 maximum of 4 Megabytes.
#
# NOTE: Edit `memap.c' and set the define NPROC to at least the
# number of slots in your process table. Default is 150.
#
# INSDIR is the directory where memap will reside. Normally, this
# is /etc to keep it out of the public eye, although the public
# can still use it. If you change INSDIR, you might also change
# the SYNOPSIS in the manual page `memap.1'.
#
# RJKing WECo-MG6565 Sep 1981
#

INSDIR=/etc
MEMORY=4194304L
MANDIR=/usr/man/local/man1

all: memap memaptest

memap:
$(CC) -DOURM=$(MEMORY) -O -n -s memap.c -o memap
@if mv $(INSDIR)/memap $(INSDIR)/OLDmemap 2>/dev/null; \
then echo $(INSDIR)/memap moved to $(INSDIR)/OLDmemap; \
fi
mv memap $(INSDIR)/memap
chown root $(INSDIR)/memap
chgrp bin $(INSDIR)/memap
chmod 4775 $(INSDIR)/memap
cp memap.1 $(MANDIR)/memap.1
chown bin $(MANDIR)/memap.1
chgrp bin $(MANDIR)/memap.1
chmod 664 $(MANDIR)/memap.1

memaptest:
$(CC) -O -n -s memaptest.c -o memaptest
@if mv $(INSDIR)/memaptest $(INSDIR)/OLDmemaptest 2>/dev/null; \
then echo $(INSDIR)/memaptest move to $(INSDIR)/OLDmemaptest; \
fi
mv memaptest $(INSDIR)/memaptest
chown bin $(INSDIR)/memaptest
chgrp bin $(INSDIR)/memaptest
chmod 775 $(INSDIR)/memaptest
/***********************************************************************
* 11/70 MEMAP - REAL TIME MEMORY MAP
* FILE 3 of 5 - memap.c
***********************************************************************
*/
/* Memap - Real time (?) UNIX memory map. This program produces a
* real time display of the active system memory as near as can be
* obtained. It is restricted to the VT100 terminal with advanced
* video. RJKing WECO-MG6565 Sep 1981
*/

#include <stdio.h>
#include <fcntl.h>
#include <a.out.h>
#include <sys/utsname.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/text.h>
#include <sys/file.h>
#include <sys/inode.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/dir.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/var.h>

#define NROW 23 /* # of rows in display */
#define NCOL 13 /* # of columns in display */
#define VOID (char *)0 /* Char NULL pointer */
#define NPROC 150 /* MAIN: Dimension for proc slots */
#define MAXM 4194304L /* MAIN: Max 11/70 MAIN memory */
#ifndef OURM
#define OURM 3145728L /* MAIN: Our maximum memory */
#endif
#define CSIZ (132 /NCOL) /* SHOW: Column width */
#define NSIZ (CSIZ -1) /* SHOW: Max process name length */
#define DRAW 001 /* SHOW[what]: Draw grid ticks */
#define ERAS 002 /* SHOW[what]: Erase at [addr] */
#define PRNT 004 /* SHOW[what]: Print at [addr] */
#define KERN 010000 /* SHOW[mode]: This proc is kernel */
#define TEXT 020000 /* SHOW[slot]: This proc has sep I/D */
#define DATA 040000 /* UPDATE[what]: update non-text */
#define ENDM 0001 /* SHOW: Screen position is END mark */
#define PRCM 0002 /* SHOW: Screen position is process */
#define TXTM 0004 /* SHOW: Screen position is text */
#define PROC 0 /* MAIN: Index to nl struct */
#define SBUF 1 /* MAIN: Index to nl struct */
#define ENDT 2 /* MAIN: Index to nl struct */
#define UTXS 3 /* MAIN: Index to nl struct */
#define TXTT 4 /* MAIN: Index to nl struct */
#define VARA 5 /* MAIN: Index to nl struct */
#define USER 6 /* MAIN: Index to nl struct */
#define NNLE 7 /* MAIN: Number of namelist entries */

int tmem,catch(); /* Signal catching routine */
char position[NROW][NCOL]; /* "position occupied" flags */
long maxmem=OURM; /* Default screen resolution */
struct nlist nl[] = { { "_proc" },
{ "_sabuf" },
{ "_etext" },
{ "tstart" },
{ "_text" },
{ "_v" },
{ "_u" },
{ "" }
};
struct savp { char p_stat, p_flag;
short p_pid;
ushort p_addr, p_size;
ushort x_size, x_caddr;
char x_count;
} savp[NPROC];
struct proc newp;
struct text newt;
struct var var;
struct user ub;

char *getenv(),*strcpy(),*malloc(),*strncpy(),*strcat(),*strncat(),*ctime();
long lseek(),atol(),time();
unsigned sleep();
extern (*signal())();
extern optind,errno;
extern char *optarg;
main(argc,argv)
char *argv[];
{ register int i,slot;
register char *tp;
int smem,umem;
long t,addr,size;
struct utsname uts;
unsigned mode;

if(strcmp(getenv("TERM"), "vt100") != 0)
{ fprintf(stderr, "Term not vt100\n");
exit(1);
}
uname(&uts);
smem = open("/dev/mem", O_RDONLY);
umem = open("/dev/mem", O_RDONLY);
tmem = open("/dev/mem", O_RDONLY);
if(smem < 0 || umem < 0 || tmem < 0)
{ perror("/dev/mem");
exit(errno);
}
while((i = getopt(argc,argv,"t:m:")) != EOF)
{ switch(i)
{
case 't': maxmem = atol(optarg) *(long)(NCOL *NROW);
break;
case 'm': maxmem = atol(optarg);
break;
default: fprintf(stderr,
"usage: %s [ -tTIKSIZ ] [ -mMEMSIZ ]\n",
argv[0]);
exit(1);
}
if(i == 't' || i == 'm')
{ i = strlen(optarg);
if(optarg[i-1] == 'm' || optarg[i-1] == 'M')
maxmem *= 1048576;
if(optarg[i-1] == 'k' || optarg[i-1] == 'K')
maxmem *= 1024;
}
}
argc -= (optind -1); argv += (optind -1);
if(maxmem > MAXM || maxmem < 1)
{ fprintf(stderr, "%d bytes out of range\n", maxmem);
exit(1);
}
for(i=1; i<=NSIG; ++i)
signal(i, catch);
nlist("/unix", nl);
for(i=0; i<NNLE; ++i)
if(nl[i].n_type == 0)
{ fprintf(stderr, "namelist error on %s\n", nl[i].n_name);
exit(1);
}
if(lseek(smem, (long)nl[VARA].n_value, 0) < 0)
fatalerr("seek to _v");
if(read(smem, (char *)&var, sizeof(var)) < 0)
fatalerr("read _v");
if(var.v_proc > NPROC)
{ fprintf(stderr, "NPROC define must be at least %d\n",
var.v_proc);
exit(1);
}
if(NPROC > var.v_proc +25)
{ fprintf(stderr,
"NPROC define wasting memory; should be around %d\n",
var.v_proc);
sleep(5);
}
show(DRAW, VOID, 0L, 0L, NULL);
show(PRNT, "Proctbl", (long)nl[PROC].n_value, 0L, KERN);
show(PRNT, "_sabufs", (long)nl[SBUF].n_value, 0L, KERN);
show(PRNT, "EndOfText", (long)nl[ENDT].n_value, 0L, KERN);
show(PRNT, uts.sysname, (long)nl[UTXS].n_value, 0L, KERN);
addr = (long)(nl[USER].n_value + USIZE *64);
show(PRNT, "Stack_Top", addr, 0L, KERN);
i = nice(0);
nice(-i);
for(;;)
{ if(lseek(smem, (long)nl[PROC].n_value, 0) < 0)
fatalerr("seek to process table");
for(slot=0; slot<var.v_proc; ++slot)
{
if(read(smem, (char *)&newp, sizeof(newp)) < 0)
fatalerr("read process table");
if(sameproc(slot))
continue;
if(savp[slot].p_addr)
{ addr = ctob((long)savp[slot].p_addr);
size = ctob((long)savp[slot].p_size);
show(ERAS, VOID, addr, size, NULL);
if((savp[slot].x_count == 1) &&
(savp[slot].x_caddr >= 1))
{ addr = ctob((long)savp[slot].x_caddr);
size = ctob((long)savp[slot].x_size);
show(ERAS, VOID, addr, size, NULL);
savp[slot].x_count = 0;
}
}
if((newp.p_flag &SLOAD) == 0)
{ clearout(slot);
continue;
}
if(newp.p_addr)
{ addr = ctob((long)newp.p_addr);
size = ctob((long)newp.p_size);
mode = (unsigned)(newp.p_flag &0377);
mode |= ((newp.p_stat <<8) &07400);
if(lseek(umem, addr, 0) < 0)
fatalerr("seek to user block");
if(read(umem, (char *)&ub, sizeof(ub)) < 0)
fatalerr("read user block");
show(PRNT, ub.u_comm, addr, size, mode);
if(ub.u_tsize && getextdata())
{ addr = ctob((long)newt.x_caddr);
size = ctob((long)newt.x_size);
mode = TEXT;
show(PRNT, ub.u_comm, addr, size, mode);
update(TEXT, slot);
}
}
update(DATA, slot);
}
time(&t);
tp = ctime(&t);
*(tp+19) = NULL;
printf("\33[24;59H%s", tp+11);
sleep(1);
}
}
show(what, name, addr, size, mode)
char *name;
long addr, size;
unsigned mode;
{ register int i,swap=0;
static int ticks;
int srow, scol, erow, ecol, srpos, scpos, erpos, ecpos;
char pnam[32],flag,stat;
long check;

if(what &DRAW)
{ ticks = (int) (maxmem / ((long)(NCOL *NROW)));
printf("\33<\33[?3h");
sleep(1);
printf("\33[2J\33[24H\33#6");
printf("%d Bytes/Tick (%.2f Meg) ",
ticks, (double)maxmem /1048576.0);
printf("\33[1;7mText\33[m \33[4mLocked\33[m ");
printf("\33[7mSpecial\33[m \33[1mRunnable\33[m\33(0");
for(scol=1; scol<=NCOL; ++scol)
{ printf("\33[1;%dH", (NCOL -3) *(scol -1) +1);
for(srow=1; srow<=NROW; ++srow)
{ if(srow == 1)
printf("l\b\33D");
else if(srow == NROW)
printf("m");
else printf("t\b\33D");
}
}
printf("\33(B\33[24H\33[m");
}
flag = (char)(mode &0377);
stat = (char)((mode &07400) >>8);
check = (addr /(long)ticks) +1L;
if(check > (long)(NROW *NCOL))
return;
srow = (int)check;
check = ((addr +size) /(long)ticks) +1L;
if(check > (long)(NROW *NCOL))
return;
erow = (int)check;
for(scol=0; srow>NROW; ++scol)
srow -= NROW;
srpos = srow -1;
scpos = scol;
scol = (scol *CSIZ) +2;
for(ecol=0; erow>NROW; ++ecol)
erow -= NROW;
erpos = erow -1;
ecpos = ecol;
ecol = (ecol *CSIZ) +2;
if(*name == NULL)
{ if(newp.p_pid == 0)
name = "swapper";
else
{ name = "SWAPPING";
++swap;
}
}
if(what &ERAS)
{ printf("\33[%d;%dH\33[%d;%dH", srow, scol, srow, scol);
for(i=0; i<NSIZ; ++i)
printf(" ");
position[srpos][scpos] = 0;
if(position[erpos][ecpos] == ENDM)
{ printf("\33[%d;%dH\33[%d;%dH",
erow, ecol, erow, ecol);
for(i=0; i<NSIZ; ++i)
printf(" ");
position[erpos][ecpos] = 0;
}
}
if(what &PRNT)
{ if((mode &TEXT) && position[srpos][scpos] == TXTM)
return;
*pnam = NULL;
if(flag &SLOCK)
strcat(pnam, "\33[4m");
if(stat == SRUN)
strcat(pnam, "\33[1m");
if((mode &KERN) || swap)
strcat(pnam, "\33[7m");
if(mode &TEXT)
strcat(pnam, "\33[1;7m");
strncat(pnam, name, NSIZ);
strcat(pnam, "\33[m");
for(i=strlen(name); i<NSIZ; ++i)
strcat(pnam, " ");
printf("\33[%d;%dH\33[%d;%dH%s", srow, scol, srow, scol, pnam);
position[srpos][scpos] = (mode &TEXT)?TXTM:PRCM;
if(position[erpos][ecpos] == 0)
{ printf("\33(0\33[%d;%dH\33[%d;%dH",
erow, ecol, erow, ecol);
if(stat == SRUN)
printf("\33[1m");
if((mode &KERN) || swap)
printf("\33[7m");
for(i=0; i<NSIZ; ++i)
printf("~");
printf("\33(B\33[m");
position[erpos][ecpos] = ENDM;
}
}
}

catch(sig)
{ signal(sig, SIG_IGN);
printf("\33[?3l");
sleep(1);
exit(sig);
}

fatalerr(errms)
char *errms;
{ printf("\33[24H\33[2K");
perror(errms);
exit(errno);
}

sameproc(slot)
{ if(newp.p_stat != SSLEEP && newp.p_stat != SRUN)
{ newp.p_addr = 0;
return(0);
}
if(newp.p_flag &(SSWAP |SSPART))
{ newp.p_addr = 0;
return(0);
}
if(newp.p_stat != savp[slot].p_stat)
return(0);
if(newp.p_flag != savp[slot].p_flag)
return(0);
if(newp.p_pid != savp[slot].p_pid)
return(0);
if(newp.p_addr != savp[slot].p_addr)
return(0);
if(newp.p_size != savp[slot].p_size)
return(0);
return(1);
}

getextdata()
{ register int i;

if(lseek(tmem, (long)nl[TXTT].n_value, 0) < 0)
fatalerr("seek to text table");
for(i=0; i<var.v_text; ++i)
{ if(read(tmem, (char *)&newt, sizeof(newt)) < 0)
fatalerr("read text table");
/* Talk about SWAG: */
if(newt.x_count && newt.x_size == ub.u_tsize)
return(1);
}
return(0);
}

update(what,slot)
{ if(what == DATA)
{ savp[slot].p_stat = newp.p_stat;
savp[slot].p_flag = newp.p_flag;
savp[slot].p_pid = newp.p_pid;
savp[slot].p_addr = newp.p_addr;
savp[slot].p_size = newp.p_size;
}
if(what == TEXT)
{ savp[slot].x_size = newt.x_size;
savp[slot].x_caddr = newt.x_caddr;
savp[slot].x_count = newt.x_count;
}
}

clearout(slot)
{ savp[slot].p_stat = 0;
savp[slot].p_flag = 0;
savp[slot].p_pid = 0;
savp[slot].p_addr = 0;
savp[slot].p_size = 0;
savp[slot].x_size = 0;
savp[slot].x_caddr = 0;
savp[slot].x_count = 0;
}
/***********************************************************************
* 11/70 MEMAP - REAL TIME MEMORY MAP
* FILE 4 of 5 - memap.1
***********************************************************************
*/
.TH MEMAP 1 local
.SH NAME
.B memap\^
- display active UNIX memory
.SH SYNOPSIS
/etc/memap [ -tTIKSIZE ] [ -mMEMSIZE ]
.br
Available ONLY on a DEC VT100 with advanced video option
.SH DESCRIPTION
Memap displays the swappable image of all processes
residing in main memory, updating the display every second.
.PP
Default main memory size has been pre-defined by the system administrator.
This value may be overridden in two ways as defined below:
.TP 5
.B -t\^
TIKSIZE is the number of bytes that each scale tick mark will represent.
This number may be suffixed with a `K' or `M' for Kilo and Mega,
respectively. Sorry, no floating point specification for TIKSIZE.
.TP 5
.B -m\^
MEMSIZE is the number of bytes in main memory. This number may be suffixed
with a `K' or `M' for Kilo and Mega, respectively. Sorry, no floating
point specification for MEMSIZE.
.PP
The K and M conversions multiply the preceding value by 1024 and
1048576, respectively.
.PP
Processes appearing BOLD are those made runnable. Processes that are
underscored are currently locked in memory; usually due to a fork(2)
system call. Processes that are reverse video are
start locations of certain kernel symbols.
Processes that are displayed in bold reverse video are the text
segments of separate I/D space programs.
The kernel symbols displayed are:
.TP 15
.B Proctbl\^
(_proc) the process table
.TP 15
.B _sabufs\^
(_sabuf) system addressable buffers
.TP 15
.B EndOfText\^
(_etext) end of text symbol
.TP 15
.B {nodename}\^
(tstart) start of kernel text
.TP 15
.B (TopOfStack)
(_u + USIZE * CLICKS) top of kernel stack
.PP
Another type of process in reverse video called "SWAPPING"
is displayed when a process is in "mid-swap", so to speak.
.PP
The small dots (sometimes) appearing mark the end of the process
named above them. These may be overwritten by another process and
never appear again unless the process is swapped.
.PP
Text space is displayed only once, i.e. the first process in the
process table with separate I/D space is the one whose name is used
for text. This can be confusing for linked processes such as
"sh" and "rsh"; "ed" and "red"; etc. The user must remember that
the text for one is the text for the other.
.SH BUGS
Because the VT100 has been known to fail direct cursor addressing
in the ANSI mode on occasion, each direct cursor address is sent
twice. These extra characters make their presence known only during
high system activity and on slow ( below 2400 baud ) VT100's.
.PP
Just as is disclaimed by ps(1), things can change while memap is
running. Sometimes the display is incorrect for a moment or two.
Case in point is the process that shows up as "SWAPPING". It should
have been caught earlier and not displayed, but that's the way it goes.
/***********************************************************************
* 11/70 MEMAP - REAL TIME MEMORY MAP
* FILE 5 of 5 - memaptest.c
***********************************************************************
*/
char *malloc();

main(argc,argv)
char *argv[];
{ switch(fork())
{
case -1: perror("fork");
exit(1);
case 0: break;
default: exit(0);
}
while(malloc(512) != 0)
sleep(1);
putchar(7);
}

Reply all
Reply to author
Forward
0 new messages