nagel@paris.ics.uci.edu (Mark Nagel) (08/26/88)
Some time ago there was a version of top (a program to display information about the system and the top n processes using curses) that worked on the Sequent Balance. We seem to have lost the source code for this version and I'd really like to make the newest version (2.5) work on our Balance. If anyone out there has the source for this, please let me know or point me in the right direction. Thanks in advance... -- Mark Nagel Department of Information and Computer Science, UC Irvine nagel@ics.uci.edu (ARPA) When they ship styrofoam... {sdcsvax|ucbvax}!ucivax!nagel (UUCP) ...what do they pack it in?
tom@taux01.UUCP (Tom Gorodecki) (08/30/88)
In article <650@paris.ICS.UCI.EDU> nagel@paris.ics.uci.edu (Mark Nagel) writes: >Some time ago there was a version of top (a program to display information >about the system and the top n processes using curses) that worked on >the Sequent Balance. We seem to have lost the source code for this version >and I'd really like to make the newest version (2.5) work on our Balance. >If anyone out there has the source for this, please let me know or >point me in the right direction. Thanks in advance... > >-- Top on sequent. Please send me a copy too. Thanks. Tom. -- Gorodecki Tom. National Semiconductor (IC) 6 Maskit st. P.O.B. 3007, Herzlia B, 46 104, Israel UUCP: {hplabs,pyramid,sun,decwrl}!nsc!taux01!tom domain: tom%taux01@nsc.com
pwolfe@kailand.KAI.COM (08/31/88)
Here is the source to a version 1.6 of top that compiles and runs on V3.0.4 DYNIX on our Sequent Balance. It compiles, but doesn't work correctly on our Sequent Symmetry running DYNIX V3.0.12. If you can use this to make any newer version work, great! Please post it to comp.sys.sequent. Thanks, Patrick Wolfe (pwolfe@kai.com, kailand!pwolfe) #! /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 shell archive." # Contents: README Makefile top.c top.1 # Wrapped by pwolfe@kailand on Tue Aug 30 21:10:26 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(3365 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' XThis file contains a few comments about "top". X X"top" is a program that will give continual reports about the state of the Xsystem, including a list of the top cpu using processes. It requires read Xaccess to the memory files "/dev/kmem" and "/dev/mem" as well as the system Ximage "/vmunix". Some installations have these files protected from general Xaccess. These sites would have to install this program in the same way that Xprograms such as "ps" are installed. X XThere are a few things that need to be checked before compiling the program: X XThe most important item is the internal hash table size. This size is Xdefined in the program with the preprocessor variable "Table_size". This Xconstant MUST be larger than the number of lines in the file /etc/passwd. XIt is advisable that this number be about twice the number of lines, and Xthat it be a prime number (since it dictates the size of the hash table). XMake sure this is checked before compilation. X XThe next thing is the routine called "bzero". This function simply zeros Xa block of memory. The file "bzero.c" in this distribution is written for Xa VAX and will not work on any other type of machine. This routine is not Xneeded under 4.2, since it is already defined in the C run time library. XThe routine is very easy to write, but it is something that should be as Xfast as possible. If the local machine is not a VAX then "bzero.c" will Xhave to be replaced with something else. If you can't come up with a Xslick method, there is a very simple C equivalent (although it will not be Xvery fast) that will work: X X bzero(memory, amount) X X char *memory; X int amount; X X { X while (amount > 0) X { X *memory++ = 0; X amount--; X } X } X XThere are two Makefiles in this distribution. One makes a version of top Xfor a 4.1 system (called "Makefile4.1") and the other makes a version for a X4.2 system (called "Makefile4.2"). Rename or link the version that is Xappropriate for your machine to "Makefile" before running make. There are Xsome differences compiling and linking the different versions. For example: X"bzero" is already defined in the 4.2 C library, so that routine is not needed Xunder 4.2. There are also differences in the source, which are Xconditionally compiled. Both of these cases are handled correctly by the Xappropriate Makefile. X XFinally, there are two preprocessor variables that are defined at compile Xtime by the makefile. These are "Default_TOPN" and "Default_DELAY". Their Xvalues are the defaults used for the top number of processes to be displayed Xand the number of seconds to delay between displays, respectively. They are Xset by the Makefile variables "TOPN" and "DELAY", respecitvely. These Xconstants are preset as follows: TOPN=10, DELAY=5. These can be overriden Xby either changing the Makefile or by specifying the change on the make Xcommand line (with something like "make TOPN=15"). X XIf you make a change to "top" that you feel would be beneficial to others Xwho use this program, or if you find and fix a bug, feel free to send me the Xchange. X XEnjoy! X X William LeFebvre X Department of Computer Science X Rice University X ARPANet address: <phil@Rice.arpa> X X U.S. Mail address: X William LeFebvre X P.O. Box 1892 X Department of Computer Science X Houston, TX 77251 END_OF_FILE if test 3365 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(664 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# Makefile for Sequent DYNIX V3.0.4 version of "top" X X# values for two defaults in "top" XTOPN = 15 XDELAY = 3 X XCFLAGS = -DFOUR_TWO -DSUN -O XDEFS = -DDefault_TOPN=$(TOPN) -DDefault_DELAY=$(DELAY) XLIBS = -lcurses -ltermcap -lseq -lm XMANSECT = l XTARFILES = Makefile README top.c top.1 X Xtop: top.c X cc -o top $(CFLAGS) $(DEFS) top.c $(LIBS) X Xinstall: top X install -s -g staff -m 771 top /usr/local/bin X Xmanpage: top.1 X cp top.1 /usr/man/man$(MANSECT)/top.$(MANSECT) X chgrp staff /usr/man/man$(MANSECT)/top.$(MANSECT) X chmod 664 /usr/man/man$(MANSECT)/top.$(MANSECT) X Xman: X nroff -$(MAN) -rN$(TOPN) -rD$(DELAY) top.1 | cat -s >top.cat X Xtar: X tar cvf top.tar $(TARFILES) END_OF_FILE if test 664 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'top.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'top.c'\" else echo shar: Extracting \"'top.c'\" \(16193 characters\) sed "s/^X//" >'top.c' <<'END_OF_FILE' Xchar *copyright = "Top, version 1.6, copyright (c) 1984, William LeFebvre"; X X/* X * Top users display for Berkeley Unix X * Version 1.6 X * X * This program may be freely redistributed to other Unix sites, but this X * entire comment MUST remain intact. X * X * Copyright (c) 1984, William LeFebvre, Rice University X * X * This program is designed to run on either Berkeley 4.1 or 4.2 Unix. X * Compile with the preprocessor variable "FOUR_TWO" set to get an X * executable that will run on Berkeley 4.2 Unix. X * X * The Sun kernel uses scaled integers instead of floating point so compile X * with the preprocessor variable "SUN" to get an executable that will run X * on Sun Unix version 1.1 or later. X * X * Fixes and enhancements since version 1.5: X * X * Jonathon Feiber at sun: X * added "#ifdef SUN" code to make top work on a Sun, X * fixed race bug in getkval for getting user structure, X * efficiency improvements: added register variables and X * removed the function hashit X */ X X#include <curses.h> X#include <stdio.h> X#include <pwd.h> X#include <nlist.h> X#include <signal.h> X#include <sys/param.h> X#ifdef FOUR_TWO X#include <machine/pte.h> X#else X#include <sys/pte.h> X#endif X#include <sys/dir.h> X#include <sys/user.h> X#include <sys/proc.h> X#include <sys/dk.h> X#include <sys/vm.h> X#include <machine/hwparam.h> X#include <machine/engine.h> X#include <machine/plocal.h> X X/* obvious file names */ X X#define VMUNIX "/dynix" X#define KMEM "/dev/kmem" X#define MEM "/dev/mem" X X/* X * The number of users in /etc/passwd CANNOT be greater than Table_size! X * If you get the message "table overflow: too many users", then increase X * Table_size. Since this is the size of a hash table, things will work X * best if it is a prime number that is about twice the number of users. X */ X X#define Table_size 421 X X/* Number of lines of header information on the standard screen */ X# define Header_lines 5 X X/* wish list for kernel symbols */ X Xstruct nlist nlst[] = { X { "_avenrun" }, X#define X_AVENRUN 0 X { "_ccpu" }, X#define X_CCPU 1 X { "_engine" }, X#define X_ENGINE 2 X { "_hz" }, X#define X_HZ 3 X { "_mpid" }, X#define X_MPID 4 X { "_nproc" }, X#define X_NPROC 5 X { "_proc" }, X#define X_PROC 6 X { "_Nengine" }, X#define X_CPUS 7 X { 0 }, X}; X X/* useful externals */ Xextern int errno; Xextern char *sys_errlist[]; Xextern int LINES; X X/* signal handling routines */ Xint leave(); Xint onalrm(); X X/* file descriptors for memory devices */ Xint kmem; Xint mem; X Xint engines; Xstruct engine *enginep, engin; Xstruct plocal tmppl, *plp[30]; Xunsigned *p1, *p2; Xstruct vmmeter vm; Xint nproc; Xint mpid; X X/* kernel "hz" variable -- clock rate */ Xlong hz; X X/* All this is to calculate the cpu state percentages */ X Xlong cp_time[CPUSTATES]; Xlong cp_old[CPUSTATES]; Xlong cp_change[CPUSTATES]; Xlong total_change; Xlong cp_time_offset; Xlong mpid_offset; Xlong avenrun_offset; X X#ifdef SUN Xlong ccpu; Xlong avenrun[3]; X#else Xdouble ccpu; Xdouble avenrun[3]; X#endif Xdouble logcpu; X Xstruct proc *proc; Xstruct proc *pbase; Xint bytes; X Xstruct user u; X X/* Verbose process state names */ X Xchar *state_name[] = { X "", "sleeping", "ABANDONED", "runnable", "starting", "zombie", "stopped", X "Running"}; X X/* process state names for the "STATE" column of the display */ X Xchar *state_abbrev[] = { X "", "sleep", "WAIT", "run", "idl", "zomb", "stop", "Run" X}; X X/* cpu state names for percentages */ X Xchar *cpu_state[] = { X "user", "nice", "system", "idle" X}; X X/* routines that don't return int */ X Xstruct passwd *getpwent(); Xchar *username(); Xchar *ctime(); Xchar *rindex(); X Xint proc_compar(); Xdouble log(); Xdouble exp(); X Xmain(argc, argv) X Xint argc; Xchar *argv[]; X X{ X register struct proc *pp; X register struct proc **prefp; X register int i; X register int active_procs; X register int change; X register long cputime; X X int j,k; X struct proc **pref; X int total_procs; X int proc_brkdn[8]; X int topn = Default_TOPN; X int delay = Default_DELAY; X long curr_time; X long time(); X char do_cpu = 0; X char *myname = "top"; X double pctcpu; X X /* get our name */ X if (argc > 0) X { X if ((myname = rindex(argv[0], '/')) == 0) X { X myname = argv[0]; X } X else X { X myname++; X } X } X X /* check for time delay option */ X if (argc > 1 && argv[1][0] == '-') X { X if (argv[1][1] != 's') X { X fprintf(stderr, "Usage: %s [-sn] [number]\n", myname); X exit(1); X } X delay = atoi(&(argv[1][2])); X argc--; X argv++; X } X X /* get count of top processes to display (if any) */ X if (argc > 1) X { X topn = atoi(argv[1]); X } X X /* open kmem and mem */ X if ((kmem = open(KMEM, 0)) < 0) X { X perror(KMEM); X exit(1); X } X if ((mem = open(MEM, 0)) < 0) X { X perror(MEM); X exit(1); X } X X /* get the list of symbols we want to access in the kernel */ X errno = 0; X nlist(VMUNIX, nlst); X if (nlst[0].n_type == 0) X { X fprintf(stderr, "%s: can't nlist image\n", VMUNIX); X exit(1); X } X X /* get the symbol values out of kmem */ X getkval(nlst[X_PROC].n_value, &proc, sizeof(int), nlst[X_PROC].n_name); X getkval(nlst[X_NPROC].n_value, &nproc, sizeof(int), nlst[X_NPROC].n_name); X getkval(nlst[X_CCPU].n_value, &ccpu, sizeof(int), nlst[X_CCPU].n_name); X getkval(nlst[X_HZ].n_value, &hz, sizeof(int), nlst[X_HZ].n_name); X getkval(nlst[X_CPUS].n_value, &engines,sizeof(int), nlst[X_CPUS].n_name); X getkval(nlst[X_ENGINE].n_value,&enginep,sizeof(int),nlst[X_ENGINE].n_name); X X /* get vmmeter ptrs */ X for(i=0;i<engines;i++){ X getkval(enginep,&engin,sizeof(engin),"engine"); X plp[i] = (struct plocal *)engin.e_local->pp_local; X enginep++; X } X /* some calculations we use later */ X X mpid_offset = nlst[X_MPID].n_value; X avenrun_offset = nlst[X_AVENRUN].n_value; X X /* this is used in calculating WCPU -- calculate it ahead of time */ X#ifdef SUN X logcpu = log((double)ccpu / FSCALE); X#else X logcpu = log(ccpu); X#endif X X /* allocate space for proc structure array and array of pointers */ X bytes = nproc * sizeof(struct proc); X pbase = (struct proc *)sbrk(bytes); X pref = (struct proc **)sbrk(nproc * sizeof(struct proc *)); X X /* Just in case ... */ X if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL) X { X fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); X exit(1); X } X X /* initialize the hashing stuff */ X init_hash(); X X /* initialize curses and screen (last) */ X initscr(); X erase(); X clear(); X refresh(); X X /* setup signal handlers */ X signal(SIGINT, leave); X signal(SIGQUIT, leave); X X /* can only display (LINES - Header_lines) processes */ X if (topn > LINES - Header_lines) X { X printw("Warning: this terminal can only display %d processes...\n", X LINES - Header_lines); X refresh(); X sleep(2); X topn = LINES - Header_lines; X clear(); X } X X /* main loop ... */ X X while (1) /* while(1)'s are forever ... */ X { X /* read all the proc structures in one fell swoop */ X getkval(proc, pbase, bytes, "proc array"); X X /* get load average array */ X getkval(avenrun_offset, avenrun, sizeof(avenrun), "_avenrun"); X X /* get mpid -- process id of last process */ X getkval(mpid_offset, &mpid, sizeof(mpid), "_mpid"); X X /* sum up engines data vmmeter */ X#define NVM (sizeof(struct vmmeter)/sizeof(int)) X p1 = (unsigned *)&vm; X for(j=0;j<NVM;j++) *p1++ = 0; X for(j=0;j<engines;j++){ X getkval(plp[j],&tmppl,sizeof(struct plocal),"plocal"); X p1 = (unsigned *)&vm; X p2 = (unsigned *)&tmppl.cnt; X for(k=0;k<NVM;k++,p1++) *p1 += *p2++; X } X bcopy(vm.v_time,cp_time,sizeof(cp_time)); X X /* count up process states and get pointers to interesting procs */ X total_procs = 0; X active_procs = 0; X bzero(proc_brkdn, sizeof(proc_brkdn)); X prefp = pref; X for (pp = pbase, i = 0; i < nproc; pp++, i++) X { X /* place pointers to each valid proc structure in pref[] */ X /* (processes with SSYS set are system processes) */ X if (pp->p_pid != 0 && pp->p_stat != 0 && (pp->p_flag & SSYS) == 0) X { X total_procs++; X proc_brkdn[pp->p_stat]++; X if (pp->p_stat != SZOMB) X { X *prefp++ = pp; X active_procs++; X } X } X } X X /* display the load averages */ X printw("last pid: %d; load averages", mpid); X { X for (i = 0; i < 3; i++) X { X printw("%c %4.2f", X i == 0 ? ':' : ',', X#ifdef SUN X (double)avenrun[i] / FSCALE); X#else X avenrun[i]); X#endif X } X } X /* display number of users */ X printw(" Users: %d CPUs %d",user_count(),engines); X X /* X * Display the current time. X * "ctime" always returns a string that looks like this: X * X * Sun Sep 16 01:03:52 1973 X * 012345678901234567890123 X * 1 2 X * X * We want indices 11 thru 18 (length 8). X */ X X curr_time = time(0); X move(0, 79-8); X printw("%-8.8s\n", &(ctime(&curr_time)[11])); X X /* display process state breakdown */ X printw("%d processes", total_procs); X for (i = 1; i < 8; i++) X { X if (proc_brkdn[i] != 0) X printw("%c %d %s%s", X i == 1 ? ':' : ',', X proc_brkdn[i], X state_name[i], X (i == SZOMB) && (proc_brkdn[i] > 1) ? "s" : ""); X } X X /* calculate percentage time in each cpu state */ X printw("\nCpu states: "); X if (do_cpu) /* but not the first time */ X { X total_change = 0; X for (i = 0; i < CPUSTATES; i++) X { X /* calculate changes for each state and overall change */ X if (cp_time[i] < cp_old[i]) X { X /* this only happens when the counter wraps */ X change = (int) X ((unsigned long)cp_time[i]-(unsigned long)cp_old[i]); X } X else X { X change = cp_time[i] - cp_old[i]; X } X total_change += (cp_change[i] = change); X } X if (total_change == 0) total_change=1; X for (i = 0; i < CPUSTATES; i++) X { X printw("%s%4.1f%% %s", X i == 0 ? "" : ", ", X ((float)cp_change[i] / (float)total_change) * 100.0, X cpu_state[i]); X cp_old[i] = cp_time[i]; X } X } X else X { X /* we'll do it next time */ X for (i = 0; i < CPUSTATES; i++) X { X printw("%s %s", X i == 0 ? "" : ", ", X cpu_state[i]); X cp_old[i] = 0; X } X do_cpu = 1; X } X printw("\n"); X X if (topn > 0) X { X printw("\n PID USERNAME PRI NICE SIZE RES STATE TIME WCPU CPU ENG COMMAND\n"); X X /* sort by cpu percentage (pctcpu) */ X qsort(pref, active_procs, sizeof(struct proc *), proc_compar); X X /* now, show the top whatever */ X if (active_procs > topn) X { X /* adjust for a lack of processes */ X active_procs = topn; X } X for (prefp = pref, i = 0; i < active_procs; prefp++, i++) X { X pp = *prefp; X if (getu(pp) == -1) X { X strcpy(u.u_comm, "<swapped>"); X cputime = 0; X } X else X { X cputime = X#ifdef FOUR_TWO X (u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec); X#else X (int)((float)(u.u_vm.vm_utime + u.u_vm.vm_stime)/hz); X#endif X } X#ifdef SUN X pctcpu = (double)pp->p_pctcpu / FSCALE; X#else X pctcpu = pp->p_pctcpu; X#endif X printw("%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %2d %-11.11s\n", X pp->p_pid, X username(pp->p_uid), X pp->p_pri - PZERO, X pp->p_nice - NZERO, X (pp->p_dsize + pp->p_ssize) >> 1, X pp->p_rssize >> 1, X state_abbrev[pp->p_stat], X cputime / 60l, X cputime % 60l, X#ifdef SUN X (100.0 * pctcpu / (1.0 - exp(pp->p_time * logcpu))), X (100.0 * pctcpu), X#else X (100.0 * pctcpu / (1.0 - exp(pp->p_time * logcpu))), X (100.0 * pctcpu), X#endif X pp->p_engno, X u.u_comm); X } X } X refresh(); X X /* wait ... */ X signal(SIGALRM, onalrm); X alarm(delay); X pause(); X X /* clear for new display */ X erase(); X } X} X X/* X * signal handlers X */ X Xleave() /* exit under normal conditions -- INT handler */ X X{ X move(LINES - 1, 0); X refresh(); X endwin(); X exit(0); X} X Xquit(status) /* exit under duress */ X Xint status; X X{ X endwin(); X exit(status); X} X Xonalrm() X X{ X return(0); X} X X/* X * comparison function for "qsort" X */ X Xproc_compar(p1, p2) X Xstruct proc **p1; Xstruct proc **p2; X X{ X if ((*p1)->p_pctcpu < (*p2)->p_pctcpu) X { X return(1); X } X else X { X return(-1); X } X} X X/* X * These routines handle uid to username mapping. X * They use a hashing table scheme to reduce reading overhead. X */ X Xstruct hash_el { X int uid; X char name[8]; X}; X X#define H_empty -1 X X/* simple minded hashing function */ X#define hashit(i) ((i) % Table_size) X Xstruct hash_el hash_table[Table_size]; X Xinit_hash() X X{ X register int i; X register struct hash_el *h; X X for (h = hash_table, i = 0; i < Table_size; h++, i++) X { X h->uid = H_empty; X } X X setpwent(); X} X Xchar *username(uid) X Xregister int uid; X X{ X register int index; X register int found; X register char *name; X X /* This is incredibly naive, but it'll probably get changed anyway */ X index = hashit(uid); X while ((found = hash_table[index].uid) != uid) X { X if (found == H_empty) X { X /* not here -- get it out of passwd */ X index = get_user(uid); X break; /* out of while */ X } X index = index++ % Table_size; X } X return(hash_table[index].name); X} X Xenter_user(uid, name) X Xregister int uid; Xregister char *name; X X{ X register int length; X register int index; X register int try; X static int uid_count = 0; X X /* avoid table overflow -- insure at least one empty slot */ X if (++uid_count >= Table_size) X { X fprintf(stderr, "table overflow: too many users\n"); X quit(1); X } X X index = hashit(uid); X while ((try = hash_table[index].uid) != H_empty) X { X if (try == uid) X { X return(index); X } X index = index++ % Table_size; X } X hash_table[index].uid = uid; X strncpy(hash_table[index].name, name, 8); X return(index); X} X Xget_user(uid) X Xregister int uid; X X{ X struct passwd *pwd; X static char buff[20]; X register int last_index; X X while ((pwd = getpwent()) != NULL) X { X last_index = enter_user(pwd->pw_uid, pwd->pw_name); X if (pwd->pw_uid == uid) X { X return(last_index); X } X } X sprintf(buff, "%d", uid); X return(enter_user(uid, buff)); X} X X/* X * All of this stuff gets things out of the memory files. X */ X X/* X * Get the user structure for the process who's proc structure is in p. The X * user structure is returned in u. X */ Xgetu(p) X Xregister struct proc *p; X X{ X struct pte uptes[UPAGES]; X register caddr_t upage; X register struct pte *pte; X register nbytes, n; X X /* X * Check if the process is currently loaded or swapped out. The way we X * get the u area is totally different for the two cases. For this X * application, we just don't bother if the process is swapped out. X */ X if ((p->p_flag & SLOAD) == 0) X { X return(-1); X } X X /* X * Process is currently in memory, we hope! X */ X if (!getkval(p->p_upte, uptes, sizeof(uptes), "p->p_addr")) X { X /* we can't seem to get to it, so pretend it's swapped out */ X return(-1); X } X upage = (caddr_t)&u; X pte = uptes; X for (nbytes = sizeof(u); nbytes > 0; nbytes -= NBPG) X { X lseek(mem, pte++->pg_pfnum * NBPG, 0); X n = MIN(nbytes, NBPG); X if (read(mem, upage, n) != n) X { X /* we can't seem to get to it, so pretend it's swapped out */ X return(-1); X } X upage += n; X } X return(0); X} X X/* X * get the value of something from /dev/kmem X */ X Xgetkval(offset, ptr, size, refstr) X Xlong offset; Xint *ptr; Xint size; Xchar *refstr; X X{ X if (lseek(kmem, offset, 0) == -1) X { X fprintf(stderr, "%s: lseek to %s: %s\n", X KMEM, refstr, sys_errlist[errno]); X quit(1); X } X if (read(kmem, ptr, size) == -1) X { X if (strcmp(refstr, "p->p_addr") == 0) X { X /* we lost the race with the kernel, process isn't in memory */ X return(0); X } X else X { X fprintf(stderr, "%s: reading %s: %s\n", X KMEM, refstr, sys_errlist[errno]); X quit(1); X } X } X return(1); X} X X/* X * outc - real subroutine that writes a character; for termcap X */ X Xoutc(ch) X Xregister char ch; X X{ X putchar(ch); X} X X#include <utmp.h> X Xint user_count() X{ X static int first = 1; X static FILE *strm; X struct utmp utmp; X int count = 0; X X if (first) X { X strm = fopen("/etc/utmp", "r"); X first = 0; X } X X rewind(strm); X while(fread(&utmp, sizeof(utmp), 1, strm)) X { X if (utmp.ut_name[0] != '\0') X count++; X } X X return(count); X} END_OF_FILE if test 16193 -ne `wc -c <'top.c'`; then echo shar: \"'top.c'\" unpacked with wrong size! fi # end of 'top.c' fi if test -f 'top.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'top.1'\" else echo shar: Extracting \"'top.1'\" \(2930 characters\) sed "s/^X//" >'top.1' <<'END_OF_FILE' X.TH TOP 1 Local X.UC 4 X.SH NAME Xtop \- display and update information about the top cpu processes X.SH SYNOPSIS X.B top X[ X.BI \-s time X] [ X.I number X] X.SH DESCRIPTION X.\" This defines appropriate quote strings for nroff and troff X.ds lq \&" X.ds rq \&" X.if t .ds lq `` X.if t .ds rq '' X.\" Just in case the command line didn't set these number registers... X.if !\nN .nr N 10 X.if !\nD .nr D 5 X.I Top Xdisplays the top \nN processes on the system and periodically Xupdates this information. It uses raw cpu percentage Xto determine the top processes. The X.IR curses (3) Xpackage is used to do semi-optimal screen updating. If X.I number Xis given, then the top X.I number Xprocesses will be displayed instead of the default amount of \nN. XThe X.B \-s Xoption sets the delay between screen updates to X.I time Xseconds. The default delay between updates is \nD seconds. X.PP XThe top few lines of the display show general information about the state of Xthe system, including the last process id assigned to a process, the three Xload averages, the current time, the number of existing processes, the number Xof processes in each state X(sleeping, ABANDONED, running, starting, zombies, and stopped), Xand a percentage of time Xspent in each of the processor states (user, nice, system, and idle). X.PP XThe remainder of the screen displays information about individual Xprocesses. This display is similar in spirit to X.IR ps (1) Xbut it is not exactly the same. PID is the process id, USERNAME is the name Xof the process's owner, PRI is the current priority of the process, NICE is Xthe nice amount (in the range \-20 to 20), SIZE is the total size of the Xprocess (text, data, and stack), RES is the current amount of resident Xmemory (both SIZE and RES are given in kilobytes), STATE is the current Xstate (one of \*(lqsleep\*(rq, \*(lqWAIT\*(rq, \*(lqrun\*(rq, X\*(lqidl\*(rq, \*(lqzomb\*(rq, or \*(lqstop\*(rq), TIME is Xthe number of system and user Xcpu seconds that the process has used, WCPU is the weighted cpu percentage X(this is the same value that X.IR ps (1) Xdisplays as CPU), CPU is the raw percentage and is the field that is sorted Xto determine the order of the processes, and COMMAND is the name of the Xcommand that the process is currently running (if the process is swapped Xout, this column is marked \*(lq<swapped>\*(rq). X.SH NOTES XThe \*(lqABANDONED\*(rq state (known in the kernel as \*(lqSWAIT\*(rq) was Xabandoned, thus the name. A process should never end up in this state. X.SH AUTHOR XWilliam LeFebvre, Rice University graduate student X.SH FILES X.DT X/dev/kmem kernel memory X.br X/dev/mem physical memory X.br X/vmunix system image X.SH BUGS XThe command name for swapped processes should be tracked down, but this Xwould make the program run slower. X.PP XAs with X.IR ps (1), Xthings can change while X.I top Xis collecting information for an update. The picture it gives is only a Xclose approximation to reality. X.SH "SEE ALSO" Xps(1), mem(4) END_OF_FILE if test 2930 -ne `wc -c <'top.1'`; then echo shar: \"'top.1'\" unpacked with wrong size! fi # end of 'top.1' fi echo shar: End of shell archive. exit 0