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

Revision 16185, 16.0 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:  For Pyramid DC/OSX
5 *
6 * DESCRIPTION:
7 *      DC/OSX for MISserver
8 *      DC/OSX for Nile
9 *
10 * LIBS:  -lelf -lext
11 *
12 * AUTHORS:  Phillip Wu         <pwu01@qantek.com.au>
13 */
14
15#include "top.h"
16#include "machine.h"
17#include "utils.h"
18#include <stdio.h>
19#include <fcntl.h>
20#include <unistd.h>
21#include <stdlib.h>
22#include <errno.h>
23#include <dirent.h>
24#include <nlist.h>
25#include <string.h>
26#include <sys/types.h>
27#include <sys/param.h>
28#include <sys/tuneable.h>
29#include <sys/statis.h>
30#include <sys/proc.h>
31#include <sys/procfs.h>
32#include <sys/sysinfo.h>
33#include <sys/immu.h>
34#include <sys/sysmacros.h>
35#include <sys/vmmeter.h>
36#include <vm/anon.h>
37#include <sys/priocntl.h>
38#include <sys/rtpriocntl.h>
39#include <sys/tspriocntl.h>
40#include <sys/procset.h>
41#include <sys/var.h>
42
43#define UNIX "/stand/unix"
44#define KMEM "/dev/kmem"
45#define PROCFS "/proc"
46#define MAXCPU 24
47#define CPUSTATES       5
48
49#ifndef PRIO_MAX
50#define PRIO_MAX        20
51#endif
52#ifndef PRIO_MIN
53#define PRIO_MIN        -20
54#endif
55
56#ifndef FSCALE
57#define FSHIFT  8               /* bits to right of fixed binary point */
58#define FSCALE  (1<<FSHIFT)
59#endif
60
61#define loaddouble(x) ((double)(x) / FSCALE)
62#define percent_cpu(x) ((double)(x)->pr_cpu / FSCALE)
63#define weighted_cpu(pct, pp) ( ((pp)->pr_time.tv_sec) == 0 ? 0.0 : \
64        ((pp)->pr_cpu) / ((pp)->pr_time.tv_sec) )
65#define pagetok(size) ctob(size) >> LOG1024
66
67/* definitions for the index in the nlist array */
68#define X_AVENRUN       0
69#define X_MPID          1
70#define X_V             2
71#define X_NPROC         3
72#define X_PHYSMEM       4
73
74static struct nlist nlst[] =
75{
76  {"avenrun"},                  /* 0 */
77  {"mpid"},                     /* 1 */
78  {"v"},                        /* 2 */
79  {"nproc"},                    /* 3 */
80  {"physmem"},                  /* 4 */
81  {NULL}
82};
83
84static unsigned long avenrun_offset;
85static unsigned long mpid_offset;
86static unsigned long nproc_offset;
87static unsigned long physmem_offset;
88
89/* get_process_info passes back a handle.  This is what it looks like: */
90
91struct handle
92  {
93    struct prpsinfo **next_proc;/* points to next valid proc pointer */
94    int remaining;              /* number of pointers remaining */
95  };
96
97/*
98 *  These definitions control the format of the per-process area
99 */
100
101static char header[] =
102"  PID X        PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
103/* 0123456   -- field to fill in starts at header+6 */
104#define UNAME_START 6
105#define Proc_format \
106        "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %3d.0%% %5.2f%% %.16s"
107
108char *state_abbrev[] =
109{"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"};
110
111int process_states[8];
112char *procstatenames[] =
113{
114  "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
115  " starting, ", " on cpu, ", " swapped, ",
116  NULL
117};
118
119int cpu_states[CPUSTATES];
120char *cpustatenames[] =
121{"idle", "user", "kernel", "wait", "swap", NULL};
122
123/* these are for detailing the memory statistics */
124
125int memory_stats[5];
126char *memorynames[] =
127{"K real, ", "K active, ", "K free, ", "K swap, ", "K free swap", NULL};
128
129static int kmem = -1;
130static int nproc;
131static int bytes;
132static struct prpsinfo *pbase;
133static struct prpsinfo **pref;
134static DIR *xprocdir;
135
136/* useful externals */
137extern int errno;
138extern char *sys_errlist[];
139extern char *myname;
140extern int check_nlist ();
141extern int getkval ();
142extern void perror ();
143extern void getptable ();
144extern void quit ();
145extern int nlist ();
146
147int
148machine_init (struct statics *statics)
149  {
150    static struct var v;
151
152    /* fill in the statics information */
153    statics->procstate_names = procstatenames;
154    statics->cpustate_names = cpustatenames;
155    statics->memory_names = memorynames;
156
157    /* get the list of symbols we want to access in the kernel */
158    if (nlist (UNIX, nlst))
159      {
160        (void) fprintf (stderr, "Unable to nlist %s\n", UNIX);
161        return (-1);
162      }
163
164    /* make sure they were all found */
165    if (check_nlist (nlst) > 0)
166      return (-1);
167
168    /* open kernel memory */
169    if ((kmem = open (KMEM, O_RDONLY)) == -1)
170      {
171        perror (KMEM);
172        return (-1);
173      }
174
175    /* get the symbol values out of kmem */
176    /* NPROC Tuning parameter for max number of processes */
177    (void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name);
178    nproc = v.v_proc;
179
180    /* stash away certain offsets for later use */
181    mpid_offset = nlst[X_MPID].n_value;
182    nproc_offset = nlst[X_NPROC].n_value;
183    avenrun_offset = nlst[X_AVENRUN].n_value;
184    physmem_offset = nlst[X_PHYSMEM].n_value;
185
186    /* allocate space for proc structure array and array of pointers */
187    bytes = nproc * sizeof (struct prpsinfo);
188    pbase = (struct prpsinfo *) malloc (bytes);
189    pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
190
191    /* Just in case ... */
192    if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
193      {
194        (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
195        return (-1);
196      }
197
198    if (!(xprocdir = opendir (PROCFS)))
199      {
200        (void) fprintf (stderr, "Unable to open %s\n", PROCFS);
201        return (-1);
202      }
203
204    if (chdir (PROCFS))
205      {                         /* handy for later on when we're reading it */
206        (void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
207        return (-1);
208      }
209
210    /* all done! */
211    return (0);
212  }
213
214char *
215format_header (char *uname_field)
216{
217  register char *ptr;
218
219  ptr = header + UNAME_START;
220  while (*uname_field != '\0')
221    *ptr++ = *uname_field++;
222
223  return (header);
224}
225
226static int get_sysinfo_firsttime=0;
227static int physmem;
228static size_t   sysinfo_size, vmtotal_size, minfo_size;
229static int ncpu;
230void
231get_system_info (struct system_info *si)
232{
233  long avenrun[3];
234  static struct sysinfo sysinfo[MAXCPU];
235  static struct vmtotal vmtotal;
236  static struct minfo minfo;
237  static time_t cp_time[CPUSTATES];
238  static time_t cp_old[CPUSTATES];
239  static time_t cp_diff[CPUSTATES];     /* for cpu state percentages */
240  register int i, j, k, cpu;
241
242  /* Get number of cpus and size of system information data structure
243     but only first time */
244  if( ! get_sysinfo_firsttime )
245  {
246     get_sysinfo_firsttime=1;
247     if (statis("ncpu", STATIS_GET, &ncpu, sizeof(ncpu))== -1)
248     {
249      perror("failed to get sysinfo");
250      exit(1);
251     }
252     if (statis("sysinfo", STATIS_SIZ, &sysinfo_size, sizeof(sysinfo_size))==-1)
253     {
254      perror("failed to get sysinfo");
255      exit(1);
256     }
257     if (statis("vm total", STATIS_SIZ, &vmtotal_size, sizeof(vmtotal_size))==-1)
258     {
259      perror("failed to get vm total");
260      exit(1);
261     }
262     if (statis("minfo", STATIS_SIZ, &minfo_size, sizeof(minfo_size))==-1)
263     {
264      perror("failed to get minfo");
265      exit(1);
266     }
267     sysinfo_size *= ncpu;
268    (void) getkval (physmem_offset, (int *)(&physmem), sizeof(int), "physmem");
269    physmem=physmem<<2;
270    memory_stats[0] = (physmem/1024)*1000;
271   }
272 
273  /* Get system information  data structure from the kernel - one per cpu */
274  if( statis("sysinfo", STATIS_GET,  sysinfo, sysinfo_size) != sysinfo_size )
275  {
276    perror("failed to get sysinfo");
277    exit(1);
278  }
279
280  for( j = 0; j < CPUSTATES; j++)
281  {
282    cp_time[j] = 0;
283    for( cpu = 1; cpu < ncpu; cpu++)
284      cp_time[j] += sysinfo[cpu].cpu[j];
285    cp_time[j] /= ncpu;
286   }
287
288  /* convert cp_time counts to percentages */
289  (void) percentages (CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
290
291  /* get mpid -- process id of last process */
292  (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),
293                  "mpid");
294
295  /* get load average array */
296  (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");
297
298  /* convert load averages to doubles */
299  for (i = 0; i < 3; i++)
300    si->load_avg[i] = loaddouble (avenrun[i]);
301
302  /* get vmmeter and minfo */
303  if( statis("vm total", STATIS_GET,  &vmtotal, vmtotal_size) != vmtotal_size )
304  {
305    perror("failed to get vm total");
306    exit(1);
307  }
308  if( statis("minfo", STATIS_GET,  &minfo, minfo_size) != minfo_size )
309  {
310    perror("failed to get minfo");
311    exit(1);
312  }
313  /* convert memory stats to Kbytes */
314  memory_stats[1] = pagetok (vmtotal.t_arm);
315  memory_stats[2] = pagetok (vmtotal.t_free);
316  memory_stats[3] = pagetok (minfo.swap);
317  memory_stats[4] = pagetok (minfo.freeswap);
318
319  /* set arrays and strings */
320  si->cpustates = cpu_states;
321  si->memory = memory_stats;
322}
323
324static struct handle handle;
325
326caddr_t
327get_process_info (
328                   struct system_info *si,
329                   struct process_select *sel,
330                   int (*compare) ())
331{
332  register int i;
333  register int total_procs;
334  register int active_procs;
335  register struct prpsinfo **prefp;
336  register struct prpsinfo *pp;
337
338  /* these are copied out of sel for speed */
339  int show_idle;
340  int show_system;
341  int show_uid;
342
343  /* Get current number of processes */
344  (void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc");
345
346  /* read all the proc structures */
347  getptable (pbase);
348
349  /* get a pointer to the states summary array */
350  si->procstates = process_states;
351
352  /* set up flags which define what we are going to select */
353  show_idle = sel->idle;
354  show_system = sel->system;
355  show_uid = sel->uid != -1;
356
357  /* count up process states and get pointers to interesting procs */
358  total_procs = 0;
359  active_procs = 0;
360  (void) memset (process_states, 0, sizeof (process_states));
361  prefp = pref;
362
363  for (pp = pbase, i = 0; i < nproc; pp++, i++)
364    {
365      /*
366         *  Place pointers to each valid proc structure in pref[].
367         *  Process slots that are actually in use have a non-zero
368         *  status field.  Processes with SSYS set are system
369         *  processes---these get ignored unless show_sysprocs is set.
370         */
371      if (pp->pr_state != 0 &&
372          (show_system || ((pp->pr_flag & SSYS) == 0)))
373        {
374          total_procs++;
375          process_states[pp->pr_state]++;
376          if ((!pp->pr_zomb) &&
377              (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&
378              (!show_uid || pp->pr_uid == (uid_t) sel->uid))
379            {
380              *prefp++ = pp;
381              active_procs++;
382            }
383        }
384    }
385
386  /* if requested, sort the "interesting" processes */
387  if (compare != NULL)
388      qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), compare);
389
390  /* remember active and total counts */
391  si->p_total = total_procs;
392  si->p_active = active_procs;
393
394  /* pass back a handle */
395  handle.next_proc = pref;
396  handle.remaining = active_procs;
397  return ((caddr_t) & handle);
398}
399
400char fmt[MAX_COLS];                     /* static area where result is built */
401
402char *
403format_next_process (
404                      caddr_t handle,
405                      char *(*get_userid) ())
406{
407  register struct prpsinfo *pp;
408  struct handle *hp;
409  register long cputime;
410  register double pctcpu;
411
412  /* find and remember the next proc structure */
413  hp = (struct handle *) handle;
414  pp = *(hp->next_proc++);
415  hp->remaining--;
416
417  /* get the cpu usage and calculate the cpu percentages */
418  cputime = pp->pr_time.tv_sec;
419  pctcpu = percent_cpu (pp);
420
421  /* format this entry */
422  (void) sprintf (fmt,
423                  Proc_format,
424                  pp->pr_pid,
425                  (*get_userid) (pp->pr_uid),
426                  pp->pr_pri - PZERO,
427                  pp->pr_nice - NZERO,
428                  format_k(pagetok (pp->pr_size)),
429                  format_k(pagetok (pp->pr_rssize)),
430                  state_abbrev[pp->pr_state],
431                  format_time(cputime),
432                  (pp->pr_cpu & 0377),
433                  100.0 * pctcpu,
434                  pp->pr_fname);
435
436  /* return the result */
437  return (fmt);
438}
439
440/*
441 * check_nlist(nlst) - checks the nlist to see if any symbols were not
442 *              found.  For every symbol that was not found, a one-line
443 *              message is printed to stderr.  The routine returns the
444 *              number of symbols NOT found.
445 */
446int
447check_nlist (register struct nlist *nlst)
448{
449  register int i;
450
451  /* check to see if we got ALL the symbols we requested */
452  /* this will write one line to stderr for every symbol not found */
453
454  i = 0;
455  while (nlst->n_name != NULL)
456    {
457      if (nlst->n_type == 0)
458        {
459          /* this one wasn't found */
460          (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
461          i = 1;
462        }
463      nlst++;
464    }
465  return (i);
466}
467
468
469/*
470 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
471 *      "offset" is the byte offset into the kernel for the desired value,
472 *      "ptr" points to a buffer into which the value is retrieved,
473 *      "size" is the size of the buffer (and the object to retrieve),
474 *      "refstr" is a reference string used when printing error meessages,
475 *          if "refstr" starts with a '!', then a failure on read will not
476 *          be fatal (this may seem like a silly way to do things, but I
477 *          really didn't want the overhead of another argument).
478 *
479 */
480int
481getkval (
482          unsigned long offset,
483          int *ptr,
484          int size,
485          char *refstr)
486{
487#ifdef MIPS
488  if (lseek (kmem, (long) (offset & 0x7fffffff), 0) == -1)
489#else
490  if (lseek (kmem, (long) offset, 0) == -1)
491#endif
492    {
493      if (*refstr == '!')
494        refstr++;
495      (void) fprintf (stderr, "%s: lseek to %s: %s\n",
496                      myname, refstr, sys_errlist[errno]);
497      quit (22);
498    }
499  if (read (kmem, (char *) ptr, size) == -1)
500    if (*refstr == '!')
501      /* we lost the race with the kernel, process isn't in memory */
502      return (0);
503    else
504      {
505        (void) fprintf (stderr, "%s: reading %s: %s\n",
506                        myname, refstr, sys_errlist[errno]);
507        quit (23);
508      }
509  return (1);
510}
511
512/* comparison routine for qsort */
513
514/*
515 *  proc_compare - comparison function for "qsort"
516 *      Compares the resource consumption of two processes using five
517 *      distinct keys.  The keys (in descending order of importance) are:
518 *      percent cpu, cpu ticks, state, resident set size, total virtual
519 *      memory usage.  The process states are ordered as follows (from least
520 *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
521 *      array declaration below maps a process state index into a number
522 *      that reflects this ordering.
523 */
524
525
526unsigned char sorted_state[] =
527{
528  0,                            /* not used             */
529  3,                            /* sleep                */
530  6,                            /* run                  */
531  2,                            /* zombie               */
532  4,                            /* stop                 */
533  5,                            /* start                */
534  7,                            /* run on a processor   */
535  1                             /* being swapped (WAIT) */
536};
537
538int
539proc_compare (
540               struct prpsinfo **pp1,
541               struct prpsinfo **pp2)
542  {
543    register struct prpsinfo *p1;
544    register struct prpsinfo *p2;
545    register long result;
546
547    /* remove one level of indirection */
548    p1 = *pp1;
549    p2 = *pp2;
550
551    /* compare percent cpu (pctcpu) */
552    if ((result = (long) (p2->pr_cpu - p1->pr_cpu)) == 0)
553      {
554        /* use cpticks to break the tie */
555        if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
556          {
557            /* use process state to break the tie */
558            if ((result = (long) (sorted_state[p2->pr_state] -
559                                  sorted_state[p1->pr_state])) == 0)
560              {
561                /* use priority to break the tie */
562                if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)
563                  {
564                    /* use resident set size (rssize) to break the tie */
565                    if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
566                      {
567                        /* use total memory to break the tie */
568                        result = (p2->pr_size - p1->pr_size);
569                      }
570                  }
571              }
572          }
573      }
574    return (result);
575  }
576
577/*
578get process table
579*/
580void
581getptable (struct prpsinfo *baseptr)
582{
583  struct prpsinfo *currproc;    /* pointer to current proc structure    */
584  int numprocs = 0;
585  struct dirent *direntp;
586
587  for (rewinddir (xprocdir); direntp = readdir (xprocdir);)
588    {
589      int fd;
590
591      if ((fd = open (direntp->d_name, O_RDONLY)) < 0)
592        continue;
593
594      currproc = &baseptr[numprocs];
595      if (ioctl (fd, PIOCPSINFO, currproc) < 0)
596        {
597          (void) close (fd);
598          continue;
599        }
600
601      numprocs++;
602      (void) close (fd);
603    }
604
605  if (nproc != numprocs)
606    nproc = numprocs;
607}
608
609/* return the owner of the specified process, for use in commands.c as we're
610   running setuid root */
611uid_t
612proc_owner (pid_t pid)
613{
614  register struct prpsinfo *p;
615  int i;
616  for (i = 0, p = pbase; i < nproc; i++, p++)
617    if (p->pr_pid == pid)
618      return (p->pr_uid);
619
620  return (-1);
621}
622
623int
624setpriority (int dummy, int who, int niceval)
625{
626  int scale;
627  int prio;
628  pcinfo_t pcinfo;
629  pcparms_t pcparms;
630  tsparms_t *tsparms;
631
632  strcpy (pcinfo.pc_clname, "TS");
633  if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
634    return (-1);
635
636  prio = niceval;
637  if (prio > PRIO_MAX)
638    prio = PRIO_MAX;
639  else if (prio < PRIO_MIN)
640    prio = PRIO_MIN;
641
642  tsparms = (tsparms_t *) pcparms.pc_clparms;
643  scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
644  tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
645  pcparms.pc_cid = pcinfo.pc_cid;
646
647  if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
648    return (-1);
649
650  return (0);
651}
Note: See TracBrowser for help on using the repository browser.