source: trunk/third/top/machine/m_irixsgi.c @ 16185

Revision 16185, 26.2 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16184, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * top - a top users display for Unix
3 *
4 * SYNOPSIS:  Any SGI machine running IRIX 6.2 and up
5 *
6 * DESCRIPTION:
7 * This is the machine-dependent module for IRIX as supplied by
8 * engineers at SGI.
9 *
10 * CFLAGS: -DHAVE_GETOPT -D_OLD_TERMIOS -DORDER
11 *
12 * AUTHOR: Sandeep Cariapa <cariapa@sgi.com>
13 * AUTHOR: Larry McVoy <lm@sgi.com>
14 * Sandeep did all the hard work; I ported to 6.2 and fixed up some formats.
15 * AUTHOR: John Schimmel <jes@sgi.com>
16 * He did the all irix merge.
17 * AUTHOR: Ariel Faigon <ariel@sgi.com>
18 *      Ported to Ficus/Kudzu (IRIX 6.4+).
19 *      Got rid of all nlist and different (elf64, elf32, COFF) kernel
20 *      dependencies
21 *      Various small fixes and enhancements: multiple CPUs, nicer formats.
22 *      Added -DORDER process display ordering
23 *      cleaned most -fullwarn'ings.
24 *      Need -D_OLD_TERMIOS when compiling on IRIX 6.4 to work on 6.2 systems
25 *      Support much bigger values in memory sizes (over Peta-byte)
26 */
27
28#define _KMEMUSER
29
30#include <sys/types.h>
31#include <sys/time.h>
32#include <sys/stat.h>
33#include <sys/swap.h>
34#include <sys/proc.h>
35#include <sys/procfs.h>
36#include <sys/sysinfo.h>
37#include <sys/sysmp.h>
38#include <sys/utsname.h>
39#include <sys/schedctl.h>       /* for < 6.4 NDPHIMAX et al. */
40#include <paths.h>
41#include <assert.h>
42#include <values.h>
43#include <dirent.h>
44#include <stdio.h>
45#include <unistd.h>
46#include <stdlib.h>
47#include <errno.h>
48#include <fcntl.h>
49#include <dlfcn.h>
50
51#include "top.h"
52#include "machine.h"
53
54#define KMEM    "/dev/kmem"
55
56typedef double load_avg;
57#define loaddouble(la) (la)
58#define intload(i) ((double)(i))
59
60/*
61 * Structure for keeping track of CPU times from last time around
62 * the program.  We keep these things in a hash table, which is
63 * recreated at every cycle.
64 */
65struct oldproc {
66        pid_t   oldpid;
67        double  oldtime;
68        double  oldpct;
69};
70static int oldprocs;                    /* size of table */
71static struct oldproc *oldbase;
72#define HASH(x) ((x << 1) % oldprocs)
73
74
75#define pagetok(pages) ((((uint64_t) pages) * pagesize) >> 10)
76
77/*
78 * Ugly hack, save space and complexity of allocating and maintaining
79 * parallel arrays to the prpsinfo array: use spare space (pr_fill area)
80 * in prpsinfo structures to store %CPU calculated values
81 */
82#define D_align(addr)           (((unsigned long)(addr) & ~0x0fU))
83#define percent_cpu(pp)         (* (double *) D_align(&((pp)->pr_fill[0])))
84#define weighted_cpu(pp)        (* (double *) D_align(&((pp)->pr_fill[4])))
85
86
87/* Username field to fill in starts at: */
88#define UNAME_START 16
89
90/*
91 *  These definitions control the format of the per-process area
92 */
93static char header[] =
94"    PID    PGRP X         PRI   SIZE   RES STATE    TIME %WCPU  %CPU COMMAND";
95/*
96 012345678901234567890123456789012345678901234567890123456789012345678901234567
97          10        20        30        40        50        60        70
98 */
99
100/*       PID PGRP USER  PRI   SIZE  RES   STATE  TIME  %WCPU %CPU  CMD */
101#define Proc_format \
102        "%7d %7d %-8.8s %4.4s %6.6s %5.5s %-6.6s %6.6s %5.2f %5.2f %-.10s"
103
104
105/*
106 * these are for detailing the cpu states
107 * Data is taken from the sysinfo structure (see <sys/sysinfo.h>)
108 * We rely on the following values:
109 *
110 *      #define CPU_IDLE        0
111 *      #define CPU_USER        1
112 *      #define CPU_KERNEL      2
113 *      #define CPU_WAIT        3
114 *      #define CPU_SXBRK       4
115 *      #define CPU_INTR        5
116 */
117#ifndef CPU_STATES      /* defined only in 6.4 and up */
118# define CPU_STATES 6
119#endif
120
121int     cpu_states[CPU_STATES];
122char    *cpustatenames[] = {
123        "idle", "usr", "ker", "wait", "xbrk", "intr",
124        NULL
125};
126
127/* these are for detailing the memory statistics */
128
129#define MEMSTATS 10
130int     memory_stats[MEMSTATS];
131char    *memorynames[] = {
132        "K max, ", "K avail, ", "K free, ", "K swap, ", "K free swap", NULL
133};
134
135char    uname_str[40];
136double  load[3];
137static  char fmt[MAX_COLS + 2];
138int     numcpus;
139
140/* useful externals */
141extern int      errno;
142extern char     *sys_errlist[];
143
144extern char     *myname;
145extern char     *format_k();
146extern char     *format_time();
147extern long     percentages();
148
149static int kmem;
150static unsigned long avenrun_offset;
151
152static float    irix_ver;               /* for easy numeric comparison */
153
154static struct prpsinfo  *pbase;
155static struct prpsinfo  **pref;
156static struct oldproc   *oldbase;
157static int              oldprocs;       /* size of table */
158
159static DIR      *procdir;
160
161static int      ptable_size;    /* allocated process table size */
162static int      nproc;          /* estimated process table size */
163static int      pagesize;
164
165/* get_process_info passes back a handle.  This is what it looks like: */
166struct handle {
167        struct prpsinfo **next_proc;    /* points to next valid proc pointer */
168        int             remaining;      /* number of pointers remaining */
169};
170
171static struct handle    handle;
172
173void getptable(struct prpsinfo *baseptr);
174void size(int fd, struct prpsinfo *ps);
175
176extern char *ordernames[];
177
178/*
179 * Process states letters are mapped into numbers
180 * 6.5 seems to have changed the semantics of prpsinfo.pr_state
181 * so we rely, (like ps does) on the char value pr_sname.
182 * The order we use here is what may be most interesting
183 * to top users:  Most interesting state on top, least on bottom.
184 * 'S' (sleeping) is the most common case so I put it _after_
185 * zombie, even though it is more "active" than zombie.
186 *
187 * State letters and their meanings:
188 *
189 *      R   Process is running (may not have a processor yet)
190 *      I   Process is in intermediate state of creation
191 *      X   Process is waiting for memory
192 *      T   Process is stopped
193 *      Z   Process is terminated and parent not waiting (zombie)
194 *      S   Process is sleeping, waiting for a resource
195 */
196
197/* abbreviated process states */
198static char *state_abbrev[] =
199{ "", "sleep", "zomb", "stop", "swap", "start", "ready", "run", NULL };
200
201/* Same but a little "wordier", used in CPU activity summary */
202int     process_states[8];      /* per state counters */
203char    *procstatenames[] = {
204        /* ready to run is considered running here */
205        "",             " sleeping, ",  " zombie, ",    " stopped, ",
206        " swapped, ",   " starting, ",  " ready, ",     " running, ",
207        NULL
208};
209
210#define S_RUNNING       7
211#define S_READY         6
212#define S_STARTING      5
213#define S_SWAPPED       4
214#define S_STOPPED       3
215#define S_ZOMBIE        2
216#define S_SLEEPING      1
217
218#define IS_ACTIVE(pp) \
219        (first_screen ? proc_state(pp) >= S_STARTING : percent_cpu(pp) > 0.0)
220
221/*
222 * proc_state
223 *      map the pr_sname value to an integer.
224 *      used as an index into state_abbrev[]
225 *      as well as an "order" key
226 */
227static int proc_state(struct prpsinfo *pp)
228{
229    char psname = pp->pr_sname;
230
231    switch (psname) {
232        case 'R': return
233                 (pp->pr_sonproc >= 0 && pp->pr_sonproc < numcpus) ?
234                        S_RUNNING /* on a processor */ : S_READY;
235        case 'I': return S_STARTING;
236        case 'X': return S_SWAPPED;
237        case 'T': return S_STOPPED;
238        case 'Z': return S_ZOMBIE;
239        case 'S': return S_SLEEPING;
240        default : return 0;
241    }
242}
243
244
245/*
246 * To avoid nlist'ing the kernel (with all the different kernel type
247 * complexities), we estimate the size of the needed working process
248 * table by scanning  /proc/pinfo and taking the number of entries
249 * multiplied by some reasonable factor.
250 * Assume current dir is _PATH_PROCFSPI
251 */
252static int active_proc_count()
253{
254        DIR     *dirp;
255        int     pcnt;
256
257        if ((dirp = opendir(".")) == NULL) {
258                (void) fprintf(stderr, "%s: Unable to open %s\n",
259                                        myname, _PATH_PROCFSPI);
260                exit(1);
261        }
262        for (pcnt = 0; readdir(dirp) != NULL; pcnt++)
263                ;
264        closedir(dirp);
265
266        return pcnt;
267}
268
269/*
270 * allocate space for:
271 *      proc structure array
272 *      array of pointers to the above (used for sorting)
273 *      array for storing per-process old CPU usage
274 */
275void
276allocate_proc_tables()
277{
278        int     n_active = active_proc_count();
279
280        if (pbase != NULL)  /* && n_active < ptable_size */
281                return;
282
283        /* Need to realloc if we exceed, but factor should be enough */
284        nproc = n_active * 5;
285        oldprocs = 2 * nproc;
286
287        pbase = (struct prpsinfo *)
288                malloc(nproc * sizeof(struct prpsinfo));
289        pref = (struct prpsinfo **)
290                malloc(nproc * sizeof(struct prpsinfo *));
291        oldbase = (struct oldproc *)
292                malloc (oldprocs * sizeof(struct oldproc));
293
294        ptable_size = nproc;
295
296        if (pbase == NULL || pref == NULL || oldbase == NULL) {
297                (void) fprintf(stderr, "%s: malloc: out of memory\n", myname);
298                exit (1);
299        }
300}
301
302int
303machine_init(struct statics *statics)
304{
305        struct oldproc  *op, *endbase;
306        int             pcnt = 0;
307        struct utsname  utsname;
308        char            tmpbuf[20];
309
310        uname(&utsname);
311        irix_ver = (float) atof((const char *)utsname.release);
312        strncpy(tmpbuf, utsname.release, 9);
313        tmpbuf[9] = '\0';
314        sprintf(uname_str, "%s %-.14s %s %s",
315                utsname.sysname, utsname.nodename,
316                tmpbuf, utsname.machine);
317
318        pagesize = getpagesize();
319
320        if ((kmem = open(KMEM, O_RDONLY)) == -1) {
321                perror(KMEM);
322                return -1;
323        }
324
325        if (chdir(_PATH_PROCFSPI)) {
326                /* handy for later on when we're reading it */
327                (void) fprintf(stderr, "%s: Unable to chdir to %s\n",
328                                        myname, _PATH_PROCFSPI);
329                return -1;
330        }
331        if ((procdir = opendir(".")) == NULL) {
332                (void) fprintf(stderr, "%s: Unable to open %s\n",
333                                        myname, _PATH_PROCFSPI);
334                return -1;
335        }
336
337        if ((avenrun_offset = sysmp(MP_KERNADDR, MPKA_AVENRUN)) == -1) {
338                perror("sysmp(MP_KERNADDR, MPKA_AVENRUN)");
339                return -1;
340        }
341
342        allocate_proc_tables();
343
344        oldprocs = 2 * nproc;
345        endbase = oldbase + oldprocs;
346        for (op = oldbase; op < endbase; op++) {
347                op->oldpid = -1;
348        }
349
350        statics->cpustate_names = cpustatenames;
351        statics->memory_names = memorynames;
352        statics->order_names = ordernames;
353        statics->procstate_names = procstatenames;
354
355        return (0);
356}
357
358char   *
359format_header(uname_field)
360        register char *uname_field;
361{
362        register char *ptr;
363
364        ptr = header + UNAME_START;
365        while (*uname_field != '\0') {
366                *ptr++ = *uname_field++;
367        }
368
369        return (header);
370}
371
372void
373get_system_info(si)
374        struct system_info *si;
375{
376        int             i;
377        int             avenrun[3];
378        struct rminfo   realmem;
379        struct sysinfo  sysinfo;
380        static time_t   cp_old [CPU_STATES];
381        static time_t   cp_diff[CPU_STATES];    /* for cpu state percentages */
382        off_t           fswap;          /* current free swap in blocks */
383        off_t           tswap;          /* total swap in blocks */
384
385        (void) getkval(avenrun_offset, (int *) avenrun, sizeof(avenrun), "avenrun");
386
387        for (i = 0; i < 3; i++) {
388                si->load_avg[i] = loaddouble(avenrun[i]);
389                si->load_avg[i] /= 1024.0;
390        }
391
392        if ((numcpus = sysmp(MP_NPROCS)) == -1) {
393                perror("sysmp(MP_NPROCS)");
394                return;
395        }
396
397        if (sysmp(MP_SAGET, MPSA_RMINFO, &realmem, sizeof(realmem)) == -1) {
398                perror("sysmp(MP_SAGET,MPSA_RMINFO, ...)");
399                return;
400        }
401
402        swapctl(SC_GETFREESWAP, &fswap);
403        swapctl(SC_GETSWAPTOT, &tswap);
404
405        memory_stats[0] = pagetok(realmem.physmem);
406        memory_stats[1] = pagetok(realmem.availrmem);
407        memory_stats[2] = pagetok(realmem.freemem);
408        memory_stats[3] = tswap / 2;
409        memory_stats[4] = fswap / 2;
410
411        if (sysmp(MP_SAGET,MPSA_SINFO, &sysinfo,sizeof(struct sysinfo)) == -1) {
412                perror("sysmp(MP_SAGET,MPSA_SINFO)");
413                return;
414        }
415        (void) percentages(CPU_STATES, cpu_states, sysinfo.cpu, cp_old, cp_diff);
416
417        si->cpustates = cpu_states;
418        si->memory = memory_stats;
419        si->last_pid = -1;
420
421        return;
422}
423
424caddr_t
425get_process_info(si, sel, compare)
426        struct system_info *si;
427        struct process_select *sel;
428        int     (*compare) ();
429
430{
431        int             i, total_procs, active_procs;
432        struct prpsinfo **prefp;
433        struct prpsinfo *pp;
434        int             show_uid;
435        static char     first_screen = 1;
436
437        /* read all the proc structures */
438        getptable(pbase);
439
440        /* get a pointer to the states summary array */
441        si->procstates = process_states;
442
443        /* set up flags which define what we are going to select */
444        show_uid = sel->uid != -1;
445
446        /* count up process states and get pointers to interesting procs */
447        total_procs = 0;
448        active_procs = 0;
449        (void) memset(process_states, 0, sizeof(process_states));
450        prefp = pref;
451
452        for (pp = pbase, i = 0; i < nproc; pp++, i++) {
453                /*
454                 * Place pointers to each valid proc structure in pref[].
455                 * Process slots that are actually in use have a non-zero
456                 * status field.  Processes with SSYS set are system
457                 * processes---these get ignored unless show_system is set.
458                 * Ariel: IRIX 6.4 had to redefine "system processes"
459                 * They do not exist outside the kernel in new kernels.
460                 * Now defining as uid==0 and ppid==1 (init children)
461                 */
462                if (pp->pr_state &&
463                        (sel->system || !(pp->pr_uid==0 && pp->pr_ppid==1))) {
464                        total_procs++;
465                        process_states[proc_state(pp)]++;
466                        /*
467                         * zombies are actually interesting (to avoid)
468                         * although they are not active, so I leave them
469                         * displayed.
470                         */
471                        if (/* (! pp->pr_zomb) && */
472                            (sel->idle || IS_ACTIVE(pp)) &&
473                            (! show_uid || pp->pr_uid == (uid_t) sel->uid)) {
474                                *prefp++ = pp;
475                                active_procs++;
476                        }
477                }
478        }
479        first_screen = 0;
480
481        /* if requested, sort the "interesting" processes */
482        if (compare != NULL)
483                qsort((char *) pref, active_procs, sizeof(struct prpsinfo *), compare);
484
485        /* remember active and total counts */
486        si->p_total = total_procs;
487        si->p_active = active_procs;
488
489        /* pass back a handle */
490        handle.next_proc = pref;
491        handle.remaining = active_procs;
492        return ((caddr_t) &handle);
493}
494
495/*
496 * Added cpu_id to running processes, add 'ready' (to run) state
497 */
498static char * format_state(struct prpsinfo *pp)
499{
500        static char     state_str[16];
501        int             state = proc_state(pp);
502
503        if (state == S_RUNNING) {
504                /*
505                 * Alert: 6.2 (MP only?) binary incompatibility
506                 * pp->pr_sonproc apparently (?) has a different
507                 * offset on 6.2 machines... I've seen cases where
508                 * a 6.4 compiled top running on 6.2 printed
509                 * a garbage CPU-id. To be safe, I print the CPU-id
510                 * only if it falls within range [0..numcpus-1]
511                 */
512                sprintf(state_str, "run/%d", pp->pr_sonproc);
513                return state_str;
514        }
515
516        /* default */
517        return state_abbrev[state];
518}
519
520static char *
521format_prio(pp)
522        struct prpsinfo *pp;
523{
524    static char prio_str[10];
525
526    if (irix_ver < 6.4) {
527        /*
528         * Note: this is _compiled_ on 6.x where x >= 4 but I would like
529         * it to run on 6.2 6.3 as well (backward binary compatibility).
530         * Scheduling is completely different between these IRIX versions
531         * and some scheduling classes may even have different names.
532         *
533         * The solution: have more than one style of 'priority' depending
534         * on the OS version.
535         *
536         * See npri(1) + nice(2) + realtime(5) for scheduling classes,
537         * and priority values.
538         */
539        if (pp->pr_pri <= NDPHIMIN)                     /* real time? */
540                sprintf(prio_str, "+%d", pp->pr_pri);
541        else if (pp->pr_pri <= NDPNORMMIN)              /* normal interactive */
542                sprintf(prio_str, "%d", pp->pr_pri);
543        else                                            /* batch: low prio */
544                sprintf(prio_str, "b%d", pp->pr_pri);
545
546    } else {
547
548        /* copied from Kostadis's code */
549
550        if (strcmp(pp->pr_clname, "RT") == 0)           /* real time */
551                sprintf(prio_str, "+%d", pp->pr_pri);
552        else if (strcmp(pp->pr_clname, "DL") == 0)      /* unsupported ? */
553                sprintf(prio_str, "d%d", pp->pr_pri);
554        else if (strcmp(pp->pr_clname, "GN") == 0)
555                sprintf(prio_str, "g%d", pp->pr_pri);
556        else if (strcmp(pp->pr_clname, "GB") == 0)
557                sprintf(prio_str, "p%d", pp->pr_pri);
558
559        else if (strcmp(pp->pr_clname, "WL") == 0)      /* weightless */
560                return "w";
561        else if (strcmp(pp->pr_clname, "BC") == 0)
562                return "bc";                            /* batch critical */
563        else if (strcmp(pp->pr_clname, "B") == 0)
564                return "b";                             /* batch */
565        else
566                sprintf(prio_str, "%d", pp->pr_pri);
567    }
568    return prio_str;
569}
570
571static double
572clip_percent(double pct)
573{
574    if (pct < 0) {
575        return 0.0;
576    } else if (pct >= 100) {
577        return 99.99;
578    }
579    return pct;
580}
581
582char *
583format_next_process(handle, get_userid)
584        caddr_t handle;
585        char *(*get_userid)();
586{
587        struct prpsinfo *pp;
588        struct handle   *hp;
589        long            cputime;
590
591        /* find and remember the next proc structure */
592        hp = (struct handle *) handle;
593        pp = *(hp->next_proc++);
594        hp->remaining--;
595
596        /* get the process cpu usage since startup */
597        cputime = pp->pr_time.tv_sec;
598
599        /* format this entry */
600        sprintf(fmt,
601                Proc_format,
602                pp->pr_pid,
603                pp->pr_pgrp,
604                (*get_userid) (pp->pr_uid),
605                format_prio(pp),
606                format_k(pagetok(pp->pr_size)),
607                format_k(pagetok(pp->pr_rssize)),
608                format_state(pp),
609                format_time(cputime),
610                clip_percent(weighted_cpu(pp)),
611                clip_percent(percent_cpu(pp)),
612                pp->pr_fname);
613
614        /* return the result */
615        return (fmt);
616}
617
618/*
619 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
620 *      "offset" is the byte offset into the kernel for the desired value,
621 *      "ptr" points to a buffer into which the value is retrieved,
622 *      "size" is the size of the buffer (and the object to retrieve),
623 *      "refstr" is a reference string used when printing error meessages,
624 *          if "refstr" starts with a '!', then a failure on read will not
625 *          be fatal (this may seem like a silly way to do things, but I
626 *          really didn't want the overhead of another argument).
627 *
628 */
629
630int
631getkval(offset, ptr, size, refstr)
632        unsigned long offset;
633        int    *ptr;
634        int     size;
635        char   *refstr;
636
637{
638        if (lseek(kmem, (long) offset, SEEK_SET) == -1) {
639                if (*refstr == '!')
640                        refstr++;
641                (void) fprintf(stderr, "%s: %s: lseek to %s: %s\n",
642                                myname, KMEM, refstr, strerror(errno));
643                exit(0);
644        }
645        if (read(kmem, (char *) ptr, size) == -1) {
646                if (*refstr == '!')
647                        return (0);
648                else {
649                        (void) fprintf(stderr, "%s: %s: reading %s: %s\n",
650                                myname, KMEM, refstr, strerror(errno));
651                        exit(0);
652                }
653        }
654        return (1);
655}
656
657/*
658 *  compare_K - comparison functions for "qsort"
659 *      Compares the resource consumption of two processes using five
660 *      distinct keys.  The keys are:
661 *      percent cpu, cpu ticks, state, resident set size, total virtual
662 *      memory usage.  The process states are ordered as follows (from least
663 *      to most important):  WAIT, zombie, sleep, stop, idle, run.
664 *      Different comparison functions are used for different orderings.
665 */
666
667/* these are names given to allowed sorting orders -- first is default */
668char *ordernames[] = {
669        /*
670         * Aliases for user convenience/friendliness:
671         *      mem == size
672         *      rss == res
673         */
674        "cpu", "size", "mem", "res", "rss",
675        "time", "state", "command", "prio", NULL
676};
677
678/* forward definitions for comparison functions */
679int compare_cpu(struct prpsinfo **pp1, struct prpsinfo **pp2);
680int compare_size(struct prpsinfo **pp1, struct prpsinfo **pp2);
681int compare_res(struct prpsinfo **pp1, struct prpsinfo **pp2);
682int compare_time(struct prpsinfo **pp1, struct prpsinfo **pp2);
683int compare_state(struct prpsinfo **pp1, struct prpsinfo **pp2);
684int compare_cmd(struct prpsinfo **pp1, struct prpsinfo **pp2);
685int compare_prio(struct prpsinfo **pp1, struct prpsinfo **pp2);
686
687int (*proc_compares[])() = {
688        compare_cpu,
689        compare_size,
690        compare_size,
691        compare_res,
692        compare_res,
693        compare_time,
694        compare_state,
695        compare_cmd,
696        compare_prio,
697        NULL
698};
699
700
701/*
702 * The possible comparison expressions.  These are defined in such a way
703 * that they can be merely listed in the source code to define the actual
704 * desired ordering.
705 */
706
707#define ORDERKEY_PCTCPU \
708        if (dresult = percent_cpu(p2) - percent_cpu(p1),\
709        (result = dresult > 0.0 ? 1 : dresult < 0.0 ? -1 : 0) == 0)
710#define ORDERKEY_CPTICKS \
711        if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
712#define ORDERKEY_STATE  if ((result = proc_state(p2) - proc_state(p1)) == 0)
713#define ORDERKEY_PRIO   if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)
714#define ORDERKEY_RSSIZE if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
715#define ORDERKEY_MEM    if ((result = (p2->pr_size - p1->pr_size)) == 0)
716#define ORDERKEY_CMD    if ((result = strcmp(p1->pr_fname,p2->pr_fname)) == 0)
717
718int compare_cpu(struct prpsinfo **pp1, struct prpsinfo **pp2)
719{
720        struct prpsinfo *p1, *p2;
721        int             result;
722        double          dresult;
723
724        /* remove one level of indirection */
725        p1 = *pp1;
726        p2 = *pp2;
727        /*
728         * order by various keys, resorting to the next one
729         * whenever there's a tie in comparisons
730         */
731        ORDERKEY_PCTCPU
732        ORDERKEY_CPTICKS
733        ORDERKEY_STATE
734        ORDERKEY_PRIO
735        ORDERKEY_RSSIZE
736        ORDERKEY_MEM
737        ;
738        return (result);
739}
740
741int compare_size(struct prpsinfo **pp1, struct prpsinfo **pp2)
742{
743        struct prpsinfo *p1, *p2;
744        int             result;
745        double          dresult;
746
747        /* remove one level of indirection */
748        p1 = *pp1;
749        p2 = *pp2;
750        /*
751         * order by various keys, resorting to the next one
752         * whenever there's a tie in comparisons
753         */
754        ORDERKEY_MEM
755        ORDERKEY_RSSIZE
756        ORDERKEY_PCTCPU
757        ORDERKEY_CPTICKS
758        ORDERKEY_STATE
759        ORDERKEY_PRIO
760        ;
761        return (result);
762}
763
764int compare_res(struct prpsinfo **pp1, struct prpsinfo **pp2)
765{
766        struct prpsinfo *p1, *p2;
767        int             result;
768        double          dresult;
769
770        /* remove one level of indirection */
771        p1 = *pp1;
772        p2 = *pp2;
773        /*
774         * order by various keys, resorting to the next one
775         * whenever there's a tie in comparisons
776         */
777        ORDERKEY_RSSIZE
778        ORDERKEY_MEM
779        ORDERKEY_PCTCPU
780        ORDERKEY_CPTICKS
781        ORDERKEY_STATE
782        ORDERKEY_PRIO
783        ;
784        return (result);
785}
786
787int compare_time(struct prpsinfo **pp1, struct prpsinfo **pp2)
788{
789        struct prpsinfo *p1, *p2;
790        int             result;
791        double          dresult;
792
793        /* remove one level of indirection */
794        p1 = *pp1;
795        p2 = *pp2;
796        /*
797         * order by various keys, resorting to the next one
798         * whenever there's a tie in comparisons
799         */
800        ORDERKEY_CPTICKS
801        ORDERKEY_RSSIZE
802        ORDERKEY_MEM
803        ORDERKEY_PCTCPU
804        ORDERKEY_STATE
805        ORDERKEY_PRIO
806        ;
807        return (result);
808}
809
810int compare_cmd(struct prpsinfo **pp1, struct prpsinfo **pp2)
811{
812        struct prpsinfo *p1, *p2;
813        int             result;
814        double          dresult;
815
816        /* remove one level of indirection */
817        p1 = *pp1;
818        p2 = *pp2;
819        /*
820         * order by various keys, resorting to the next one
821         * whenever there's a tie in comparisons
822         */
823        ORDERKEY_CMD
824        ORDERKEY_PCTCPU
825        ORDERKEY_CPTICKS
826        ORDERKEY_RSSIZE
827        ;
828        return (result);
829}
830
831int compare_state(struct prpsinfo **pp1, struct prpsinfo **pp2)
832{
833        struct prpsinfo *p1, *p2;
834        int             result;
835        double          dresult;
836
837        /* remove one level of indirection */
838        p1 = *pp1;
839        p2 = *pp2;
840        /*
841         * order by various keys, resorting to the next one
842         * whenever there's a tie in comparisons
843         */
844        ORDERKEY_STATE
845        ORDERKEY_PCTCPU
846        ORDERKEY_CPTICKS
847        ORDERKEY_RSSIZE
848        ;
849        return (result);
850}
851
852int compare_prio(struct prpsinfo **pp1, struct prpsinfo **pp2)
853{
854        struct prpsinfo *p1, *p2;
855        int             result;
856        double          dresult;
857
858        /* remove one level of indirection */
859        p1 = *pp1;
860        p2 = *pp2;
861        /*
862         * order by various keys, resorting to the next one
863         * whenever there's a tie in comparisons
864         */
865        ORDERKEY_PRIO
866        ORDERKEY_PCTCPU
867        ;
868        return (result);
869}
870
871
872
873/* return the owner of the specified process. */
874uid_t
875proc_owner(pid)
876        pid_t   pid;
877{
878        register struct prpsinfo *p;
879        int     i;
880
881        for (i = 0, p = pbase; i < nproc; i++, p++)
882                if (p->pr_pid == pid)
883                        return (p->pr_uid);
884
885        return (-1);
886}
887
888#ifdef DO_MAPSIZE
889static void
890size(int fd, struct prpsinfo *ps)
891{
892        prmap_sgi_arg_t maparg;
893        struct prmap_sgi maps[256];
894        int     nmaps;
895        double  sz;
896        int     i;
897
898        maparg.pr_vaddr = (caddr_t) maps;
899        maparg.pr_size = sizeof maps;
900        if ((nmaps = ioctl(fd, PIOCMAP_SGI, &maparg)) == -1) {
901                /* XXX - this will be confusing */
902                return;
903        }
904        for (i = 0, sz = 0; i < nmaps; ++i) {
905                sz += (double) maps[i].pr_wsize / MA_WSIZE_FRAC;
906        }
907        ps->pr_rssize = (long) sz;
908}
909#endif
910
911/* get process table */
912void
913getptable(struct prpsinfo *baseptr)
914{
915        struct prpsinfo         *currproc; /* ptr to current proc struct */
916        int                     i, numprocs;
917        struct dirent           *direntp;
918        struct oldproc          *op, *endbase;
919        static struct timeval   lasttime, thistime;
920        static double           timediff, alpha, beta;
921
922        /* measure time between last call to getptable and current call */
923        gettimeofday (&thistime, NULL);
924
925        /*
926         * To avoid divides, we keep times in nanoseconds.  This is
927         * scaled by 1e7 rather than 1e9 so that when we divide we
928         * get percent.
929         */
930        timediff = ((double) thistime.tv_sec  * 1.0e7 -
931                    (double) lasttime.tv_sec  * 1.0e7)
932                                +
933                   ((double) thistime.tv_usec * 10 -
934                    (double) lasttime.tv_usec * 10);
935
936        /*
937         * Under extreme load conditions, sca has experienced
938         * an assert(timediff > 0) failure here. His guess is that
939         * sometimes timed resets the time backwards and gettimeofday
940         * returns a lower number on a later call.
941         * To be on the safe side I fix it here by setting timediff
942         * to some arbitrary small value (in nanoseconds).
943         */
944        if (timediff <= 0.0) timediff = 100.0;
945
946        lasttime = thistime;    /* prepare for next round */
947
948        /*
949         * constants for exponential decaying average.
950         *      avg = alpha * new + beta * avg
951         * The goal is 50% decay in 30 sec.  However if the sample period
952         * is greater than 30 sec, there's not a lot we can do.
953         */
954        if (timediff < 30.0e7) {
955                alpha = 0.5 * (timediff / 15.0e7);
956                beta = 1.0 - alpha;
957        } else {
958                alpha = 0.5;
959                beta = 0.5;
960        }
961        assert(alpha >= 0); assert(alpha <= 1);
962        assert(beta >= 0); assert(beta <= 1);
963
964        endbase = oldbase + oldprocs;
965        currproc = baseptr;
966
967        for (numprocs = 0, rewinddir(procdir); direntp = readdir(procdir);) {
968                int     fd;
969
970                if ((fd = open(direntp->d_name, O_RDONLY)) < 0)
971                        continue;
972
973                currproc = baseptr + numprocs;
974
975                if (ioctl(fd, PIOCPSINFO, currproc) < 0) {
976                        (void) close(fd);
977                        continue;
978                }
979
980                /*
981                 * SVR4 doesn't keep track of CPU% in the kernel,
982                 * so we have to do our own.
983                 * See if we've heard of this process before.
984                 * If so, compute % based on CPU since last time.
985                 */
986                op = oldbase + HASH (currproc->pr_pid);
987                for (;;) {
988                        if (op->oldpid == -1) /* not there */
989                                break;
990                        if (op->oldpid == currproc->pr_pid) {
991                                /* found old data */
992                                percent_cpu(currproc) =
993                                        ((currproc->pr_time.tv_sec * 1.0e9 +
994                                        currproc->pr_time.tv_nsec)
995                                        - op->oldtime) / timediff;
996
997                                weighted_cpu(currproc) =
998                                        op->oldpct * beta +
999                                        percent_cpu(currproc) * alpha;
1000
1001                                break;
1002                        }
1003                        op++;           /* try next entry in hash table */
1004                        if (op == endbase)    /* table wrap around */
1005                                op = oldbase;
1006                }
1007
1008                /* Otherwise, it's new, so use all of its CPU time */
1009                if (op->oldpid == -1) {
1010                        if (lasttime.tv_sec) {
1011                                percent_cpu(currproc) =
1012                                        (currproc->pr_time.tv_sec * 1.0e9 +
1013                                        currproc->pr_time.tv_nsec) / timediff;
1014
1015                                weighted_cpu(currproc) = percent_cpu(currproc);
1016                        } else {
1017                                /* first screen -- no difference is possible */
1018                                percent_cpu(currproc) = 0.0;
1019                                weighted_cpu(currproc) = 0.0;
1020                        }
1021                }
1022
1023#ifdef DO_MAPSIZE
1024                size(fd, currproc);
1025#endif
1026                numprocs++;
1027                (void) close(fd);
1028
1029                /*
1030                 * Bug: in case process count grew so dramatically
1031                 * as to exceed to table size. We give up on a full scan.
1032                 * the chances of this to happen are extremely slim due to
1033                 * the big factor we're using. getting nproc from nlist
1034                 * is not worth the headache. realloc wouldn't work either
1035                 * because we have pointers to the proc table so we cannot
1036                 * move it around.
1037                 */
1038                if (numprocs >= ptable_size) {
1039                        fprintf(stderr,
1040                                "preallocated proc table size (%d) exceeded, "
1041                                "skipping some processes\n", ptable_size);
1042                        break;
1043                }
1044        }
1045        nproc = numprocs;
1046
1047        /*
1048         * Save current CPU time for next time around
1049         * For the moment recreate the hash table each time, as the code
1050         * is easier that way.
1051         */
1052        oldprocs = 2 * nproc;
1053        endbase = oldbase + oldprocs;
1054
1055        for (op = oldbase; op < endbase; op++)
1056                op->oldpid = -1;
1057
1058        for (i = 0, currproc = baseptr; i < nproc; i++, currproc++) {
1059
1060                /* find an empty spot */
1061                op = oldbase + HASH (currproc->pr_pid);
1062                for (;;) {
1063                        if (op->oldpid == -1)
1064                                break;
1065                        op++;
1066                        if (op == endbase)
1067                                op = oldbase;
1068                }
1069                op->oldpid = currproc->pr_pid;
1070                op->oldtime = (currproc->pr_time.tv_sec * 1.0e9 +
1071                                currproc->pr_time.tv_nsec);
1072                op->oldpct = weighted_cpu(currproc);
1073        }
1074}
1075
Note: See TracBrowser for help on using the repository browser.