RSS for System V -- does it really, really work?
Jeff Bauer
bauer at loligo
Fri Feb 10 01:20:45 AEST 1989
Here's a simple hack for System V running on an ETA-10 that shows
the actual working set of running processs. It should be somewhat
adaptable to any System V I'd think. On ETA-10s it's a necessity to know
just how much real memory a process is using (and "ps" doesn't have
bsd's nice "RSS" field!). Incidentally, anybody know how to get the size
of the proc[] table in System V (ala NPROC)? Also, is adding up the
"r_nvalid" pages for all the assigned pregions/regions of a process the
correct approach?
I stuck this in comp.bugs.sys5 to limit the audience to System V
interested readers and to see if anybody can answer these questions for
their port of SysV. Don't be offended, it's a small shar!
--- cut here ---
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# Makefile
# ws.1
# ws.1.cat
# ws.c
sed 's/^X//' << 'SHAR_EOF' > Makefile
XDEFINES=
XCFLAGS=-O
X
Xws: ws.c
X $(CC) $@.c -o $@ $(CFLAGS) $(DEFINES)
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > ws.1
X.TH WS 1
X.SH NAME
X\fBws\fR \- display process working set
X.SH USAGE
X.B ws
X[\-a] [\-t] [\-u username] [\-p process_id]
X.SH DESCRIPTION
XThe
X.I ws
Xcommand displays memory usage for a process by displaying the number of
Xpages assigned to the current working set.
XWith no options
X.I ws
Xwill display information for all processes that are not owned by "root". If
X.I \-a
Xis specified,
X.I ws
Xwill display the working set information for all processes on the system.
XThe
X.I \-u
Xoption accepts an option argument specifiying that only processes owned
Xby the specified username are to be shown. The
X.I \-p
Xoption accepts an option argument specifying that only the working set for
Xa single process ID is to be shown. The
X.I \-t
Xoption switches the output from showing individual process working sets
X(the default) to showing totals for all working sets of processes that
Xmatch the selection options above.
X.SH OUTPUT
X.TP
X.B PID
Xprocess ID.
X.TP
X.B USER
Xeffective owner of process.
X.TP
X.B SZ
Xprocess size (same as on ps(1) "the size (in pages or
Xclocks) of the swappable process's image in main memory").
X.TP
X.B WS
XThe number of actual pages in main memory for this process, ALWAYS
Xgiven in small page units, even if the process uses a combination of
Xsmall and large pages. The last five columns break down WS even more,
Xwhere each category of memory region is described by a pair of numbers,
Xseparated by a comma. The first number indicates the number of small pages
Xand the second number the number of large pages for that category.
X.TP
X.B STEXT
XThe number of small and large pages in main memory used as shared text
X(program code).
X.TP
X.B USTEXT
XThe number of small and large pages in main memory used as unshared (private)
Xtext.
X.TP
X.B DATA
XThe number of small and large pages in main memory used for data.
X.TP
X.B STACK
XThe number of small and large pages in main memory used for stack space.
X.TP
X.B OTHER
XThe number of small and large pages in main memory used for other
Xmemory types, such as shared library text, shared library
Xdata, and shared memory.
X.SH EXAMPLES
X$ ws
X.br
X PID USER SZ WS STEXT USTEXT DATA STACK OTHER
X.br
X 150 operator 8 7 4, 0 0, 0 2, 0 1, 0 0, 0
X.br
X1435 jtbauer 8 7 4, 0 0, 0 2, 0 1, 0 0, 0
X.br
X1509 tjensen 8 7 4, 0 0, 0 2, 0 1, 0 0, 0
X.br
X1538 jtbauer 5 4 1, 0 0, 0 2, 0 1, 0 0, 0
X.br
X$ ws -t -a
X.br
X SZ WS STEXT USTEXT DATA STACK OTHER
X.br
XTOTALS : 202 170 64, 0 0, 0 75, 0 31, 0 0, 0
X.br
XSmall page size = 65536 bytes (8192 words)
X.br
XLarge page size = 524288 bytes (65536 words)
X.br
XVirtual working set = 202 small pages (12 MB)
X.br
XReal working set = 170 small pages (10 MB)
X.SH CAVEATS
XPages that are part of shared text (STEXT) and shared libraries or
Xshared memory (OTHER) may be accounted for in more than one place,
Xgiving a false impression by inflating the amount of actual real memory
Xin use. This is only a problem, of course, for multiple occurrences of
Xthe same binary in different processes.
X.SH SEE ALSO
X.BR ps(1), pt(1).
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > ws.1.cat
XWS(1) USER COMMANDS WS(1)
X
X
X
XNAME
X ws - display process working set
X
XUSAGE
X ws [-a] [-t] [-u username] [-p process_id]
X
XDESCRIPTION
X The _w_s command displays memory usage for a process by
X displaying the number of pages assigned to the current work-
X ing set. With no options _w_s will display information for
X all processes that are not owned by "root". If -_a is speci-
X fied, _w_s will display the working set information for all
X processes on the system. The -_u option accepts an option
X argument specifiying that only processes owned by the speci-
X fied username are to be shown. The -_p option accepts an
X option argument specifying that only the working set for a
X single process ID is to be shown. The -_t option switches
X the output from showing individual process working sets (the
X default) to showing totals for all working sets of processes
X that match the selection options above.
X
XOUTPUT
X PID process ID.
X
X USER effective owner of process.
X
X SZ process size (same as on ps(1) "the size (in pages or
X clocks) of the swappable process's image in main
X memory").
X
X WS The number of actual pages in main memory for this pro-
X cess, ALWAYS given in small page units, even if the
X process uses a combination of small and large pages.
X The last five columns break down WS even more, where
X each category of memory region is described by a pair
X of numbers, separated by a comma. The first number
X indicates the number of small pages and the second
X number the number of large pages for that category.
X
X STEXT
X The number of small and large pages in main memory used
X as shared text (program code).
X
X USTEXT
X The number of small and large pages in main memory used
X as unshared (private) text.
X
X DATA The number of small and large pages in main memory used
X for data.
X
X STACK
X The number of small and large pages in main memory used
X for stack space.
X
X OTHER
X The number of small and large pages in main memory used
X for other memory types, such as shared library text,
X shared library data, and shared memory.
X
XEXAMPLES
X $ ws
X PID USER SZ WS STEXT USTEXT DATA STACK OTHER
X 150 operator 8 7 4, 0 0, 0 2, 0 1, 0 0, 0
X 1435 jtbauer 8 7 4, 0 0, 0 2, 0 1, 0 0, 0
X 1509 tjensen 8 7 4, 0 0, 0 2, 0 1, 0 0, 0
X 1538 jtbauer 5 4 1, 0 0, 0 2, 0 1, 0 0, 0
X
X $ ws -t -a
X SZ WS STEXT USTEXT DATA STACK OTHER
X TOTALS : 202 170 64, 0 0, 0 75, 0 31, 0 0, 0
X Small page size = 65536 bytes (8192 words)
X Large page size = 524288 bytes (65536 words)
X Virtual working set = 202 small pages (12 MB)
X Real working set = 170 small pages (10 MB)
X
XCAVEATS
X Pages that are part of shared text (STEXT) and shared
X libraries or shared memory (OTHER) may be accounted for in
X more than one place, giving a false impression by inflating
X the amount of actual real memory in use. This is only a
X problem, of course, for multiple occurrences of the same
X binary in different processes.
X
XSEE ALSO
X ps(1),pt(1).
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > ws.c
X/*
X ws.c - display working set (regions) of processes
X
X ws [-a] [-t] [-u user] [-p pid]
X
X */
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/immu.h>
X#include <sys/region.h>
X#include <sys/proc.h>
X#include <nlist.h>
X#include <pwd.h>
X
X#define PROC 0
X#define PREGPP 1
X#define MAXPRT 16
X#define TRUE 1
X#define FALSE 0
X
X/* Namelist for various kernel tables */
X
Xstruct nlist nl[] = {
X {"proc", (int32) 0, (int32) 0, (uint32) 0, (char) 0, (char) 0},
X {"pregpp", (int32) 0, (int32) 0, (uint32) 0, (char) 0, (char) 0},
X {NULL, (int32) 0, (int32) 0, (uint32) 0, (char) 0, (char) 0}
X};
X
Xstruct memuse {
X uint stext; /* shared text (pages) */
X uint ustext; /* unshared text */
X uint data; /* data pages */
X uint stack; /* stack pages */
X uint other; /* other regions : shmem, dmm, libtxt, libdat */
X};
X
X#define readmem(mem_addr, buf_addr) \
X if (lseek(mf, (long) mem_addr, 0) < 0) { \
X perror("lseek"); \
X exit(1); \
X } \
X if (read(mf, (char *) &buf_addr, sizeof(buf_addr)) < 0) { \
X perror("read"); \
X exit(1); \
X }
X
X/* Global variables */
X
Xint mf; /* memory file - /dev/kmem */
Xchar kernel_name[] = { "/unix" };
Xchar mem_name[] = { "/dev/kmem" };
Xulong pbase;
Xstruct proc *pp;
Xstruct proc pb;
Xpreg_t preg;
Xreg_t reg, *regp;
X/* pde_t pde;
Xpde_t *ptable; */
Xint pid, pregpp;
Xstruct memuse sp; /* small pages */
Xstruct memuse lp; /* large pages */
Xstruct memuse totsp;
Xstruct memuse totlp;
Xstruct memuse *mymem;
Xstruct passwd *pwe;
Xint showroot, showtot;
Xchar uname[9];
Xchar user[32];
X
X/* Externally-referenced functions */
X
Xextern long lseek();
Xextern void exit();
Xextern struct passwd *getpwuid();
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X int i, j, c;
X int ws, totws, totpsize;
X extern char *optarg;
X
X pid = 0;
X user[0] = '\0';
X showroot = FALSE;
X showtot = FALSE;
X while ((c = getopt(argc, argv, "atu:p:")) != -1)
X switch (c) {
X case 'a' :
X showroot = TRUE;
X break;
X case 't' :
X showtot = TRUE;
X break;
X case 'u' :
X strcpy(user, optarg);
X break;
X case 'p' :
X sscanf(optarg, "%d", &pid);
X break;
X }
X if (strcmp(user, "root") == 0) showroot = TRUE;
X if (showroot == TRUE) { /* override other settings */
X user[0] = '\0';
X pid = 0;
X }
X
X /* read the kernel name list, using selected symbols */
X
X if (nlist(kernel_name, nl)) {
X perror("nlist");
X exit(1);
X }
X
X if ((mf = open(mem_name, O_RDONLY)) < 0) {
X perror("open");
X exit(1);
X }
X
X if ((nl[PROC].n_value == 0) && (nl[PROC].n_type == 0)) {
X fprintf(stderr, "Symbol `proc' not found.\n");
X exit(1);
X }
X else {
X pbase = nl[PROC].n_value;
X }
X if ((nl[PREGPP].n_value == 0) && (nl[PREGPP].n_type == 0)) {
X fprintf(stderr, "Symbol `pregpp' not found.\n");
X exit(1);
X }
X else {
X readmem(nl[PREGPP].n_value, pregpp);
X if (pregpp > MAXPRT) {
X fprintf(stderr,"pregpp > MAXRT!\n");
X exit(1);
X }
X }
X
X totsp.stext = 0;
X totsp.ustext = 0;
X totsp.data = 0;
X totsp.stack = 0;
X totsp.other = 0;
X totlp.stext = 0;
X totlp.ustext = 0;
X totlp.data = 0;
X totlp.stack = 0;
X totlp.other = 0;
X totws = 0;
X totpsize = 0;
X
X if (showtot == FALSE)
X printf(" PID USER SZ WS STEXT USTEXT DATA STACK OTHER\n");
X
X for (i = 0; i < 200; i++) { /* yuck! where's NPROC defined? */
X readmem(pbase+(i*sizeof(struct proc)), pb);
X if (pb.p_pid != 0) {
X if (((pid == 0) || ((pid != 0) && (pb.p_pid == pid)))) {
X if ((showroot == FALSE) && (pb.p_suid == 0)) continue;
X
X /* Hunt through the pregions & regions of those pregions
X assigned to this process. */
X
X sp.stext = 0;
X sp.ustext = 0;
X sp.data = 0;
X sp.stack = 0;
X sp.other = 0;
X lp.stext = 0;
X lp.ustext = 0;
X lp.data = 0;
X lp.stack = 0;
X lp.other = 0;
X ws = 0;
X
X if ((pwe = getpwuid(pb.p_suid)) == NULL)
X strcpy(uname, "(bogus)");
X else
X strcpy(uname, pwe->pw_name);
X if ((user[0] != '\0') && (strcmp(user,uname) != 0)) continue;
X
X for (j = 0; j < pregpp; j++) {
X readmem((pb.p_region+j), preg);
X if (preg.p_reg != NULL) {
X readmem(preg.p_reg, reg);
X mymem = NULL;
X if ((reg.r_flags & RG_SPAGE) != 0) {
X mymem = &sp;
X ws += reg.r_nvalid;
X }
X if ((reg.r_flags & RG_LPAGE) != 0) {
X mymem = &lp;
X ws += (reg.r_nvalid * NSPPLP); /* keep ws in small pages */
X }
X if (mymem == NULL) {
X fprintf("Error - region not of small or large pages!\n");
X continue;
X }
X switch (preg.p_type) {
X case PT_TEXT :
X if (reg.r_type == RT_STEXT)
X mymem->stext += reg.r_nvalid;
X else
X mymem->ustext += reg.r_nvalid;
X break;
X case PT_DATA :
X mymem->data += reg.r_nvalid;
X break;
X case PT_STACK :
X mymem->stack += reg.r_nvalid;
X break;
X default :
X mymem->other += reg.r_nvalid;
X break;
X }
X }
X }
X totsp.stext += sp.stext;
X totsp.ustext += sp.ustext;
X totsp.data += sp.data;
X totsp.stack += sp.stack;
X totsp.other += sp.other;
X totlp.stext += lp.stext;
X totlp.ustext += lp.ustext;
X totlp.data += lp.data;
X totlp.stack += lp.stack;
X totlp.other += lp.other;
X totws += ws;
X totpsize += pb.p_size;
X
X if (showtot == FALSE)
X printf("%6d %8s %3d %3d %3d,%3d %3d,%3d %3d,%3d %3d,%3d %3d,%3d\n",
X pb.p_pid, uname, pb.p_size, ws, sp.stext, lp.stext,
X sp.ustext, lp.ustext, sp.data, lp.data, sp.stack, lp.stack,
X sp.other, lp.other);
X }
X }
X }
X if (showtot == TRUE) {
X printf(" SZ WS STEXT USTEXT DATA STACK OTHER\n");
X printf("TOTALS : %3d %3d %3d,%3d %3d,%3d %3d,%3d %3d,%3d %3d,%3d\n",
X totpsize, totws, totsp.stext, totlp.stext, totsp.ustext,
X totlp.ustext, totsp.data, totlp.data, totsp.stack, totlp.stack,
X totsp.other, totlp.other);
X printf("Small page size = %d bytes (%d words)\n", NBPP,
X (NBPP/8));
X printf("Large page size = %d bytes (%d words)\n", NBPLP,
X (NBPLP/8));
X printf("Virtual working set = %d small pages (%d MB)\n",
X totpsize, ((totpsize*NBPP)/(1024*1024)));
X printf("Real working set = %d small pages (%d MB)\n",
X totws, ((totws*NBPP)/(1024*1024)));
X }
X}
SHAR_EOF
exit
More information about the Comp.bugs.sys5
mailing list