source: trunk/third/top/machine/m_ftx.c @ 9084

Revision 9084, 20.8 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9083, which included commits to RCS files with non-trunk default branches.
RevLine 
[9083]1/*
2 * top - a top users display for Unix
3 *
4 * SYNOPSIS:  For FTX based System V Release 4
5 *
6 * DESCRIPTION:
7 *      System V release 4.0.x for FTX (FTX 2.3 and greater)
8 *
9 * LIBS:  -lelf
10 *
11 * AUTHORS:  Andrew Herbert     <andrew@werple.apana.org.au>
12 *           Robert Boucher     <boucher@sofkin.ca>
13 *           Steve Scherf       <scherf@swdc.stratus.com>
14 */
15
16#include <stdio.h>
17#include <fcntl.h>
18#include <unistd.h>
19#include <stdlib.h>
20#include <errno.h>
21#include <dirent.h>
22#include <nlist.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/param.h>
26#include <sys/procfs.h>
27#include <sys/sysmacros.h>
28#include <sys/sysinfo.h>
29#include <sys/vmmeter.h>
30#include <vm/anon.h>
31#include <sys/priocntl.h>
32#include <sys/rtpriocntl.h>
33#include <sys/tspriocntl.h>
34#include <sys/procset.h>
35#include <sys/var.h>
36#include <sys/tuneable.h>
37#include <sys/fs/rf_acct.h>
38#include <sys/sar.h>
39#include <sys/ftx/dcm.h>
40
41#include "top.h"
42#include "machine.h"
43
44#define UNIX "/unix"
45#define KMEM "/dev/kmem"
46#define PROCFS "/proc"
47#define SAR "/dev/sar"
48#define CPUSTATES       5
49
50#ifndef PRIO_MAX
51#define PRIO_MAX        20
52#endif
53#ifndef PRIO_MIN
54#define PRIO_MIN        -20
55#endif
56
57#ifndef FSCALE
58#define FSHIFT  8               /* bits to right of fixed binary point */
59#define FSCALE  (1<<FSHIFT)
60#endif
61
62#define loaddouble(x) ((double)(x) / FSCALE)
63#define pagetok(size) ctob(size) >> LOG1024
64#define PRTOMS(pp) \
65        ((pp)->pr_time.tv_sec * 1000) + ((pp)->pr_time.tv_nsec / 1000000)
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_ANONINFO      4
73#define X_TOTAL         5
74
75static struct nlist nlst[] =
76{
77  {"avenrun"},                  /* 0 */
78  {"mpid"},                     /* 1 */
79  {"v"},                        /* 2 */
80  {"nproc"},                    /* 3 */
81  {"anoninfo"},                 /* 4 */
82  {"total"},                    /* 5 */
83  {NULL}
84};
85
86static unsigned long avenrun_offset;
87static unsigned long mpid_offset;
88static unsigned long nproc_offset;
89static unsigned long anoninfo_offset;
90static unsigned long total_offset;
91
92/* get_process_info passes back a handle.  This is what it looks like: */
93
94struct handle
95  {
96    struct prpsinfo **next_proc;/* points to next valid proc pointer */
97    int remaining;              /* number of pointers remaining */
98  };
99
100#define MAXTIMEHIST     12
101#define HASHSZ          512     /* This must be a power of 2. */
102#define HASHMASK        (HASHSZ - 1)
103#define TF_USED         0x01
104#define TF_NEWPROC      0x02
105
106#define TD_HASH(pid) \
107        (timedata_t *)(&hash[(pid) & HASHMASK])
108
109typedef struct hash {
110        struct timedata *hnext;
111        struct timedata *hlast;
112} hash_t;
113
114/* data for CPU and WCPU fields */
115typedef struct timedata {
116        struct timedata *hnext;
117        struct timedata *hlast;
118        struct timedata *lnext;
119        struct timedata *llast;
120        pid_t pid;
121        char index;
122        char cnt;
123        char flags;
124        long hist[MAXTIMEHIST];
125        long time;
126        long ltime;
127} timedata_t;
128
129
130/*
131 *  These definitions control the format of the per-process area
132 */
133
134static char header[] =
135"  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
136/* 0123456   -- field to fill in starts at header+6 */
137#define UNAME_START 6
138#define Proc_format \
139        "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.16s"
140
141char *state_abbrev[] =
142{"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"};
143
144int process_states[8];
145char *procstatenames[] =
146{
147  "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
148  " starting, ", " on cpu, ", " swapped, ",
149  NULL
150};
151
152int cpu_states[CPUSTATES];
153char *cpustatenames[] =
154{"idle", "user", "kernel", "wait", "swap", NULL};
155
156/* these are for detailing the memory statistics */
157
158int memory_stats[5];
159char *memorynames[] =
160{"K real, ", "K active, ", "K free, ", "K swap, ", "K free swap", NULL};
161
162static int kmem;
163static int sar;
164static int initted;
165static int nproc;
166static int bytes;
167static struct prpsinfo *pbase;
168static struct prpsinfo **pref;
169static DIR *procdir;
170static char cpu_state[MAX_LOG_CPU];
171static struct sysinfo cpu_sysinfo[MAX_LOG_CPU];
172static sar_percpu_args_t spa;
173static timedata_t timedata;
174static long total_time;
175static double total_cpu;
176static hash_t hash[HASHSZ];
177
178/* useful externals */
179extern int errno;
180extern char *sys_errlist[];
181extern char *myname;
182extern long percentages ();
183extern int check_nlist ();
184extern int getkval ();
185extern void perror ();
186extern void getptable ();
187extern void quit ();
188extern int nlist ();
189
190/* Prototypes. */
191void getsysinfo(struct sysinfo *);
192void add_time(struct prpsinfo *);
193void get_cpu(struct prpsinfo *, double *, double *);
194void clean_timedata(void);
195timedata_t *get_timedata(struct prpsinfo *);
196
197
198int
199machine_init (struct statics *statics)
200  {
201    int i;
202    static struct var v;
203
204    /* fill in the statics information */
205    statics->procstate_names = procstatenames;
206    statics->cpustate_names = cpustatenames;
207    statics->memory_names = memorynames;
208
209    /* get the list of symbols we want to access in the kernel */
210    if (nlist (UNIX, nlst))
211      {
212        (void) fprintf (stderr, "Unable to nlist %s\n", UNIX);
213        return (-1);
214      }
215
216    /* make sure they were all found */
217    if (check_nlist (nlst) > 0)
218      return (-1);
219
220    /* open kernel memory */
221    if ((kmem = open (KMEM, O_RDONLY)) == -1)
222      {
223        perror (KMEM);
224        return (-1);
225      }
226
227    /* Open the sar driver device node. */
228    if ((sar = open(SAR, O_RDONLY)) == -1)
229      {
230        perror (SAR);
231        return (-1);
232      }
233
234
235    /* get the symbol values out of kmem */
236    /* NPROC Tuning parameter for max number of processes */
237    (void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name);
238    nproc = v.v_proc;
239
240    /* stash away certain offsets for later use */
241    mpid_offset = nlst[X_MPID].n_value;
242    nproc_offset = nlst[X_NPROC].n_value;
243    avenrun_offset = nlst[X_AVENRUN].n_value;
244    anoninfo_offset = nlst[X_ANONINFO].n_value;
245    total_offset = nlst[X_TOTAL].n_value;
246
247    /* allocate space for proc structure array and array of pointers */
248    bytes = nproc * sizeof (struct prpsinfo);
249    pbase = (struct prpsinfo *) malloc (bytes);
250    pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
251
252    /* Just in case ... */
253    if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
254      {
255        (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
256        return (-1);
257      }
258
259    if (!(procdir = opendir (PROCFS)))
260      {
261        (void) fprintf (stderr, "Unable to open %s\n", PROCFS);
262        return (-1);
263      }
264
265    if (chdir (PROCFS))
266      {                         /* handy for later on when we're reading it */
267        (void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
268        return (-1);
269      }
270
271    /* Set up the pointers to the sysinfo data area. */
272    spa.uvcp = (caddr_t) &cpu_state[0];
273    spa.uvsp = (caddr_t) &cpu_sysinfo[0];
274
275    timedata.lnext = &timedata;
276    timedata.llast = &timedata;
277
278    for (i = 0; i < HASHSZ; i++) {
279      hash[i].hnext = (timedata_t *)&hash[i];
280      hash[i].hlast = (timedata_t *)&hash[i];
281    }
282
283    /* all done! */
284    return (0);
285  }
286
287char *
288format_header (char *uname_field)
289{
290  register char *ptr;
291
292  ptr = header + UNAME_START;
293  while (*uname_field != '\0')
294    *ptr++ = *uname_field++;
295
296  return (header);
297}
298
299void
300get_system_info (struct system_info *si)
301{
302  long avenrun[3];
303  struct sysinfo sysinfo;
304  struct vmtotal total;
305  struct anoninfo anoninfo;
306  static time_t cp_old[CPUSTATES];
307  static time_t cp_diff[CPUSTATES];     /* for cpu state percentages */
308  register int i;
309
310  getsysinfo(&sysinfo);
311
312  /* convert cp_time counts to percentages */
313  (void) percentages (CPUSTATES, cpu_states, sysinfo.cpu, cp_old, cp_diff);
314
315  /* Find total CPU utilization, as a fraction of 1. */
316  total_cpu = (cpu_states[CPU_USER] + cpu_states[CPU_KERNEL]) / 1000.0;
317
318  /* get mpid -- process id of last process */
319  (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),
320                  "mpid");
321
322  /* get load average array */
323  (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");
324
325  /* convert load averages to doubles */
326  for (i = 0; i < 3; i++)
327    si->load_avg[i] = loaddouble (avenrun[i]);
328
329  /* get total -- systemwide main memory usage structure */
330  (void) getkval (total_offset, (int *) (&total), sizeof (total), "total");
331  /* convert memory stats to Kbytes */
332  memory_stats[0] = pagetok (total.t_rm);
333  memory_stats[1] = pagetok (total.t_arm);
334  memory_stats[2] = pagetok (total.t_free);
335  (void) getkval (anoninfo_offset, (int *) (&anoninfo), sizeof (anoninfo),
336                  "anoninfo");
337  memory_stats[3] = pagetok (anoninfo.ani_max - anoninfo.ani_free);
338  memory_stats[4] = pagetok (anoninfo.ani_max - anoninfo.ani_resv);
339
340  /* set arrays and strings */
341  si->cpustates = cpu_states;
342  si->memory = memory_stats;
343}
344
345static struct handle handle;
346
347caddr_t
348get_process_info (
349                   struct system_info *si,
350                   struct process_select *sel,
351                   int (*compare) ())
352{
353  register int i;
354  register int total_procs;
355  register int active_procs;
356  register struct prpsinfo **prefp;
357  register struct prpsinfo *pp;
358
359  /* these are copied out of sel for speed */
360  int show_idle;
361  int show_system;
362  int show_uid;
363
364  /* Get current number of processes */
365  (void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc");
366
367  /* read all the proc structures */
368  getptable (pbase);
369
370  /* get a pointer to the states summary array */
371  si->procstates = process_states;
372
373  /* set up flags which define what we are going to select */
374  show_idle = sel->idle;
375  show_system = sel->system;
376  show_uid = sel->uid != -1;
377
378  /* count up process states and get pointers to interesting procs */
379  total_procs = 0;
380  active_procs = 0;
381  total_time = 0;
382  (void) memset (process_states, 0, sizeof (process_states));
383  prefp = pref;
384
385  clean_timedata();
386
387  for (pp = pbase, i = 0; i < nproc; pp++, i++)
388    {
389      /*
390         *  Place pointers to each valid proc structure in pref[].
391         *  Process slots that are actually in use have a non-zero
392         *  status field.  Processes with SSYS set are system
393         *  processes---these get ignored unless show_sysprocs is set.
394         */
395      if (pp->pr_state != 0 &&
396          (show_system || ((pp->pr_flag & SSYS) == 0)))
397        {
398          total_procs++;
399          process_states[pp->pr_state]++;
400          if ((!pp->pr_zomb) &&
401              (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&
402              (!show_uid || pp->pr_uid == (uid_t) sel->uid))
403            {
404              *prefp++ = pp;
405              active_procs++;
406            }
407        }
408
409      if (pp->pr_state != 0)
410        add_time(pp);
411    }
412
413  /* Note that we've run this at least once. */
414  initted++;
415
416  /* if requested, sort the "interesting" processes */
417  if (compare != NULL)
418      qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), compare);
419
420  /* remember active and total counts */
421  si->p_total = total_procs;
422  si->p_active = active_procs;
423
424  /* pass back a handle */
425  handle.next_proc = pref;
426  handle.remaining = active_procs;
427  return ((caddr_t) & handle);
428}
429
430char fmt[128];                  /* static area where result is built */
431
432char *
433format_next_process (
434                      caddr_t handle,
435                      char *(*get_userid) ())
436{
437  register struct prpsinfo *pp;
438  struct handle *hp;
439  register long cputime;
440  double pctcpu;
441  double pctwcpu;
442
443  /* find and remember the next proc structure */
444  hp = (struct handle *) handle;
445  pp = *(hp->next_proc++);
446  hp->remaining--;
447
448  /* get the cpu usage and calculate the cpu percentages */
449  cputime = pp->pr_time.tv_sec;
450  get_cpu(pp, &pctcpu, &pctwcpu);
451
452  /* format this entry */
453  (void) sprintf (fmt,
454                  Proc_format,
455                  pp->pr_pid,
456                  (*get_userid) (pp->pr_uid),
457                  pp->pr_pri - PZERO,
458                  pp->pr_nice - NZERO,
459                  pagetok (pp->pr_size),
460                  pagetok (pp->pr_rssize),
461                  state_abbrev[pp->pr_state],
462                  cputime / 60l,
463                  cputime % 60l,
464                  pctwcpu,
465                  pctcpu,
466                  pp->pr_fname);
467
468  /* return the result */
469  return (fmt);
470}
471
472/*
473 * check_nlist(nlst) - checks the nlist to see if any symbols were not
474 *              found.  For every symbol that was not found, a one-line
475 *              message is printed to stderr.  The routine returns the
476 *              number of symbols NOT found.
477 */
478int
479check_nlist (register struct nlist *nlst)
480{
481  register int i;
482
483  /* check to see if we got ALL the symbols we requested */
484  /* this will write one line to stderr for every symbol not found */
485
486  i = 0;
487  while (nlst->n_name != NULL)
488    {
489      if (nlst->n_type == 0)
490        {
491          /* this one wasn't found */
492          (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
493          i = 1;
494        }
495      nlst++;
496    }
497  return (i);
498}
499
500
501/*
502 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
503 *      "offset" is the byte offset into the kernel for the desired value,
504 *      "ptr" points to a buffer into which the value is retrieved,
505 *      "size" is the size of the buffer (and the object to retrieve),
506 *      "refstr" is a reference string used when printing error meessages,
507 *          if "refstr" starts with a '!', then a failure on read will not
508 *          be fatal (this may seem like a silly way to do things, but I
509 *          really didn't want the overhead of another argument).
510 *
511 */
512int
513getkval (
514          unsigned long offset,
515          int *ptr,
516          int size,
517          char *refstr)
518{
519  if (lseek (kmem, (long) offset, 0) == -1)
520    {
521      if (*refstr == '!')
522        refstr++;
523      (void) fprintf (stderr, "%s: lseek to %s: %s\n",
524                      myname, refstr, sys_errlist[errno]);
525      quit (22);
526    }
527  if (read (kmem, (char *) ptr, size) == -1)
528    if (*refstr == '!')
529      /* we lost the race with the kernel, process isn't in memory */
530      return (0);
531    else
532      {
533        (void) fprintf (stderr, "%s: reading %s: %s\n",
534                        myname, refstr, sys_errlist[errno]);
535        quit (23);
536      }
537  return (1);
538}
539
540/* comparison routine for qsort */
541
542/*
543 *  proc_compare - comparison function for "qsort"
544 *      Compares the resource consumption of two processes using five
545 *      distinct keys.  The keys (in descending order of importance) are:
546 *      percent cpu, cpu ticks, state, resident set size, total virtual
547 *      memory usage.  The process states are ordered as follows (from least
548 *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
549 *      array declaration below maps a process state index into a number
550 *      that reflects this ordering.
551 */
552
553
554unsigned char sorted_state[] =
555{
556  0,                            /* not used             */
557  3,                            /* sleep                */
558  6,                            /* run                  */
559  2,                            /* zombie               */
560  4,                            /* stop                 */
561  5,                            /* start                */
562  7,                            /* run on a processor   */
563  1                             /* being swapped (WAIT) */
564};
565
566int
567proc_compare (
568               struct prpsinfo **pp1,
569               struct prpsinfo **pp2)
570  {
571    register struct prpsinfo *p1;
572    register struct prpsinfo *p2;
573    register long result;
574    register long d1;
575    register long d2;
576    register timedata_t *td;
577
578    /* remove one level of indirection */
579    p1 = *pp1;
580    p2 = *pp2;
581
582    td = get_timedata(p1);
583    if (td->ltime == -1)
584      d1 = 0;
585    else
586      d1 = td->time - td->ltime;
587
588    td = get_timedata(p2);
589    if (td->ltime == -1)
590      d2 = 0;
591    else
592      d2 = td->time - td->ltime;
593
594    /* compare cpu usage */
595    if ((result = d2 - d1) == 0)
596      {
597        /* use cpticks to break the tie */
598        if ((result = (PRTOMS(p2) - PRTOMS(p1))) == 0)
599          {
600            /* use process state to break the tie */
601            if ((result = (long) (sorted_state[p2->pr_state] -
602                                  sorted_state[p1->pr_state])) == 0)
603              {
604                /* use priority to break the tie */
605                if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)
606                  {
607                    /* use resident set size (rssize) to break the tie */
608                    if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
609                      {
610                        /* use total memory to break the tie */
611                        result = (p2->pr_size - p1->pr_size);
612                      }
613                  }
614              }
615          }
616      }
617    return (result);
618  }
619
620/*
621get process table
622*/
623void
624getptable (struct prpsinfo *baseptr)
625{
626  struct prpsinfo *currproc;    /* pointer to current proc structure    */
627  int numprocs = 0;
628  struct dirent *direntp;
629
630  for (rewinddir (procdir); direntp = readdir (procdir);)
631    {
632      int fd;
633
634      if ((fd = open (direntp->d_name, O_RDONLY)) < 0)
635        continue;
636
637      currproc = &baseptr[numprocs];
638      if (ioctl (fd, PIOCPSINFO, currproc) < 0)
639        {
640          (void) close (fd);
641          continue;
642        }
643
644      numprocs++;
645      (void) close (fd);
646    }
647
648  if (nproc != numprocs)
649    nproc = numprocs;
650}
651
652/* return the owner of the specified process, for use in commands.c as we're
653   running setuid root */
654uid_t
655proc_owner (pid_t pid)
656{
657  register struct prpsinfo *p;
658  int i;
659  for (i = 0, p = pbase; i < nproc; i++, p++)
660    if (p->pr_pid == pid)
661      return (p->pr_uid);
662
663  return (-1);
664}
665
666int
667setpriority (int dummy, int who, int niceval)
668{
669  int scale;
670  int prio;
671  pcinfo_t pcinfo;
672  pcparms_t pcparms;
673  tsparms_t *tsparms;
674
675  strcpy (pcinfo.pc_clname, "TS");
676  if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
677    return (-1);
678
679  prio = niceval;
680  if (prio > PRIO_MAX)
681    prio = PRIO_MAX;
682  else if (prio < PRIO_MIN)
683    prio = PRIO_MIN;
684
685  tsparms = (tsparms_t *) pcparms.pc_clparms;
686  scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
687  tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
688  pcparms.pc_cid = pcinfo.pc_cid;
689
690  if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
691    return (-1);
692
693  return (0);
694}
695
696
697/*
698 * Per-process CPU calculation:
699 *
700 * We emulate actual % CPU usage calculation, since the statistics
701 * kept by FTX are not valid for this purpose. We fake this calculation
702 * by totalling the amount of CPU time used by all processes since the
703 * last update, and dividing this into the CPU time used by the process
704 * in question. For the WCPU value, we average the CPU calculations for the
705 * process over the last td->cnt updates. This means that the first update
706 * when starting top will always be 0% CPU (no big deal), and that WCPU will
707 * be averaged over a varying amount of time (also no big deal). This is
708 * probably the best we can do, since the kernel doesn't keep any of these
709 * statistics itself.
710 *
711 * This method seems to yield good results. The only problems seem to be the
712 * fact that the first update always shows 0%, and that the
713 * sysinfo CPU data isn't always in sync with the per-process CPU usage
714 * when a CPU-intensive process quits. This latter problem causes funny
715 * results, because the remaining processes get credited with the residual
716 * CPU time.
717 *
718 * This algorithm may seem CPU intensive, but it's actually very
719 * inexpensive. The expensive part is the ioctl call to the sar driver.
720 * No amount of optimization in this program will reduce the sar overhead.
721 */
722
723void
724getsysinfo (struct sysinfo *sysinfo)
725{
726        register int i;
727        register int j;
728        register int cpus;
729
730        /* Get the per-CPU sysinfo data from sar. */
731        if(ioctl(sar, SAR_SYSINFO, &spa)) {
732                perror("ioctl(sar, SAR_SYSINFO)");
733                quit(24);
734        }
735
736        (void)memset((char *)sysinfo, 0, sizeof(struct sysinfo));
737
738        /* Average the state times to get systemwide values. */
739        for(i = 0, cpus = 0; i < MAX_LOG_CPU; i++) {
740                if(cpu_state[i] != SAR_CPU_RUNNING)
741                        continue;
742
743                cpus++;
744
745                for(j = 0; j < 5; j++)
746                        sysinfo->cpu[j] += cpu_sysinfo[i].cpu[j];
747        }
748
749        for(i = 0; i < 5; i++)
750                sysinfo->cpu[i] /= cpus;
751}
752
753
754void
755add_time (struct prpsinfo *pp)
756{
757        register timedata_t *td;
758
759        td = get_timedata(pp);
760
761        td->flags |= TF_USED;
762
763        if(td->time == -1) {
764                td->time = PRTOMS(pp);
765
766                if(!(td->flags & TF_NEWPROC))
767                        return;
768
769                td->flags &= ~TF_NEWPROC;
770                td->ltime = 0;
771        }
772        else {
773                td->ltime = td->time;
774                td->time = PRTOMS(pp);
775        }
776
777        /* Keep track of the time spent by all processes. */
778        total_time += td->time - td->ltime;
779}
780
781
782void
783get_cpu(struct prpsinfo *pp, double *cpu, double *wcpu)
784{
785        register int i;
786        register int j;
787        register long t;
788        register timedata_t *td;
789
790        td = get_timedata(pp);
791
792        /* No history, so return 0%. */
793        if(td->ltime == -1) {
794                *cpu = 0;
795                *wcpu = 0;
796                return;
797        }
798
799        i = td->index;
800        td->index = (i + 1) % MAXTIMEHIST;
801        td->cnt = MIN((td->cnt + 1), MAXTIMEHIST);
802
803        /* Compute CPU usage (time diff from last update / total cpu time). */
804        /* We don't want to div by 0. */
805        if(total_time == 0) {
806                td->hist[i] = 0;
807                *cpu = 0.0;
808        }
809        else {
810                t = (td->time - td->ltime) * 10000 / total_time * total_cpu;
811                td->hist[i] = t;
812                *cpu = t / 100.0;
813        }
814
815        /* Compute WCPU usage (average CPU % since oldest update). */
816        for(j = 0, t = 0; j < td->cnt; j++) {
817                t += td->hist[i];
818
819                i--;
820                if(i < 0)
821                        i = MAXTIMEHIST - 1;
822        }
823        *wcpu = t / j / 100.0;
824}
825
826
827timedata_t *
828get_timedata(struct prpsinfo *pp)
829{
830        register timedata_t *t;
831        register timedata_t *l;
832
833        l = TD_HASH(pp->pr_pid);
834
835        for(t = l->hnext; t != l; t = t->hnext)
836                if(t->pid == pp->pr_pid)
837                        return t;
838
839        t = (timedata_t *)malloc(sizeof(timedata_t));
840        if(t == 0) {
841                perror("malloc");
842                quit(25);
843        }
844
845        t->pid = pp->pr_pid;
846        t->index = 0;
847        t->cnt = 0;
848        t->time = -1;
849        t->ltime = -1;
850
851        if(initted)
852                t->flags = TF_USED | TF_NEWPROC;
853        else
854                t->flags = TF_USED;
855
856        /* Put struct on hash list. */
857        t->hnext = l->hnext;
858        t->hlast = l;
859        l->hnext->hlast = t;
860        l->hnext = t;
861
862        /* Put struct on timedata list. */
863        t->lnext = timedata.lnext;
864        t->llast = &timedata;
865        timedata.lnext->llast = t;
866        timedata.lnext = t;
867
868        return t;
869}
870
871
872void
873clean_timedata(void)
874{
875        register timedata_t *t;
876
877        for(t = timedata.lnext; t != &timedata; t = t->lnext) {
878                if(!(t->flags & TF_USED)) {
879                        t->hnext->hlast = t->hlast;
880                        t->hlast->hnext = t->hnext;
881                        t->lnext->llast = t->llast;
882                        t->llast->lnext = t->lnext;
883                        free(t);
884                }
885                else {
886                        t->flags &= ~TF_USED;
887                }
888        }
889}
Note: See TracBrowser for help on using the repository browser.