bauer@loligo (Jeff Bauer) (02/09/89)
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
pim@ctisbv.UUCP (Pim Zandbergen) (02/10/89)
In article <566@loligo.cc.fsu.edu> bauer@loligo (Jeff Bauer) writes: >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 an AT&T 3B2/600 with System V release 3.1.1, make says: : cc ws.c -o ws -O -Dint32=long -Duint32=ulong -s -lc_s : "ws.c", line 190: RG_SPAGE undefined : "ws.c", line 194: RG_LPAGE undefined : "ws.c", line 196: NSPPLP undefined : "ws.c", line 250: NBPLP undefined : *** Error code 1 : : Stop. I did... -- --------------------+----------------------+----------------------------------- Pim Zandbergen | phone: +31 70 542302 | CTI Software BV pim@ctisbv.UUCP | fax : +31 70 512837 | Laan Copes van Cattenburch 70 ...!uunet!mcvax!hp4nl!ctisbv!pim | 2585 GD The Hague, The Netherlands