2 * Copyright (c) 1984 through 2008, William LeFebvre
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
16 * * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * top - a top users display for Unix
36 * SYNOPSIS: For Intel based System V Release 5 (Unixware7)
39 * System V release 5 for i[3456]86
41 * i586-sco-sysv5uw7 i386 SCO UNIX_SVR5 (UnixWare 7)
45 * CFLAGS: -DHAVE_GETOPT -DORDER
47 * AUTHORS: Mike Hopkirk <hops@sco.com>
48 * David Cutter <dpc@grail.com>
49 * Andrew Herbert <andrew@werple.apana.org.au>
50 * Robert Boucher <boucher@sofkin.ca>
54 * SHOW_NICE - process nice fields don't seem to be being updated so changed
55 * default to display # of threads in use instead.
56 * define this to display nice fields (values always 0)
61 #define prpsinfo psinfo
62 #include <sys/procfs.h>
64 #define pr_state pr_lwp.pr_state
65 #define pr_nice pr_lwp.pr_nice
66 #define pr_pri pr_lwp.pr_pri
67 #define pr_onpro pr_lwp.pr_onpro
68 #define ZOMBIE(p) ((p)->pr_nlwp == 0)
69 #define SIZE_K(p) pagetok((p)->pr_size)
70 #define RSS_K(p) pagetok((p)->pr_rssize)
81 #include <sys/types.h>
82 #include <sys/param.h>
84 #include <sys/sysmacros.h>
86 #include <sys/priocntl.h>
87 #include <sys/tspriocntl.h>
94 #define UNIX "/stand/unix"
95 #define KMEM "/dev/kmem"
96 #define PROCFS "/proc"
107 #define FSHIFT 8 /* bits to right of fixed binary point */
108 #define FSCALE (1<<FSHIFT)
111 #define loaddouble(x) ((double)x/FSCALE)
112 #define pagetok(size) ((size) * pagesz) >> LOG1024
114 /* definitions for the index in the nlist array */
119 static struct nlist nlst
[] =
127 static unsigned long avenrun_offset
;
128 static unsigned long mpid_offset
;
130 static unsigned int pagesz
;
132 static void reallocproc(int n
);
135 /* get_process_info passes back a handle. This is what it looks like: */
139 struct prpsinfo
**next_proc
;/* points to next valid proc pointer */
140 int remaining
; /* number of pointers remaining */
144 * These definitions control the format of the per-process area
147 static char header
[] =
149 " PID X PRI NICE SIZE RES STATE TIME CPU COMMAND";
151 " PID X PRI THR SIZE RES STATE TIME CPU COMMAND";
153 /* 0123456 -- field to fill in starts at header+6 */
154 #define UNAME_START 6
155 #define Proc_format \
156 "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %8.4f%% %.16s"
158 char *state_abbrev
[] =
159 {"oncpu", "run", "sleep", "stop", "idle", "zombie"};
162 int process_states
[8];
163 char *procstatenames
[] =
165 " on cpu, ", " running, ", " sleeping, ", " stopped, ",
166 " idling ", " zombie, ",
170 int cpu_states
[CPUSTATES
];
171 char *cpustatenames
[] =
172 {"idle", "user", "kernel", "wait", NULL
};
175 /* these are for detailing the memory statistics */
176 long memory_stats
[5];
177 char *memorynames
[] =
178 {"K phys, ", "K used, ", "K free, ", "K swapUsed, ", "K swapFree", NULL
};
180 /* these are names given to allowed sorting orders -- first is default */
182 {"state", "cpu", "size", "res", "time", "pid", "uid", "rpid", "ruid", NULL
};
184 /* forward definitions for comparison functions */
195 int (*proc_compares
[])() = {
208 static int kmem
= -1;
211 static struct prpsinfo
*pbase
;
212 static struct prpsinfo
**pref
;
215 /* useful externals */
217 extern char *sys_errlist
[];
219 extern long percentages ();
220 extern int check_nlist ();
221 extern int getkval ();
222 extern void perror ();
223 extern void getptable ();
228 static int kmet_init(void );
229 static int get_cpustates(int *new);
233 machine_init (struct statics
*statics
)
238 /* fill in the statics information */
239 statics
->procstate_names
= procstatenames
;
240 statics
->cpustate_names
= cpustatenames
;
241 statics
->memory_names
= memorynames
;
242 statics
->order_names
= ordernames
;
244 /* get the list of symbols we want to access in the kernel */
245 if (nlist (UNIX
, nlst
))
247 (void) fprintf (stderr
, "Unable to nlist %s\n", UNIX
);
251 /* make sure they were all found */
252 if (check_nlist (nlst
) > 0)
255 /* open kernel memory */
256 if ((kmem
= open (KMEM
, O_RDONLY
)) == -1)
262 v
.v_proc
=200; /* arbitrary default */
263 /* get the symbol values out of kmem */
264 /* NPROC Tuning parameter for max number of processes */
265 (void) getkval (nlst
[X_V
].n_value
, &v
, sizeof (struct var
), nlst
[X_V
].n_name
);
269 /* stash away certain offsets for later use */
270 mpid_offset
= nlst
[X_MPID
].n_value
;
271 avenrun_offset
= nlst
[X_AVENRUN
].n_value
;
273 /* allocate space for proc structure array and array of pointers */
274 bytes
= nproc
* sizeof (struct prpsinfo
);
275 pbase
= (struct prpsinfo
*) malloc (bytes
);
276 pref
= (struct prpsinfo
**) malloc (nproc
* sizeof (struct prpsinfo
*));
278 pagesz
= sysconf(_SC_PAGESIZE
);
281 /* Just in case ... */
282 if (pbase
== (struct prpsinfo
*) NULL
|| pref
== (struct prpsinfo
**) NULL
)
284 (void) fprintf (stderr
, "%s: can't allocate sufficient memory\n", myname
);
288 if (!(procdir
= opendir (PROCFS
)))
290 (void) fprintf (stderr
, "Unable to open %s\n", PROCFS
);
295 { /* handy for later on when we're reading it */
296 (void) fprintf (stderr
, "Unable to chdir to %s\n", PROCFS
);
308 format_header (char *uname_field
)
312 ptr
= header
+ UNAME_START
;
313 while (*uname_field
!= '\0')
314 *ptr
++ = *uname_field
++;
320 get_system_info (struct system_info
*si
)
324 static time_t cp_old
[CPUSTATES
];
325 static time_t cp_diff
[CPUSTATES
]; /* for cpu state percentages */
327 static long swap_total
;
328 static long swap_free
;
329 int new_states
[CPUSTATES
];
331 get_cpustates(new_states
);
333 /* convert cp_time counts to percentages */
334 (void) percentages (CPUSTATES
, cpu_states
, new_states
, cp_old
, cp_diff
);
338 /* get mpid -- process id of last process
339 * svr5 is nextpid - next pid to be assigned (already incremented)
341 (void) getkval (mpid_offset
, &(si
->last_pid
), sizeof (si
->last_pid
),
343 (si
->last_pid
)--; /* so we shld decrement for display */
346 /* get load average array */
347 (void) getkval (avenrun_offset
, (int *) avenrun
, sizeof (avenrun
), "avenrun");
348 /* convert load averages to doubles */
349 for (i
= 0; i
< 3; i
++)
350 si
->load_avg
[i
] = loaddouble(avenrun
[i
]);
352 mem
= sysconf(_SC_TOTAL_MEMORY
); /* physical mem */
353 memory_stats
[0] = pagetok (mem
);
355 mem
= kmet_get_freemem(); /* free mem */
356 memory_stats
[2] = pagetok (mem
);
358 /* mem = sysconf(_SC_GENERAL_MEMORY); */
359 memory_stats
[1] = memory_stats
[0] - memory_stats
[2]; /* active */
361 get_swapinfo(&swap_total
, &swap_free
);
362 memory_stats
[3] = pagetok(swap_total
- swap_free
);
363 memory_stats
[4] = pagetok(swap_free
);
366 /* set arrays and strings */
367 si
->cpustates
= cpu_states
;
368 si
->memory
= memory_stats
;
371 static struct handle handle
;
375 struct system_info
*si
,
376 struct process_select
*sel
,
380 register int total_procs
;
381 register int active_procs
;
382 register struct prpsinfo
**prefp
;
383 register struct prpsinfo
*pp
;
385 /* these are copied out of sel for speed */
390 /* Get current number of processes */
392 /* read all the proc structures */
395 /* get a pointer to the states summary array */
396 si
->procstates
= process_states
;
398 /* set up flags which define what we are going to select */
399 show_idle
= sel
->idle
;
400 show_system
= sel
->system
;
401 show_uid
= sel
->uid
!= -1;
403 nproc
= kmet_get_nproc();
405 /* count up process states and get pointers to interesting procs */
408 (void) memset (process_states
, 0, sizeof (process_states
));
411 for (pp
= pbase
, i
= 0; i
< nproc
; pp
++, i
++)
414 * Place pointers to each valid proc structure in pref[].
415 * Process slots that are actually in use have a non-zero
416 * status field. Processes with PR_ISSYS set are system
417 * processes---these get ignored unless show_sysprocs is set.
419 if ((pp
->pr_state
>= SONPROC
&& pp
->pr_state
<= SIDL
) &&
420 (show_system
|| ((pp
->pr_flag
& PR_ISSYS
) == 0)))
423 process_states
[pp
->pr_state
]++;
425 (show_idle
|| (pp
->pr_state
== SRUN
) || (pp
->pr_state
== SONPROC
)) &&
426 (!show_uid
|| pp
->pr_uid
== (uid_t
) sel
->uid
))
432 process_states
[sZOMB
]++; /* invented */
437 /* if requested, sort the "interesting" processes */
438 qsort ((char *) pref
, active_procs
, sizeof (struct prpsinfo
*),
441 /* remember active and total counts */
442 si
->p_total
= total_procs
;
443 si
->P_ACTIVE
= active_procs
;
445 /* pass back a handle */
446 handle
.next_proc
= pref
;
447 handle
.remaining
= active_procs
;
448 return ((caddr_t
) & handle
);
452 * cpu percentage calculation is as fm ps.c
453 * seems to be ratio of (sys+user time used)/(elapsed time)
454 * i.e percent of cpu utilised when on cpu
456 static double percent_cpu( struct prpsinfo
*pp
)
458 static time_t tim
= 0L;
464 tim
= time((time_t *) 0);
465 starttime
= pp
->pr_start
.tv_sec
;
466 if (pp
->pr_start
.tv_nsec
> 500000000)
468 etime
= (tim
- starttime
);
469 ctime
= pp
->pr_time
.tv_sec
;
470 if (pp
->pr_time
.tv_nsec
> 500000000)
474 /* return (float)(ctime * 100) / (unsigned)etime; */
475 /* this was ocasionally giving vals >100 for some
476 * unknown reason so the below normalises it
480 pct
= (float)(ctime
* 100) / (unsigned)etime
;
481 return (pct
< 100.0) ? pct
: 100.00;
487 char fmt
[MAX_COLS
]; /* static area where result is built */
490 format_next_process (
492 char *(*get_userid
) ())
494 register struct prpsinfo
*pp
;
496 register long cputime
;
497 register double pctcpu
;
499 /* find and remember the next proc structure */
500 hp
= (struct handle
*) handle
;
501 pp
= *(hp
->next_proc
++);
504 /* get the cpu usage and calculate the cpu percentages */
505 cputime
= pp
->pr_time
.tv_sec
;
506 pctcpu
= percent_cpu(pp
);
509 /* format this entry */
513 (*get_userid
) (pp
->pr_uid
),
518 (u_short
)pp
->pr_nlwp
< 999 ? (u_short
)pp
->pr_nlwp
: 999,
520 format_k(SIZE_K(pp
)),
522 (ZOMBIE(pp
)) ? state_abbrev
[sZOMB
]
523 : state_abbrev
[pp
->pr_state
],
524 format_time(cputime
),
525 /* 100.0 * */ pctcpu
,
526 printable(pp
->pr_fname
));
528 /* return the result */
533 * check_nlist(nlst) - checks the nlist to see if any symbols were not
534 * found. For every symbol that was not found, a one-line
535 * message is printed to stderr. The routine returns the
536 * number of symbols NOT found.
539 check_nlist (register struct nlist
*nlst
)
543 /* check to see if we got ALL the symbols we requested */
544 /* this will write one line to stderr for every symbol not found */
547 while (nlst
->n_name
!= NULL
)
549 if (nlst
->n_value
== 0)
551 /* this one wasn't found */
552 (void) fprintf (stderr
, "kernel: no symbol named `%s'\n", nlst
->n_name
);
562 * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
563 * "offset" is the byte offset into the kernel for the desired value,
564 * "ptr" points to a buffer into which the value is retrieved,
565 * "size" is the size of the buffer (and the object to retrieve),
566 * "refstr" is a reference string used when printing error meessages,
567 * if "refstr" starts with a '!', then a failure on read will not
568 * be fatal (this may seem like a silly way to do things, but I
569 * really didn't want the overhead of another argument).
574 unsigned long offset
,
579 if (lseek (kmem
, (long) offset
, 0) == -1)
583 (void) fprintf (stderr
, "%s: lseek to %s: %s\n",
584 myname
, refstr
, sys_errlist
[errno
]);
587 if (read (kmem
, (char *) ptr
, size
) == -1)
589 /* we lost the race with the kernel, process isn't in memory */
593 (void) fprintf (stderr
, "%s: reading %s: %s\n",
594 myname
, refstr
, sys_errlist
[errno
]);
600 /* ----------------- comparison routines for qsort ---------------- */
602 /* First, the possible comparison keys. These are defined in such a way
603 that they can be merely listed in the source code to define the actual
607 #define ORDERKEY_PCTCPU if (dresult = percent_cpu (p2) - percent_cpu (p1),\
608 (result = dresult > 0.0 ? 1 : \
609 dresult < 0.0 ? -1 : 0) == 0)
611 #define ORDERKEY_CPTICKS if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
612 #define ORDERKEY_STATE if ((result = (long) (sorted_state[p2->pr_state] - \
613 sorted_state[p1->pr_state])) == 0)
615 #define ORDERKEY_PRIO if ((result = p2->pr_pri - p1->pr_pri) == 0)
616 #define ORDERKEY_RSSIZE if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
617 #define ORDERKEY_MEM if ((result = (p2->pr_size - p1->pr_size)) == 0)
619 #define ORDERKEY_PID if ((result = (p2->pr_pid - p1->pr_pid)) == 0)
620 #define ORDERKEY_UID if ((result = (p2->pr_uid - p1->pr_uid)) == 0)
621 #define ORDERKEY_RPID if ((result = (p1->pr_pid - p2->pr_pid)) == 0)
622 #define ORDERKEY_RUID if ((result = (p1->pr_uid - p2->pr_uid)) == 0)
624 /* states enum {SONPROC, SRUN, SSLEEP, SSTOP, SIDL} */
625 unsigned char sorted_state
[] =
639 * proc_compare - original singleton comparison function for "qsort"
640 * Compares the resource consumption of two processes using five
641 * distinct keys. The keys (in descending order of importance) are:
642 * percent cpu, cpu ticks, state, resident set size, total virtual
643 * memory usage. The process states are ordered as follows (from least
644 * to most important): WAIT, zombie, sleep, stop, start, run. The
645 * array declaration below maps a process state index into a number
646 * that reflects this ordering.
648 /* default comparison rtn */
650 original_proc_compare (
651 struct prpsinfo
**pp1
,
652 struct prpsinfo
**pp2
)
654 register struct prpsinfo
*p1
;
655 register struct prpsinfo
*p2
;
656 register long result
;
659 /* remove one level of indirection */
663 /* compare percent cpu (pctcpu) */
664 dresult
= percent_cpu(p2
) - percent_cpu (p1
);
665 result
= dresult
> 0.0 ? 1 :
666 dresult
< 0.0 ? -1 : 0;
669 /* use cpticks to break the tie */
670 if ((result
= p2
->pr_time
.tv_sec
- p1
->pr_time
.tv_sec
) == 0)
672 /* use process state to break the tie */
673 if ((result
= (long) (sorted_state
[p2
->pr_state
] -
674 sorted_state
[p1
->pr_state
])) == 0)
676 /* use priority to break the tie */
677 if ((result
= p2
->pr_pri
- p1
->pr_pri
) == 0)
679 /* use resident set size (rssize) to break the tie */
680 if ((result
= p2
->pr_rssize
- p1
->pr_rssize
) == 0)
682 /* use total memory to break the tie */
683 result
= (p2
->pr_size
- p1
->pr_size
);
691 #endif /* original comparison rtn */
693 /* compare_state - comparison function for sorting by state,pri,time,size */
696 struct prpsinfo
**pp1
,
697 struct prpsinfo
**pp2
)
699 register struct prpsinfo
*p1
;
700 register struct prpsinfo
*p2
;
701 register long result
;
704 /* remove one level of indirection */
720 /* compare_cpu - the comparison function for sorting by cpu % (deflt) */
723 struct prpsinfo
**pp1
,
724 struct prpsinfo
**pp2
)
726 register struct prpsinfo
*p1
;
727 register struct prpsinfo
*p2
;
728 register long result
;
731 /* remove one level of indirection */
746 /* compare_size - the comparison function for sorting by total memory usage */
749 struct prpsinfo
**pp1
,
750 struct prpsinfo
**pp2
)
752 register struct prpsinfo
*p1
;
753 register struct prpsinfo
*p2
;
754 register long result
;
757 /* remove one level of indirection */
772 /* compare_res - the comparison function for sorting by resident set size */
775 struct prpsinfo
**pp1
,
776 struct prpsinfo
**pp2
)
778 register struct prpsinfo
*p1
;
779 register struct prpsinfo
*p2
;
780 register long result
;
783 /* remove one level of indirection */
798 /* compare_time - the comparison function for sorting by total cpu time */
801 struct prpsinfo
**pp1
,
802 struct prpsinfo
**pp2
)
804 register struct prpsinfo
*p1
;
805 register struct prpsinfo
*p2
;
806 register long result
;
809 /* remove one level of indirection */
824 /* compare_pid - the comparison function for sorting by pid */
827 struct prpsinfo
**pp1
,
828 struct prpsinfo
**pp2
)
830 register struct prpsinfo
*p1
;
831 register struct prpsinfo
*p2
;
832 register long result
;
835 /* remove one level of indirection */
851 /* compare_uid - the comparison function for sorting by user ID */
854 struct prpsinfo
**pp1
,
855 struct prpsinfo
**pp2
)
857 register struct prpsinfo
*p1
;
858 register struct prpsinfo
*p2
;
859 register long result
;
862 /* remove one level of indirection */
878 /* compare_rpid - the comparison function for sorting by pid ascending */
881 struct prpsinfo
**pp1
,
882 struct prpsinfo
**pp2
)
884 register struct prpsinfo
*p1
;
885 register struct prpsinfo
*p2
;
886 register long result
;
889 /* remove one level of indirection */
905 /* compare_uid - the comparison function for sorting by user ID ascending */
908 struct prpsinfo
**pp1
,
909 struct prpsinfo
**pp2
)
911 register struct prpsinfo
*p1
;
912 register struct prpsinfo
*p2
;
913 register long result
;
916 /* remove one level of indirection */
933 /* ---------------- helper rtns ---------------- */
939 getptable (struct prpsinfo
*baseptr
)
941 struct prpsinfo
*currproc
; /* pointer to current proc structure */
943 struct dirent
*direntp
;
946 for (rewinddir (procdir
); direntp
= readdir (procdir
);)
951 sprintf(buf
,"%s/psinfo", direntp
->d_name
);
953 if ((fd
= open (buf
, O_RDONLY
)) < 0)
956 if (read(fd
, currproc
, sizeof(psinfo_t
)) != sizeof(psinfo_t
))
967 /* Atypical place for growth */
968 if (numprocs
>= maxprocs
)
970 reallocproc(2 * numprocs
);
971 currproc
= (struct prpsinfo
*)
972 ((char *)baseptr
+ sizeof(psinfo_t
) * numprocs
);
977 if (nproc
!= numprocs
)
981 /* return the owner of the specified process, for use in commands.c as we're
982 running setuid root */
986 register struct prpsinfo
*p
;
988 for (i
= 0, p
= pbase
; i
< nproc
; i
++, p
++)
989 if (p
->pr_pid
== (pid_t
)pid
)
990 return ((int)(p
->pr_uid
));
996 setpriority (int dummy
, int who
, int niceval
)
1004 strcpy (pcinfo
.pc_clname
, "TS");
1005 if (priocntl (0, 0, PC_GETCID
, (caddr_t
) & pcinfo
) == -1)
1009 if (prio
> PRIO_MAX
)
1011 else if (prio
< PRIO_MIN
)
1014 tsparms
= (tsparms_t
*) pcparms
.pc_clparms
;
1015 scale
= ((tsinfo_t
*) pcinfo
.pc_clinfo
)->ts_maxupri
;
1016 tsparms
->ts_uprilim
= tsparms
->ts_upri
= -(scale
* prio
) / 20;
1017 pcparms
.pc_cid
= pcinfo
.pc_cid
;
1019 if (priocntl (P_PID
, who
, PC_SETPARMS
, (caddr_t
) & pcparms
) == -1)
1026 get_swapinfo(long *total
, long *fr
)
1028 register int cnt
, i
;
1030 struct swaptable
*swt
;
1031 struct swapent
*ste
;
1032 static char path
[256];
1034 /* get total number of swap entries */
1035 cnt
= swapctl(SC_GETNSWP
, 0);
1037 /* allocate enough space to hold count + n swapents */
1038 swt
= (struct swaptable
*)malloc(sizeof(int) +
1039 cnt
* sizeof(struct swapent
));
1048 /* fill in ste_path pointers: we don't care about the paths, so we point
1049 them all to the same buffer */
1050 ste
= &(swt
->swt_ent
[0]);
1054 ste
++->ste_path
= path
;
1057 /* grab all swap info */
1058 swapctl(SC_LIST
, swt
);
1060 /* walk thru the structs and sum up the fields */
1062 ste
= &(swt
->swt_ent
[0]);
1066 /* dont count slots being deleted */
1067 if (!(ste
->ste_flags
& ST_INDEL
) )
1069 t
+= ste
->ste_pages
;
1075 /* fill in the results */
1083 * When we reach a proc limit, we need to realloc the stuff.
1085 static void reallocproc(int n
)
1088 struct oldproc
*op
, *endbase
;
1095 /* allocate space for proc structure array and array of pointers */
1096 bytes
= maxprocs
* sizeof(psinfo_t
) ;
1097 pbase
= (struct prpsinfo
*) realloc(pbase
, bytes
);
1098 pref
= (struct prpsinfo
**) realloc(pref
,
1099 maxprocs
* sizeof(struct prpsinfo
*));
1101 /* Just in case ... */
1102 if (pbase
== (struct prpsinfo
*) NULL
|| pref
== (struct prpsinfo
**) NULL
)
1104 fprintf (stderr
, "%s: can't allocate sufficient memory\n", myname
);
1109 /* ---------------------------------------------------------------- */
1110 /* Access kernel Metrics
1111 * SVR5 uses metreg inteface to Kernel statistics (metrics)
1112 * see /usr/include/mas.h, /usr/include/metreg.h
1115 #include <sys/mman.h>
1120 static int md
; /* metric descriptor handle */
1121 static uint32 ncpu
; /* number of processors in system */
1124 static uint32
kmet_get_cpu( int type
, char *desc
);
1125 static void kmet_verify(
1126 uint32 md
, metid_t id
, units_t units
, type_t mettype
,
1127 uint32 metsz
, uint32 nobj
, uint32 nlocs
, resource_t res_id
,
1131 static int get_cpustates(int *new)
1133 new[0] = (int)kmet_get_cpu( MPC_CPU_IDLE
, "idle");
1134 new[1] = (int)kmet_get_cpu( MPC_CPU_USR
, "usr");
1135 new[2] = (int)kmet_get_cpu( MPC_CPU_SYS
, "sys");
1136 new[3] = (int)kmet_get_cpu( MPC_CPU_WIO
, "wio");
1140 /* initialises kernel metrics access and gets #cpus */
1141 static int kmet_init()
1145 /* open (and map in) the metric access file and assoc data structures */
1146 if( ( md
= mas_open( MAS_FILE
, MAS_MMAP_ACCESS
) ) < 0 )
1148 (void)fprintf(stderr
,"mas_open failed\n");
1153 /* verify the NCPU metric is everything we expect */
1154 kmet_verify(md
, NCPU
, CPUS
, CONFIGURABLE
, sizeof(short),
1155 1, 1, MAS_SYSTEM
, sizeof(uint32
) );
1157 /* get the number of cpu's on the system */
1158 if( (ncpu_p
= (uint32
*)mas_get_met( md
, NCPU
, 0 )) == NULL
)
1160 (void)fprintf(stderr
,"mas_get_met of ncpu failed\n");
1164 ncpu
= (uint32
)(*(short *)ncpu_p
);
1166 /* check that MPC_CPU_IDLE is of the form we expect
1167 * ( paranoically we should check the rest as well but ... )
1169 kmet_verify( md
, MPC_CPU_IDLE
, TIX
, PROFILE
, sizeof(uint32
),
1170 1, ncpu
, NCPU
, sizeof(short) );
1172 kmet_verify( md
, PROCUSE
, PROCESSES
, COUNT
, sizeof(uint32
),
1173 1, 1, MAS_SYSTEM
, sizeof(uint32
) );
1174 nproc
= kmet_get_nproc();
1179 /* done with kernel metrics access */
1183 if ( mas_close( md
) < 0 )
1185 (void)fprintf(stderr
,"mas_close failed\n");
1193 kmet_get_cpu( int type
, char *desc
)
1196 uint32 r
=0, rtot
=0 ;
1198 for (i
=0; i
<ncpu
; i
++)
1200 r
=*(uint32
*)mas_get_met( md
, (metid_t
)type
, 0 );
1203 (void)fprintf(stderr
,"mas_get_met of %s failed\n", desc
);
1207 rtot
+= r
; /* sum them for multi cpus */
1209 return rtot
/* /ncpu */ ;
1215 dl_t
*fm_p
, fm
, fmc
, denom
;
1222 if ((fm_p
= (dl_t
*)mas_get_met( md
, FREEMEM
, 0 )) == NULL
)
1224 (void)fprintf(stderr
,"mas_get_met of freemem failed\n");
1231 denom
.dl_lop
= (long) (td1
- td0
);
1234 /* calculate the freemem difference divided by the time diff
1235 * giving the freemem in that time sample
1236 * (new - old) / (time_between_samples)
1238 fmc
= lsub(fm
, fm_old
);
1241 fmc
= ldivide(fmc
, denom
);
1246 * return # of processes currently executing on system
1252 if ((p
= (uint32
*)mas_get_met( md
, PROCUSE
, 0 )) == NULL
)
1254 (void)fprintf(stderr
,"mas_get_met of procuse failed\n");
1263 * Function: kmet_verify
1264 * renamed from mas_usrtime example verify_met() fm Doug Souders
1266 * Description: Verify the registration data associated with this metric
1267 * match what are expected. Cautious consumer applications
1268 * should do this sort of verification before using metrics.
1272 uint32 md
, /* metric descriptor */
1273 metid_t id
, /* metric id number */
1274 units_t units
, /* expected units of metric */
1275 type_t mettype
, /* expected type of metric */
1276 uint32 metsz
, /* expected object size of metric */
1277 uint32 nobj
, /* expected number of array elements */
1278 uint32 nlocs
, /* expected number of instances */
1279 resource_t res_id
, /* expected resource id number */
1280 uint32 ressz
/* expected resource object size */
1284 char *name
; /* the name of the metric */
1285 units_t
*units_p
; /* the units of the metric */
1286 type_t
*mettype_p
; /* type field of the metric */
1287 uint32
*objsz_p
; /* size of each element in met */
1288 uint32
*nobj_p
; /* num of elements >1 then array*/
1289 uint32
*nlocs_p
; /* total number of instances */
1290 uint32
*status_p
; /* status word (update|avail) */
1291 resource_t
*resource_p
; /* the resource list of the met */
1292 uint32
*resval_p
; /* pointer to resource */
1293 uint32
*ressz_p
; /* size of the resource met */
1295 if (!(name
= mas_get_met_name( md
, id
)))
1297 (void)fprintf(stderr
,"mas_get_met_name failed\n");
1302 if (!(status_p
= mas_get_met_status( md
, id
)))
1304 (void)fprintf(stderr
,"mas_get_met_status of %s failed\n",
1309 if ( *status_p
!= MAS_AVAILABLE
)
1311 (void)fprintf(stderr
,"unexpected status word for %s\n"
1312 "- expected %u got %u\n",
1313 name
, MAS_AVAILABLE
, *status_p
);
1316 if (!(units_p
= mas_get_met_units( md
, id
)))
1318 (void)fprintf(stderr
,"mas_get_met_units of %s failed\n",
1323 if (units
!= *units_p
)
1325 (void)fprintf(stderr
,"unexpected units for %s\n"
1326 "- expected %u got %u\n",
1327 name
, units
, *units_p
);
1331 if (!(mettype_p
= mas_get_met_type( md
, id
)))
1333 (void)fprintf(stderr
,"mas_get_met_type of %s failed\n",
1338 if (mettype
!= *mettype_p
)
1340 (void)fprintf(stderr
,"unexpected metric type for %s\n"
1341 "- expected %u got %u\n",
1342 name
, mettype
, *mettype_p
);
1346 if (!(objsz_p
= mas_get_met_objsz( md
, id
)))
1348 (void)fprintf(stderr
,"mas_get_met_objsz of %s failed\n", name
);
1352 if (*objsz_p
!= metsz
)
1354 (void)fprintf(stderr
,"unexpected object size for %s\n"
1355 "- expected %u got %u\n",
1356 name
, metsz
, *objsz_p
);
1360 if (!(nobj_p
= mas_get_met_nobj( md
, id
)))
1362 (void)fprintf(stderr
,"mas_get_met_nobj of %s failed\n", name
);
1366 if (nobj
!= *nobj_p
)
1368 (void)fprintf(stderr
,"unexpected number of objects for %s\n"
1369 "- expected %u got %u\n",
1370 name
, nobj
, *nobj_p
);
1374 /* get the number of instances that libmas thinks it knows about */
1375 if (!(nlocs_p
= mas_get_met_nlocs( md
, id
)))
1377 (void)fprintf(stderr
,"mas_get_met_nlocs of %s failed\n", name
);
1381 if (nlocs
!= *nlocs_p
)
1383 (void)fprintf(stderr
,"unexpected number of instances for %s"
1384 " - expected %u got %u\n",
1385 name
, nlocs
, *nlocs_p
);
1389 /* get the resource list for the metric */
1390 if (!(resource_p
= mas_get_met_resources( md
, id
)))
1392 (void)fprintf(stderr
,"mas_get_met_resources of %s failed\n", name
);
1396 if (*resource_p
!= res_id
)
1398 (void)fprintf(stderr
,"unexpected resource id for %s\n"
1399 "- expected %u got %u\n",
1400 name
, res_id
, *resource_p
);
1403 /* get the size of the resource */
1404 if (!(ressz_p
= mas_get_met_objsz( md
, (metid_t
)(*resource_p
) )))
1406 (void)fprintf(stderr
,"mas_get_met_objsz of resource failed\n");
1410 if (*ressz_p
!= ressz
)
1412 (void)fprintf(stderr
,"unexpected resource size for %s\n"
1413 "- expected %u got %u\n",
1414 name
, ressz
, *ressz_p
);
1418 * get the address of the resource
1420 if (!(resval_p
= (uint32
*)mas_get_met( md
, *resource_p
, 0 )))
1422 (void)fprintf(stderr
,"mas_get_met of resource failed\n");
1426 if (ressz
== sizeof( short ) )
1428 if( (uint32
)(*(short *)resval_p
) != nlocs
)
1430 (void)fprintf(stderr
,"unexpected resource value for %s\n"
1431 "- expected %u got %u\n",
1432 name
, nlocs
, (uint32
)(*(short *)resval_p
) );
1437 { /* assume size of uint32 */
1438 if (*resval_p
!= nlocs
)
1440 (void)fprintf(stderr
,"unexpected resource value for %s\n"
1441 "- expected %u got %u\n",
1442 name
, nlocs
, *resval_p
);