📄 m_irixsgi.c
字号:
/* * top - a top users display for Unix * * SYNOPSIS: Any SGI machine running IRIX 6.2 and up * * DESCRIPTION: * This is the machine-dependent module for IRIX as supplied by * engineers at SGI. * * CFLAGS: -DHAVE_GETOPT -D_OLD_TERMIOS -DORDER * * AUTHOR: Sandeep Cariapa <cariapa@sgi.com> * AUTHOR: Larry McVoy <lm@sgi.com> * Sandeep did all the hard work; I ported to 6.2 and fixed up some formats. * AUTHOR: John Schimmel <jes@sgi.com> * He did the all irix merge. * AUTHOR: Ariel Faigon <ariel@sgi.com> * Ported to Ficus/Kudzu (IRIX 6.4+). * Got rid of all nlist and different (elf64, elf32, COFF) kernel * dependencies * Various small fixes and enhancements: multiple CPUs, nicer formats. * Added -DORDER process display ordering * cleaned most -fullwarn'ings. * Need -D_OLD_TERMIOS when compiling on IRIX 6.4 to work on 6.2 systems * Support much bigger values in memory sizes (over Peta-byte) */#define _KMEMUSER#include <sys/types.h>#include <sys/time.h>#include <sys/stat.h>#include <sys/swap.h>#include <sys/proc.h>#include <sys/procfs.h>#include <sys/sysinfo.h>#include <sys/sysmp.h>#include <sys/utsname.h>#include <sys/schedctl.h> /* for < 6.4 NDPHIMAX et al. */#include <paths.h>#include <assert.h>#include <values.h>#include <dirent.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <fcntl.h>#include <dlfcn.h>#include "top.h"#include "machine.h"#define KMEM "/dev/kmem"typedef double load_avg;#define loaddouble(la) (la)#define intload(i) ((double)(i))/* * Structure for keeping track of CPU times from last time around * the program. We keep these things in a hash table, which is * recreated at every cycle. */struct oldproc { pid_t oldpid; double oldtime; double oldpct;};static int oldprocs; /* size of table */static struct oldproc *oldbase;#define HASH(x) ((x << 1) % oldprocs)#define pagetok(pages) ((((uint64_t) pages) * pagesize) >> 10)/* * Ugly hack, save space and complexity of allocating and maintaining * parallel arrays to the prpsinfo array: use spare space (pr_fill area) * in prpsinfo structures to store %CPU calculated values */#define D_align(addr) (((unsigned long)(addr) & ~0x0fU))#define percent_cpu(pp) (* (double *) D_align(&((pp)->pr_fill[0])))#define weighted_cpu(pp) (* (double *) D_align(&((pp)->pr_fill[4])))/* Username field to fill in starts at: */#define UNAME_START 16/* * These definitions control the format of the per-process area */static char header[] =" PID PGRP X PRI SIZE RES STATE TIME %WCPU %CPU COMMAND";/* 012345678901234567890123456789012345678901234567890123456789012345678901234567 10 20 30 40 50 60 70 *//* PID PGRP USER PRI SIZE RES STATE TIME %WCPU %CPU CMD */#define Proc_format \ "%7d %7d %-8.8s %4.4s %6.6s %5.5s %-6.6s %6.6s %5.2f %5.2f %-.10s"/* * these are for detailing the cpu states * Data is taken from the sysinfo structure (see <sys/sysinfo.h>) * We rely on the following values: * * #define CPU_IDLE 0 * #define CPU_USER 1 * #define CPU_KERNEL 2 * #define CPU_WAIT 3 * #define CPU_SXBRK 4 * #define CPU_INTR 5 */#ifndef CPU_STATES /* defined only in 6.4 and up */# define CPU_STATES 6#endifint cpu_states[CPU_STATES];char *cpustatenames[] = { "idle", "usr", "ker", "wait", "xbrk", "intr", NULL};/* these are for detailing the memory statistics */#define MEMSTATS 10int memory_stats[MEMSTATS];char *memorynames[] = { "K max, ", "K avail, ", "K free, ", "K swap, ", "K free swap", NULL};char uname_str[40];double load[3];static char fmt[MAX_COLS + 2];int numcpus;/* useful externals */extern int errno;extern char *sys_errlist[];extern char *myname;extern char *format_k();extern char *format_time();extern long percentages();static int kmem;static unsigned long avenrun_offset;static float irix_ver; /* for easy numeric comparison */static struct prpsinfo *pbase;static struct prpsinfo **pref;static struct oldproc *oldbase;static int oldprocs; /* size of table */static DIR *procdir;static int ptable_size; /* allocated process table size */static int nproc; /* estimated process table size */static int pagesize;/* get_process_info passes back a handle. This is what it looks like: */struct handle { struct prpsinfo **next_proc; /* points to next valid proc pointer */ int remaining; /* number of pointers remaining */};static struct handle handle;void getptable(struct prpsinfo *baseptr);void size(int fd, struct prpsinfo *ps);extern char *ordernames[];/* * Process states letters are mapped into numbers * 6.5 seems to have changed the semantics of prpsinfo.pr_state * so we rely, (like ps does) on the char value pr_sname. * The order we use here is what may be most interesting * to top users: Most interesting state on top, least on bottom. * 'S' (sleeping) is the most common case so I put it _after_ * zombie, even though it is more "active" than zombie. * * State letters and their meanings: * * R Process is running (may not have a processor yet) * I Process is in intermediate state of creation * X Process is waiting for memory * T Process is stopped * Z Process is terminated and parent not waiting (zombie) * S Process is sleeping, waiting for a resource *//* abbreviated process states */static char *state_abbrev[] ={ "", "sleep", "zomb", "stop", "swap", "start", "ready", "run", NULL };/* Same but a little "wordier", used in CPU activity summary */int process_states[8]; /* per state counters */char *procstatenames[] = { /* ready to run is considered running here */ "", " sleeping, ", " zombie, ", " stopped, ", " swapped, ", " starting, ", " ready, ", " running, ", NULL};#define S_RUNNING 7#define S_READY 6#define S_STARTING 5#define S_SWAPPED 4#define S_STOPPED 3#define S_ZOMBIE 2#define S_SLEEPING 1#define IS_ACTIVE(pp) \ (first_screen ? proc_state(pp) >= S_STARTING : percent_cpu(pp) > 0.0)/* * proc_state * map the pr_sname value to an integer. * used as an index into state_abbrev[] * as well as an "order" key */static int proc_state(struct prpsinfo *pp){ char psname = pp->pr_sname; switch (psname) { case 'R': return (pp->pr_sonproc >= 0 && pp->pr_sonproc < numcpus) ? S_RUNNING /* on a processor */ : S_READY; case 'I': return S_STARTING; case 'X': return S_SWAPPED; case 'T': return S_STOPPED; case 'Z': return S_ZOMBIE; case 'S': return S_SLEEPING; default : return 0; }}/* * To avoid nlist'ing the kernel (with all the different kernel type * complexities), we estimate the size of the needed working process * table by scanning /proc/pinfo and taking the number of entries * multiplied by some reasonable factor. * Assume current dir is _PATH_PROCFSPI */static int active_proc_count(){ DIR *dirp; int pcnt; if ((dirp = opendir(".")) == NULL) { (void) fprintf(stderr, "%s: Unable to open %s\n", myname, _PATH_PROCFSPI); exit(1); } for (pcnt = 0; readdir(dirp) != NULL; pcnt++) ; closedir(dirp); return pcnt;}/* * allocate space for: * proc structure array * array of pointers to the above (used for sorting) * array for storing per-process old CPU usage */voidallocate_proc_tables(){ int n_active = active_proc_count(); if (pbase != NULL) /* && n_active < ptable_size */ return; /* Need to realloc if we exceed, but factor should be enough */ nproc = n_active * 5; oldprocs = 2 * nproc; pbase = (struct prpsinfo *) malloc(nproc * sizeof(struct prpsinfo)); pref = (struct prpsinfo **) malloc(nproc * sizeof(struct prpsinfo *)); oldbase = (struct oldproc *) malloc (oldprocs * sizeof(struct oldproc)); ptable_size = nproc; if (pbase == NULL || pref == NULL || oldbase == NULL) { (void) fprintf(stderr, "%s: malloc: out of memory\n", myname); exit (1); }}intmachine_init(struct statics *statics){ struct oldproc *op, *endbase; int pcnt = 0; struct utsname utsname; char tmpbuf[20]; uname(&utsname); irix_ver = (float) atof((const char *)utsname.release); strncpy(tmpbuf, utsname.release, 9); tmpbuf[9] = '\0'; sprintf(uname_str, "%s %-.14s %s %s", utsname.sysname, utsname.nodename, tmpbuf, utsname.machine); pagesize = getpagesize(); if ((kmem = open(KMEM, O_RDONLY)) == -1) { perror(KMEM); return -1; } if (chdir(_PATH_PROCFSPI)) { /* handy for later on when we're reading it */ (void) fprintf(stderr, "%s: Unable to chdir to %s\n", myname, _PATH_PROCFSPI); return -1; } if ((procdir = opendir(".")) == NULL) { (void) fprintf(stderr, "%s: Unable to open %s\n", myname, _PATH_PROCFSPI); return -1; } if ((avenrun_offset = sysmp(MP_KERNADDR, MPKA_AVENRUN)) == -1) { perror("sysmp(MP_KERNADDR, MPKA_AVENRUN)"); return -1; } allocate_proc_tables(); oldprocs = 2 * nproc; endbase = oldbase + oldprocs; for (op = oldbase; op < endbase; op++) { op->oldpid = -1; } statics->cpustate_names = cpustatenames; statics->memory_names = memorynames; statics->order_names = ordernames; statics->procstate_names = procstatenames; return (0);}char *format_header(uname_field) register char *uname_field;{ register char *ptr; ptr = header + UNAME_START; while (*uname_field != '\0') { *ptr++ = *uname_field++; } return (header);}voidget_system_info(si) struct system_info *si;{ int i; int avenrun[3]; struct rminfo realmem; struct sysinfo sysinfo; static time_t cp_old [CPU_STATES]; static time_t cp_diff[CPU_STATES]; /* for cpu state percentages */ off_t fswap; /* current free swap in blocks */ off_t tswap; /* total swap in blocks */ (void) getkval(avenrun_offset, (int *) avenrun, sizeof(avenrun), "avenrun"); for (i = 0; i < 3; i++) { si->load_avg[i] = loaddouble(avenrun[i]); si->load_avg[i] /= 1024.0; } if ((numcpus = sysmp(MP_NPROCS)) == -1) { perror("sysmp(MP_NPROCS)"); return; } if (sysmp(MP_SAGET, MPSA_RMINFO, &realmem, sizeof(realmem)) == -1) { perror("sysmp(MP_SAGET,MPSA_RMINFO, ...)"); return; } swapctl(SC_GETFREESWAP, &fswap); swapctl(SC_GETSWAPTOT, &tswap); memory_stats[0] = pagetok(realmem.physmem); memory_stats[1] = pagetok(realmem.availrmem); memory_stats[2] = pagetok(realmem.freemem); memory_stats[3] = tswap / 2; memory_stats[4] = fswap / 2; if (sysmp(MP_SAGET,MPSA_SINFO, &sysinfo,sizeof(struct sysinfo)) == -1) { perror("sysmp(MP_SAGET,MPSA_SINFO)"); return; } (void) percentages(CPU_STATES, cpu_states, sysinfo.cpu, cp_old, cp_diff); si->cpustates = cpu_states; si->memory = memory_stats; si->last_pid = -1; return;}caddr_tget_process_info(si, sel, compare) struct system_info *si; struct process_select *sel; int (*compare) ();{ int i, total_procs, active_procs; struct prpsinfo **prefp; struct prpsinfo *pp; int show_uid; static char first_screen = 1; /* read all the proc structures */ getptable(pbase); /* get a pointer to the states summary array */ si->procstates = process_states; /* set up flags which define what we are going to select */ show_uid = sel->uid != -1; /* count up process states and get pointers to interesting procs */ total_procs = 0; active_procs = 0; (void) memset(process_states, 0, sizeof(process_states)); prefp = pref; for (pp = pbase, i = 0; i < nproc; pp++, i++) { /* * Place pointers to each valid proc structure in pref[]. * Process slots that are actually in use have a non-zero * status field. Processes with SSYS set are system * processes---these get ignored unless show_system is set. * Ariel: IRIX 6.4 had to redefine "system processes" * They do not exist outside the kernel in new kernels. * Now defining as uid==0 and ppid==1 (init children) */ if (pp->pr_state && (sel->system || !(pp->pr_uid==0 && pp->pr_ppid==1))) { total_procs++; process_states[proc_state(pp)]++; /* * zombies are actually interesting (to avoid) * although they are not active, so I leave them * displayed. */ if (/* (! pp->pr_zomb) && */ (sel->idle || IS_ACTIVE(pp)) && (! show_uid || pp->pr_uid == (uid_t) sel->uid)) { *prefp++ = pp; active_procs++; } } } first_screen = 0; /* if requested, sort the "interesting" processes */ if (compare != NULL) qsort((char *) pref, active_procs, sizeof(struct prpsinfo *), compare); /* remember active and total counts */ si->p_total = total_procs; si->p_active = active_procs; /* pass back a handle */ handle.next_proc = pref; handle.remaining = active_procs; return ((caddr_t) &handle);}/* * Added cpu_id to running processes, add 'ready' (to run) state */static char * format_state(struct prpsinfo *pp){ static char state_str[16]; int state = proc_state(pp); if (state == S_RUNNING) { /* * Alert: 6.2 (MP only?) binary incompatibility * pp->pr_sonproc apparently (?) has a different * offset on 6.2 machines... I've seen cases where * a 6.4 compiled top running on 6.2 printed * a garbage CPU-id. To be safe, I print the CPU-id * only if it falls within range [0..numcpus-1] */ sprintf(state_str, "run/%d", pp->pr_sonproc); return state_str; } /* default */ return state_abbrev[state];}static char *format_prio(pp) struct prpsinfo *pp;{ static char prio_str[10]; if (irix_ver < 6.4) { /* * Note: this is _compiled_ on 6.x where x >= 4 but I would like * it to run on 6.2 6.3 as well (backward binary compatibility). * Scheduling is completely different between these IRIX versions * and some scheduling classes may even have different names. * * The solution: have more than one style of 'priority' depending * on the OS version. * * See npri(1) + nice(2) + realtime(5) for scheduling classes, * and priority values. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -