Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / top / dist / machine / m_aix43.c
blob11ed4dbb1d64b5e13d91523762c83e06773904d3
1 /*
2 * Copyright (c) 1984 through 2008, William LeFebvre
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
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
14 * distribution.
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: PowerPC running AIX 4.2 or higher
38 * DESCRIPTION:
39 * This is the machine-dependent module for AIX 4.2 and higher
40 * It is currenlty only tested on PowerPC architectures.
42 * TERMCAP: -lcurses
44 * CFLAGS: -DORDER -DHAVE_GETOPT
46 * LIBS: -bD:0x18000000
48 * AUTHOR: Joep Vesseur <joep@fwi.uva.nl>
50 * PATCHES: Antoine Tabary <tabary@bruyeres.cea.fr>
53 #include "config.h"
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <fcntl.h>
58 #include <nlist.h>
59 #include <sys/sysinfo.h>
60 #include <procinfo.h>
61 #include <sys/proc.h>
62 #include <sys/times.h>
63 #include <sys/param.h>
64 #include <pwd.h>
65 #include "top.h"
66 #include "machine.h"
67 #include "utils.h"
70 #define PROCRESS(p) (((p)->pi_trss + (p)->pi_drss)*4)
71 #define PROCSIZE(p) (((p)->pi_tsize/1024+(p)->pi_dvm)*4)
72 #define PROCTIME(pi) (pi->pi_ru.ru_utime.tv_sec + pi->pi_ru.ru_stime.tv_sec)
76 * structure definition taken from 'monitor' by Jussi Maki (jmaki@hut.fi)
78 struct vmker {
79 uint n0,n1,n2,n3,n4,n5,n6,n7,n8;
80 uint totalmem;
81 uint badmem; /* this is used in RS/6000 model 220 */
82 uint freemem;
83 uint n12;
84 uint numperm; /* this seems to keep other than text and data segment
85 usage; name taken from /usr/lpp/bos/samples/vmtune.c */
86 uint totalvmem,freevmem;
87 uint n15, n16, n17, n18, n19;
91 #define KMEM "/dev/kmem"
93 /* Indices in the nlist array */
94 #define X_AVENRUN 0
95 #define X_SYSINFO 1
96 #define X_VMKER 2
97 #define X_PROC 3
98 #define X_V 4
100 static struct nlist nlst[] = {
101 { "avenrun", 0, 0, 0, 0, 0 }, /* 0 */
102 { "sysinfo", 0, 0, 0, 0, 0 }, /* 1 */
103 { "vmker", 0, 0, 0, 0, 0 }, /* 2 */
104 { "proc", 0, 0, 0, 0, 0 }, /* 3 */
105 { "v", 0, 0, 0, 0, 0 }, /* 4 */
106 { NULL, 0, 0, 0, 0, 0 }
110 /* get_process_info returns handle. definition is here */
111 struct handle
113 struct procsinfo **next_proc;
114 int remaining;
118 * These definitions control the format of the per-process area
120 static char header[] =
121 " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
122 /* 0123456 -- field to fill in starts at header+6 */
123 #define UNAME_START 7
125 #define Proc_format \
126 "%6d %-8.8s %3d %4d %5d%c %4d%c %-5s %6s %5.2f%% %5.2f%% %.14s%s"
129 /* these are for detailing the process states */
130 int process_states[9];
131 char *procstatenames[] = {
132 " none, ", " sleeping, ", " state2, ", " runnable, ",
133 " idle, ", " zombie, ", " stopped, ", " running, ", " swapped, ",
134 NULL
138 /* these are for detailing the cpu states */
139 int cpu_states[4];
140 char *cpustatenames[] = {
141 "idle", "user", "kernel", "wait",
142 NULL
145 /* these are for detailing the memory statistics */
146 long memory_stats[4];
147 char *memorynames[] = {
148 "K Total, ", "K Free, ", "K Buffers", NULL
150 #define M_REAL 0
151 #define M_REALFREE 1
152 #define M_BUFFERS 2
154 long swap_stats[3];
155 char *swapnames[] = {
156 "K Total, ", "K Free", NULL
159 #define M_VIRTUAL 0
160 #define M_VIRTFREE 1
162 char *state_abbrev[] = {
163 "", "sleep", "", "", "sleep", "zomb", "stop", "run", "swap"
166 /* sorting orders. first is default */
167 char *ordernames[] = {
168 "cpu", "size", "res", "time", "pri", NULL
171 /* compare routines */
172 int compare_cpu(), compare_size(), compare_res(), compare_time(),
173 compare_prio();
175 int (*proc_compares[])() = {
176 compare_cpu,
177 compare_size,
178 compare_res,
179 compare_time,
180 compare_prio,
181 NULL
184 /* useful externals */
185 extern int errno;
186 extern char *sys_errlist[];
187 long lseek();
188 long time();
189 long percentages();
192 /* useful globals */
193 int kmem; /* file descriptor */
195 /* offsets in kernel */
196 static unsigned long avenrun_offset;
197 static unsigned long sysinfo_offset;
198 static unsigned long vmker_offset;
199 static unsigned long proc_offset;
200 static unsigned long v_offset;
202 /* used for calculating cpu state percentages */
203 static long cp_time[CPU_NTIMES];
204 static long cp_old[CPU_NTIMES];
205 static long cp_diff[CPU_NTIMES];
207 /* the runqueue length is a cumulative value. keep old value */
208 long old_runque;
210 /* process info */
211 struct var v_info; /* to determine nprocs */
212 int nprocs; /* maximum nr of procs in proctab */
213 int ncpus; /* nr of cpus installed */
215 int ptsize; /* size of process table in bytes */
216 struct proc *p_proc; /* a copy of the process table */
217 struct procsinfo *p_info; /* needed for vm and ru info */
218 struct procsinfo **pref; /* processes selected for display */
219 int pref_len; /* number of processes selected */
221 /* needed to calculate WCPU */
222 unsigned long curtime;
226 * Initialize globals, get kernel offsets and stuff...
228 machine_init(struct statics *statics)
231 time_t uptime, now;
232 struct tms tbuf;
234 if ((kmem = open(KMEM, O_RDONLY)) == -1) {
235 perror(KMEM);
236 return -1;
239 /* get kernel symbol offsets */
240 if (knlist(nlst, 5, sizeof(struct nlist)) != 0) {
241 perror("knlist");
242 return -1;
244 avenrun_offset = nlst[X_AVENRUN].n_value;
245 sysinfo_offset = nlst[X_SYSINFO].n_value;
246 vmker_offset = nlst[X_VMKER].n_value;
247 proc_offset = nlst[X_PROC].n_value;
248 v_offset = nlst[X_V].n_value;
250 getkval(v_offset, (caddr_t)&v_info, sizeof v_info, "v");
252 ncpus = v_info.v_ncpus; /* number of cpus */
253 nprocs = PROCMASK(PIDMAX);
254 if (nprocs > 1024) nprocs = 1024;
256 ptsize = nprocs * sizeof (struct proc);
257 p_proc = (struct proc *)malloc(ptsize);
258 p_info = (struct procsinfo *)malloc(nprocs * sizeof (struct procsinfo));
259 pref = (struct procsinfo **)malloc(nprocs * sizeof (struct procsinfo *));
261 if (!p_proc || !p_info || !pref) {
262 fprintf(stderr, "top: not enough memory\n");
263 return -1;
266 /* set boot time */
267 now = time(NULL);
268 uptime = times(&tbuf) / HZ;
269 statics->boottime = now - uptime;
271 statics->procstate_names = procstatenames;
272 statics->cpustate_names = cpustatenames;
273 statics->memory_names = memorynames;
274 statics->order_names = ordernames;
275 statics->swap_names = swapnames;
277 return(0);
282 char *format_header(char *uname_field)
285 register char *ptr;
287 ptr = header + UNAME_START;
288 while (*uname_field != '\0')
290 *ptr++ = *uname_field++;
293 return(header);
298 void
299 get_system_info(struct system_info *si)
302 int load_avg[3];
303 struct sysinfo s_info;
304 struct vmker m_info;
305 int i;
306 double total = 0;
308 /* get the load avarage array */
309 getkval(avenrun_offset, (caddr_t)load_avg, sizeof load_avg, "avenrun");
311 /* get the sysinfo structure */
312 getkval(sysinfo_offset, (caddr_t)&s_info, sizeof s_info, "sysinfo");
314 /* get vmker structure */
315 getkval(vmker_offset, (caddr_t)&m_info, sizeof m_info, "vmker");
317 /* convert load avarages to doubles */
318 for (i = 0; i < 3; i++)
319 si->load_avg[i] = (double)load_avg[i]/65536.0;
321 /* calculate cpu state in percentages */
322 for (i = 0; i < CPU_NTIMES; i++) {
323 cp_old[i] = cp_time[i];
324 cp_time[i] = s_info.cpu[i];
325 cp_diff[i] = cp_time[i] - cp_old[i];
326 total += cp_diff[i];
329 total = total/1000.0; /* top itself will correct this */
330 for (i = 0; i < CPU_NTIMES; i++) {
331 cpu_states[i] = cp_diff[i] / total;
334 /* calculate memory statistics, scale 4K pages to megabytes */
335 #define PAGE_TO_MB(a) ((a)*4/1024)
336 memory_stats[M_REAL] = PAGE_TO_MB(m_info.totalmem);
337 memory_stats[M_REALFREE] = PAGE_TO_MB(m_info.freemem);
338 memory_stats[M_BUFFERS] = PAGE_TO_MB(m_info.numperm);
339 swap_stats[M_VIRTUAL] = PAGE_TO_MB(m_info.totalvmem);
340 swap_stats[M_VIRTFREE] = PAGE_TO_MB(m_info.freevmem);
342 /* runnable processes */
343 process_states[0] = s_info.runque - old_runque;
344 old_runque = s_info.runque;
346 si->cpustates = cpu_states;
347 si->memory = memory_stats;
348 si->swap = swap_stats;
351 static struct handle handle;
353 caddr_t
354 get_process_info(struct system_info *si, struct process_select *sel, int compare_index)
357 int i, nproc;
358 int ptsize_util;
359 int active_procs = 0, total_procs = 0;
360 struct procsinfo *pp, **p_pref = pref;
361 unsigned long pctcpu;
362 pid_t procsindex = 0;
363 struct proc *p;
365 si->procstates = process_states;
367 curtime = time(0);
369 /* get the procsinfo structures of all running processes */
370 nproc = getprocs(p_info, sizeof (struct procsinfo), NULL, 0,
371 &procsindex, nprocs);
372 if (nproc < 0) {
373 perror("getprocs");
374 quit(1);
377 /* the swapper has no cmd-line attached */
378 strcpy(p_info[0].pi_comm, "swapper");
380 /* get proc table */
381 ptsize_util = (PROCMASK(p_info[nproc-1].pi_pid)+1) * sizeof(struct proc);
382 getkval(proc_offset, (caddr_t)p_proc, ptsize_util, "proc");
384 memset(process_states, 0, sizeof process_states);
386 /* build a list of pointers to processes to show. walk through the
387 * list of procsinfo structures instead of the proc table since the
388 * mapping of procsinfo -> proctable is easy, the other way around
389 * is cumbersome
391 for (pp = p_info, i = 0; i < nproc; pp++, i++) {
393 p = &p_proc[PROCMASK(pp->pi_pid)];
395 /* AIX marks all runnable processes as ACTIVE. We want to know
396 which processes are sleeping, so check used cpu ticks and adjust
397 status field accordingly
399 if (p->p_stat == SACTIVE && p->p_cpticks == 0)
400 p->p_stat = SIDL;
402 if (pp->pi_state && (sel->system || ((pp->pi_flags & SKPROC) == 0))) {
403 total_procs++;
404 process_states[p->p_stat]++;
405 if ( (pp->pi_state != SZOMB) &&
406 (sel->idle || p->p_cpticks != 0 || (p->p_stat == SACTIVE))
407 && (sel->uid == -1 || pp->pi_uid == (uid_t)sel->uid)) {
408 *p_pref++ = pp;
409 active_procs++;
414 /* the pref array now holds pointers to the procsinfo structures in
415 * the p_info array that were selected for display
418 /* sort if requested */
419 if (si->p_active)
420 qsort((char *)pref, active_procs, sizeof (struct procsinfo *),
421 proc_compares[compare_index]);
423 si->last_pid = -1; /* no way to figure out last used pid */
424 si->p_total = total_procs;
425 si->p_active = pref_len = active_procs;
427 handle.next_proc = pref;
428 handle.remaining = active_procs;
430 return((caddr_t)&handle);
433 char fmt[MAX_COLS]; /* static area where result is built */
435 /* define what weighted cpu is. use definition of %CPU from 'man ps(1)' */
436 #define weighted_cpu(pp) (PROCTIME(pp) == 0 ? 0.0 : \
437 (((PROCTIME(pp)*100.0)/(curtime-pi->pi_start)/ncpus)))
438 #define double_pctcpu(p) ((double)p->p_pctcpu/(double)FLT_MODULO)
440 char *
441 format_next_process(caddr_t handle, char *(*get_userid)())
444 register struct handle *hp;
445 register struct procsinfo *pi;
446 register struct proc *p;
447 char *uname;
448 long cpu_time;
449 int proc_size, proc_ress;
450 char size_unit = 'K';
451 char ress_unit = 'K';
453 hp = (struct handle *)handle;
454 if (hp->remaining == 0) { /* safe guard */
455 fmt[0] = '\0';
456 return fmt;
458 pi = *(hp->next_proc++);
459 hp->remaining--;
460 p = &p_proc[PROCMASK(pi->pi_pid)];
462 cpu_time = PROCTIME(pi);
464 /* we disply sizes up to 10M in KiloBytes, beyond 10M in MegaBytes */
465 if ((proc_size = (pi->pi_tsize/1024+pi->pi_dvm)*4) > 10240) {
466 proc_size /= 1024;
467 size_unit = 'M';
469 if ((proc_ress = (pi->pi_trss + pi->pi_drss)*4) > 10240) {
470 proc_ress /= 1024;
471 ress_unit = 'M';
474 sprintf(fmt, Proc_format ,
475 pi->pi_pid, /* PID */
476 (*get_userid)(pi->pi_uid), /* login name */
477 getpriority(PRIO_PROCESS, pi->pi_pid),
478 EXTRACT_NICE(p), /* fixed or vari */
479 proc_size, /* size */
480 size_unit, /* K or M */
481 proc_ress, /* resident */
482 ress_unit, /* K or M */
483 state_abbrev[p->p_stat], /* process state */
484 format_time(cpu_time), /* time used */
485 weighted_cpu(pi), /* WCPU */
486 100.0 * double_pctcpu(p), /* CPU */
487 printable(pi->pi_comm), /* COMM */
488 (pi->pi_flags & SKPROC) == 0 ? "" : " (sys)" /* kernel process? */
490 return(fmt);
495 * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
496 * "offset" is the byte offset into the kernel for the desired value,
497 * "ptr" points to a buffer into which the value is retrieved,
498 * "size" is the size of the buffer (and the object to retrieve),
499 * "refstr" is a reference string used when printing error meessages,
500 * if "refstr" starts with a '!', then a failure on read will not
501 * be fatal (this may seem like a silly way to do things, but I
502 * really didn't want the overhead of another argument).
507 getkval(unsigned long offset, caddr_t ptr, int size, char *refstr)
510 int upper_2gb = 0;
512 /* reads above 2Gb are done by seeking to offset%2Gb, and supplying
513 * 1 (opposed to 0) as fourth parameter to readx (see 'man kmem')
515 if (offset > 1<<31) {
516 upper_2gb = 1;
517 offset &= 0x7fffffff;
520 if (lseek(kmem, offset, SEEK_SET) != offset) {
521 fprintf(stderr, "top: lseek failed\n");
522 quit(2);
525 if (readx(kmem, ptr, size, upper_2gb) != size) {
526 if (*refstr == '!')
527 return 0;
528 else {
529 fprintf(stderr, "top: kvm_read for %s: %s\n", refstr,
530 sys_errlist[errno]);
531 quit(2);
535 return 1 ;
538 /* comparison routine for qsort */
540 * The following code is taken from the solaris module and adjusted
541 * for AIX -- JV .
544 #define ORDERKEY_PCTCPU \
545 if (lresult = p2->p_pctcpu - p1->p_pctcpu, \
546 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
548 #define ORDERKEY_CPTICKS \
549 if ((result = PROCTIME(pi2) - PROCTIME(pi1)) == 0)
552 #define ORDERKEY_STATE \
553 if ((result = sorted_state[p2->p_stat] \
554 - sorted_state[p1->p_stat]) == 0)
556 /* Nice values directly reflect the process' priority, and are always >0 ;-) */
557 #define ORDERKEY_PRIO \
558 if ((result = EXTRACT_NICE(p1) - EXTRACT_NICE(p2)) == 0)
560 #define ORDERKEY_RSSIZE \
561 if ((result = PROCRESS(pi2) - PROCRESS(pi1)) == 0)
562 #define ORDERKEY_MEM \
563 if ((result = PROCSIZE(pi2) - PROCSIZE(pi1)) == 0)
565 static unsigned char sorted_state[] =
567 0, /* not used */
571 3, /* sleep */
572 1, /* zombie */
573 4, /* stop */
574 6, /* run */
575 2, /* swap */
578 /* compare_cpu - the comparison function for sorting by cpu percentage */
581 compare_cpu(struct procsinfo **ppi1, struct procsinfo **ppi2)
584 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
585 register struct proc *p1;
586 register struct proc *p2;
587 register int result;
588 register long lresult;
590 p1 = &p_proc[PROCMASK(pi1->pi_pid)];
591 p2 = &p_proc[PROCMASK(pi2->pi_pid)];
593 ORDERKEY_PCTCPU
594 ORDERKEY_CPTICKS
595 ORDERKEY_STATE
596 ORDERKEY_PRIO
597 ORDERKEY_RSSIZE
598 ORDERKEY_MEM
601 return result;
605 /* compare_size - the comparison function for sorting by total memory usage */
608 compare_size(struct procsinfo **ppi1, struct procsinfo **ppi2)
611 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
612 register struct proc *p1;
613 register struct proc *p2;
614 register int result;
615 register long lresult;
617 p1 = &p_proc[PROCMASK(pi1->pi_pid)];
618 p2 = &p_proc[PROCMASK(pi2->pi_pid)];
620 ORDERKEY_MEM
621 ORDERKEY_RSSIZE
622 ORDERKEY_PCTCPU
623 ORDERKEY_CPTICKS
624 ORDERKEY_STATE
625 ORDERKEY_PRIO
628 return result;
632 /* compare_res - the comparison function for sorting by resident set size */
635 compare_res(struct procsinfo **ppi1, struct procsinfo **ppi2)
638 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
639 register struct proc *p1;
640 register struct proc *p2;
641 register int result;
642 register long lresult;
644 p1 = &p_proc[PROCMASK(pi1->pi_pid)];
645 p2 = &p_proc[PROCMASK(pi2->pi_pid)];
647 ORDERKEY_RSSIZE
648 ORDERKEY_MEM
649 ORDERKEY_PCTCPU
650 ORDERKEY_CPTICKS
651 ORDERKEY_STATE
652 ORDERKEY_PRIO
655 return result;
659 /* compare_time - the comparison function for sorting by total cpu time */
662 compare_time(struct procsinfo **ppi1, struct procsinfo **ppi2)
665 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
666 register struct proc *p1;
667 register struct proc *p2;
668 register int result;
669 register long lresult;
671 p1 = &p_proc[PROCMASK(pi1->pi_pid)];
672 p2 = &p_proc[PROCMASK(pi2->pi_pid)];
674 ORDERKEY_CPTICKS
675 ORDERKEY_PCTCPU
676 ORDERKEY_STATE
677 ORDERKEY_PRIO
678 ORDERKEY_MEM
679 ORDERKEY_RSSIZE
682 return result;
686 /* compare_prio - the comparison function for sorting by cpu percentage */
689 compare_prio(struct procsinfo **ppi1, struct procsinfo **ppi2)
692 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
693 register struct proc *p1;
694 register struct proc *p2;
695 register int result;
696 register long lresult;
698 p1 = &p_proc[PROCMASK(pi1->pi_pid)];
699 p2 = &p_proc[PROCMASK(pi2->pi_pid)];
701 ORDERKEY_PRIO
702 ORDERKEY_PCTCPU
703 ORDERKEY_CPTICKS
704 ORDERKEY_STATE
705 ORDERKEY_RSSIZE
706 ORDERKEY_MEM
709 return result;
713 proc_owner(int pid)
716 int uid;
717 register struct procsinfo **prefp = pref;
718 register int cnt = pref_len;
720 while (--cnt >= 0) {
721 if ((*prefp)->pi_pid == pid)
722 return (*prefp)->pi_uid;
723 prefp++;
726 return(-1);