118781Sgibbs/* $NetBSD: m_netbsd.c,v 1.15 2011/04/15 02:05:53 christos Exp $ */ 218781Sgibbs 318781Sgibbs/* 455945Sgibbs * top - a top users display for Unix 518781Sgibbs * 618781Sgibbs * SYNOPSIS: For a NetBSD-1.5 (or later) system 718781Sgibbs * 818781Sgibbs * DESCRIPTION: 918781Sgibbs * Originally written for BSD4.4 system by Christos Zoulas. 1018781Sgibbs * Based on the FreeBSD 2.0 version by Steven Wallace and Wolfram Schneider. 1139217Sgibbs * NetBSD-1.0 port by Arne Helme. Process ordering by Luke Mewburn. 1239217Sgibbs * NetBSD-1.3 port by Luke Mewburn, based on code by Matthew Green. 1318781Sgibbs * NetBSD-1.4/UVM port by matthew green. 1418781Sgibbs * NetBSD-1.5 port by Simon Burge. 1518781Sgibbs * NetBSD-1.6/UBC port by Tomas Svensson. 1618781Sgibbs * - 1718781Sgibbs * This is the machine-dependent module for NetBSD-1.5 and later 1818781Sgibbs * works for: 1918781Sgibbs * NetBSD-1.6ZC 2018781Sgibbs * and should work for: 2118781Sgibbs * NetBSD-2.0 (when released) 2218781Sgibbs * - 2318781Sgibbs * top does not need to be installed setuid or setgid with this module. 2418781Sgibbs * 2518781Sgibbs * LIBS: -lkvm 2618781Sgibbs * 2718781Sgibbs * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR 2818781Sgibbs * 2918781Sgibbs * AUTHORS: Christos Zoulas <christos@ee.cornell.edu> 3018781Sgibbs * Steven Wallace <swallace@freebsd.org> 3150477Speter * Wolfram Schneider <wosch@cs.tu-berlin.de> 3218781Sgibbs * Arne Helme <arne@acm.org> 3318781Sgibbs * Luke Mewburn <lukem@NetBSD.org> 3418781Sgibbs * matthew green <mrg@eterna.com.au> 3518781Sgibbs * Simon Burge <simonb@NetBSD.org> 3618781Sgibbs * Tomas Svensson <ts@unix1.net> 3718781Sgibbs * Andrew Doran <ad@NetBSD.org> 3818781Sgibbs * 3918781Sgibbs * 4018781Sgibbs * $Id: m_netbsd.c,v 1.16 2011/10/08 08:45:37 njoly Exp $ 4118781Sgibbs */ 4218781Sgibbs#include <sys/cdefs.h> 4318781Sgibbs 4418781Sgibbs#ifndef lint 4518781Sgibbs__RCSID("$NetBSD: m_netbsd.c,v 1.15 2011/04/15 02:05:53 christos Exp $"); 4618781Sgibbs#endif 4745846Sgibbs 4818781Sgibbs#include <sys/param.h> 4918781Sgibbs#include <sys/sysctl.h> 5039217Sgibbs#include <sys/sched.h> 5139217Sgibbs#include <sys/swap.h> 5259082Snyan 5359082Snyan#include <uvm/uvm_extern.h> 5459082Snyan 5518781Sgibbs#include <err.h> 5639217Sgibbs#include <errno.h> 5739217Sgibbs#include <kvm.h> 5839217Sgibbs#include <math.h> 5939217Sgibbs#include <nlist.h> 6018781Sgibbs#include <stdio.h> 6139217Sgibbs#include <stdlib.h> 6239217Sgibbs#include <string.h> 6339217Sgibbs#include <unistd.h> 6439217Sgibbs 6539217Sgibbs#include "os.h" 6618781Sgibbs#include "top.h" 6718781Sgibbs#include "machine.h" 6818781Sgibbs#include "utils.h" 6918781Sgibbs#include "display.h" 7039217Sgibbs#include "loadavg.h" 7118781Sgibbs#include "username.h" 7218781Sgibbs 7339217Sgibbsstatic void percentages64(int, int *, u_int64_t *, u_int64_t *, 7439217Sgibbs u_int64_t *); 7539217Sgibbs 7639217Sgibbs/* get_process_info passes back a handle. This is what it looks like: */ 7739217Sgibbs 7839217Sgibbsstruct handle { 7939217Sgibbs struct process_select *sel; 8039217Sgibbs struct kinfo_proc2 **next_proc; /* points to next valid proc pointer */ 8139217Sgibbs int remaining; /* number of pointers remaining */ 8239217Sgibbs}; 8339217Sgibbs 8439217Sgibbs/* define what weighted CPU is. */ 8539217Sgibbs#define weighted_cpu(pfx, pct, pp) ((pp)->pfx ## swtime == 0 ? 0.0 : \ 8639217Sgibbs ((pct) / (1.0 - exp((pp)->pfx ## swtime * logcpu)))) 8739217Sgibbs 8839217Sgibbs/* what we consider to be process size: */ 8939217Sgibbs/* NetBSD introduced p_vm_msize with RLIMIT_AS */ 9039217Sgibbs#ifdef RLIMIT_AS 9139217Sgibbs#define PROCSIZE(pp) \ 9239217Sgibbs ((pp)->p_vm_msize) 9339217Sgibbs#else 9439217Sgibbs#define PROCSIZE(pp) \ 9539217Sgibbs ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize) 9639217Sgibbs#endif 9739217Sgibbs 9839217Sgibbs 9939217Sgibbs/* 10039217Sgibbs * These definitions control the format of the per-process area 10139217Sgibbs */ 10239217Sgibbs 10339217Sgibbsstatic char Proc_header[] = 10439217Sgibbs " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 10539217Sgibbs/* 0123456 -- field to fill in starts at header+6 */ 10639217Sgibbs#define PROC_UNAME_START 6 10739217Sgibbs#define Proc_format \ 10839217Sgibbs "%5d %-8.8s %3d %4d%7s %5s %-8.8s%7s %5.*f%% %5.*f%% %s" 10939217Sgibbs 11039217Sgibbsstatic char Thread_header[] = 11139217Sgibbs " PID LID X PRI STATE TIME WCPU CPU NAME COMMAND"; 11239217Sgibbs/* 0123456 -- field to fill in starts at header+6 */ 11339217Sgibbs#define THREAD_UNAME_START 12 11439217Sgibbs#define Thread_format \ 11539217Sgibbs "%5d %5d %-8.8s %3d %-8.8s%7s %5.2f%% %5.2f%% %-9.9s %s" 11639217Sgibbs 11739217Sgibbs/* 11839217Sgibbs * Process state names for the "STATE" column of the display. 11939217Sgibbs */ 12039217Sgibbs 12139217Sgibbsconst char *state_abbrev[] = { 12239217Sgibbs "", "IDLE", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU" 12339217Sgibbs}; 12439217Sgibbs 12518781Sgibbsstatic kvm_t *kd; 12618781Sgibbs 12718781Sgibbsstatic char *(*userprint)(int); 12845575Seivind 12918781Sgibbs/* these are retrieved from the kernel in _init */ 13018781Sgibbs 13118781Sgibbsstatic double logcpu; 13218781Sgibbsstatic int hz; 13318781Sgibbsstatic int ccpu; 13418781Sgibbs 13518781Sgibbs/* these are for calculating CPU state percentages */ 13618781Sgibbs 13718781Sgibbsstatic int ncpu = 0; 13818781Sgibbsstatic u_int64_t *cp_time; 13918781Sgibbsstatic u_int64_t *cp_old; 14045575Seivindstatic u_int64_t *cp_diff; 14139217Sgibbs 14239217Sgibbs/* these are for detailing the process states */ 14339217Sgibbs 14439217Sgibbsint process_states[8]; 14539217Sgibbsconst char *procstatenames[] = { 14639217Sgibbs "", " idle, ", " runnable, ", " sleeping, ", " stopped, ", 14739217Sgibbs " zombie, ", " dead, ", " on CPU, ", 14839217Sgibbs NULL 14939217Sgibbs}; 15039217Sgibbs 15139217Sgibbs/* these are for detailing the CPU states */ 15239217Sgibbs 15339217Sgibbsint *cpu_states; 15439217Sgibbsconst char *cpustatenames[] = { 15539217Sgibbs "user", "nice", "system", "interrupt", "idle", NULL 15639217Sgibbs}; 15739217Sgibbs 15818781Sgibbs/* these are for detailing the memory statistics */ 15918781Sgibbs 16039217Sgibbslong memory_stats[7]; 16139217Sgibbsconst char *memorynames[] = { 16239217Sgibbs "K Act, ", "K Inact, ", "K Wired, ", "K Exec, ", "K File, ", 16339217Sgibbs "K Free, ", 16439217Sgibbs NULL 16539217Sgibbs}; 16639217Sgibbs 16739217Sgibbslong swap_stats[4]; 16839217Sgibbsconst char *swapnames[] = { 16939217Sgibbs "K Total, ", "K Used, ", "K Free, ", 17039217Sgibbs NULL 17139217Sgibbs}; 17239217Sgibbs 17339217Sgibbs 17439217Sgibbs/* these are names given to allowed sorting orders -- first is default */ 17539217Sgibbsconst char *ordernames[] = { 17639217Sgibbs "cpu", 17739217Sgibbs "pri", 17839217Sgibbs "res", 17939217Sgibbs "size", 18039217Sgibbs "state", 18139217Sgibbs "time", 18239217Sgibbs "pid", 18339217Sgibbs "command", 18439217Sgibbs "username", 18539217Sgibbs NULL 18639217Sgibbs}; 18718781Sgibbs 18818781Sgibbs/* forward definitions for comparison functions */ 18939217Sgibbsstatic int compare_cpu(struct proc **, struct proc **); 19018781Sgibbsstatic int compare_prio(struct proc **, struct proc **); 19139217Sgibbsstatic int compare_res(struct proc **, struct proc **); 19218781Sgibbsstatic int compare_size(struct proc **, struct proc **); 19318781Sgibbsstatic int compare_state(struct proc **, struct proc **); 19439217Sgibbsstatic int compare_time(struct proc **, struct proc **); 19539217Sgibbsstatic int compare_pid(struct proc **, struct proc **); 19639217Sgibbsstatic int compare_command(struct proc **, struct proc **); 19739217Sgibbsstatic int compare_username(struct proc **, struct proc **); 19839217Sgibbs 19939217Sgibbsint (*proc_compares[])(struct proc **, struct proc **) = { 20039217Sgibbs compare_cpu, 20139217Sgibbs compare_prio, 20239217Sgibbs compare_res, 20318781Sgibbs compare_size, 20439217Sgibbs compare_state, 20539217Sgibbs compare_time, 20639217Sgibbs compare_pid, 20718781Sgibbs compare_command, 20818781Sgibbs compare_username, 20939217Sgibbs NULL 21039217Sgibbs}; 21139217Sgibbs 21239217Sgibbsstatic char *format_next_lwp(caddr_t, char *(*)(int)); 21339217Sgibbsstatic char *format_next_proc(caddr_t, char *(*)(int)); 21418781Sgibbs 21518781Sgibbsstatic caddr_t get_proc_info(struct system_info *, struct process_select *, 21639217Sgibbs int (*)(struct proc **, struct proc **)); 21739217Sgibbsstatic caddr_t get_lwp_info(struct system_info *, struct process_select *, 21839217Sgibbs int (*)(struct proc **, struct proc **)); 21939217Sgibbs 22039217Sgibbs/* these are for keeping track of the proc array */ 22139217Sgibbs 22239217Sgibbsstatic int nproc; 22318781Sgibbsstatic int onproc = -1; 22418781Sgibbsstatic int nlwp; 22539217Sgibbsstatic int onlwp = -1; 22639217Sgibbsstatic int pref_len; 22718781Sgibbsstatic int lref_len; 22839217Sgibbsstatic struct kinfo_proc2 *pbase; 22939217Sgibbsstatic struct kinfo_lwp *lbase; 23039217Sgibbsstatic struct kinfo_proc2 **pref; 23139217Sgibbsstatic struct kinfo_lwp **lref; 23239217Sgibbsstatic int maxswap; 23318781Sgibbsstatic void *swapp; 23439217Sgibbsstatic int procgen; 23539217Sgibbsstatic int thread_nproc; 23639217Sgibbsstatic int thread_onproc = -1; 23718781Sgibbsstatic struct kinfo_proc2 *thread_pbase; 23818781Sgibbs 23939217Sgibbs/* these are for getting the memory statistics */ 24039217Sgibbs 24118781Sgibbsstatic int pageshift; /* log base 2 of the pagesize */ 24239217Sgibbs 24318781Sgibbsint threadmode; 24418781Sgibbs 24518781Sgibbs/* define pagetok in terms of pageshift */ 24640027Sgibbs 24740027Sgibbs#define pagetok(size) ((size) << pageshift) 24840027Sgibbs 24940027Sgibbs/* 25040027Sgibbs * Print swapped processes as <pname> and 25140027Sgibbs * system processes as [pname] 25240027Sgibbs */ 25340027Sgibbsstatic const char * 25440027Sgibbsget_pretty(const struct kinfo_proc2 *pp) 25540027Sgibbs{ 25640027Sgibbs if ((pp->p_flag & P_SYSTEM) != 0) 25740027Sgibbs return "[]"; 25840027Sgibbs if ((pp->p_flag & P_INMEM) == 0) 25940027Sgibbs return "<>"; 260111409Sobrien return ""; 261111342Sobrien} 262111342Sobrien 263111409Sobrienstatic const char * 26439217Sgibbsget_command(const struct process_select *sel, struct kinfo_proc2 *pp) 26539217Sgibbs{ 26639217Sgibbs static char cmdbuf[128]; 26739217Sgibbs const char *pretty; 26839217Sgibbs char **argv; 26939217Sgibbs if (pp == NULL) 27039217Sgibbs return "<gone>"; 27139217Sgibbs pretty = get_pretty(pp); 27239217Sgibbs 27339217Sgibbs if (sel->fullcmd == 0 || kd == NULL || (argv = kvm_getargv2(kd, pp, 27439217Sgibbs sizeof(cmdbuf))) == NULL) { 27539217Sgibbs if (pretty[0] != '\0' && pp->p_comm[0] != pretty[0]) 27639217Sgibbs snprintf(cmdbuf, sizeof(cmdbuf), "%c%s%c", pretty[0], 27739217Sgibbs printable(pp->p_comm), pretty[1]); 27839217Sgibbs else 27939217Sgibbs strlcpy(cmdbuf, printable(pp->p_comm), sizeof(cmdbuf)); 28039217Sgibbs } else { 28118781Sgibbs char *d = cmdbuf; 28239217Sgibbs if (pretty[0] != '\0' && argv[0][0] != pretty[0]) 28339217Sgibbs *d++ = pretty[0]; 28439217Sgibbs while (*argv) { 28539217Sgibbs const char *s = printable(*argv++); 28639217Sgibbs while (d < cmdbuf + sizeof(cmdbuf) - 2 && 28739217Sgibbs (*d++ = *s++) != '\0') 28839217Sgibbs continue; 28939217Sgibbs if (d > cmdbuf && d < cmdbuf + sizeof(cmdbuf) - 2 && 29039217Sgibbs d[-1] == '\0') 29118781Sgibbs d[-1] = ' '; 29218781Sgibbs } 29319426Sgibbs if (pretty[0] != '\0' && pretty[0] == cmdbuf[0]) 29418781Sgibbs *d++ = pretty[1]; 29539217Sgibbs *d++ = '\0'; 29639217Sgibbs } 29739217Sgibbs return cmdbuf; 29818781Sgibbs} 29939217Sgibbs 30039217Sgibbsint 30139217Sgibbsmachine_init(statics) 30239217Sgibbs struct statics *statics; 30339217Sgibbs{ 30439217Sgibbs int pagesize; 30539217Sgibbs int mib[2]; 30639217Sgibbs size_t size; 30739217Sgibbs struct clockinfo clockinfo; 30839217Sgibbs struct timeval boottime; 30939217Sgibbs 31039217Sgibbs if ((kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL) 31139217Sgibbs return -1; 31239217Sgibbs 31339217Sgibbs mib[0] = CTL_HW; 31439217Sgibbs mib[1] = HW_NCPU; 31539217Sgibbs size = sizeof(ncpu); 31639217Sgibbs if (sysctl(mib, 2, &ncpu, &size, NULL, 0) == -1) { 31739217Sgibbs fprintf(stderr, "top: sysctl hw.ncpu failed: %s\n", 31839217Sgibbs strerror(errno)); 31939217Sgibbs return(-1); 32039217Sgibbs } 32139217Sgibbs statics->ncpu = ncpu; 32239217Sgibbs cp_time = malloc(sizeof(cp_time[0]) * CPUSTATES * ncpu); 32339217Sgibbs mib[0] = CTL_KERN; 32439217Sgibbs mib[1] = KERN_CP_TIME; 32539217Sgibbs size = sizeof(cp_time[0]) * CPUSTATES * ncpu; 32639217Sgibbs if (sysctl(mib, 2, cp_time, &size, NULL, 0) < 0) { 32739217Sgibbs fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n", 32839217Sgibbs strerror(errno)); 32939217Sgibbs return(-1); 33039217Sgibbs } 33139217Sgibbs 33239217Sgibbs /* Handle old call that returned only aggregate */ 33339217Sgibbs if (size == sizeof(cp_time[0]) * CPUSTATES) 33439217Sgibbs ncpu = 1; 33539217Sgibbs 33639217Sgibbs cpu_states = malloc(sizeof(cpu_states[0]) * CPUSTATES * ncpu); 33739217Sgibbs cp_old = malloc(sizeof(cp_old[0]) * CPUSTATES * ncpu); 33839217Sgibbs cp_diff = malloc(sizeof(cp_diff[0]) * CPUSTATES * ncpu); 33939217Sgibbs if (cpu_states == NULL || cp_time == NULL || cp_old == NULL || 34039217Sgibbs cp_diff == NULL) { 34139217Sgibbs fprintf(stderr, "top: machine_init: %s\n", 34239217Sgibbs strerror(errno)); 34339217Sgibbs return(-1); 34439217Sgibbs } 34539217Sgibbs 34639217Sgibbs mib[0] = CTL_KERN; 34739217Sgibbs mib[1] = KERN_CCPU; 34839217Sgibbs size = sizeof(ccpu); 34939217Sgibbs if (sysctl(mib, 2, &ccpu, &size, NULL, 0) == -1) { 35039217Sgibbs fprintf(stderr, "top: sysctl kern.ccpu failed: %s\n", 35139217Sgibbs strerror(errno)); 35239217Sgibbs return(-1); 35339217Sgibbs } 35439217Sgibbs 35539217Sgibbs mib[0] = CTL_KERN; 35639217Sgibbs mib[1] = KERN_CLOCKRATE; 35739217Sgibbs size = sizeof(clockinfo); 35839217Sgibbs if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1) { 35939217Sgibbs fprintf(stderr, "top: sysctl kern.clockrate failed: %s\n", 36039217Sgibbs strerror(errno)); 36139217Sgibbs return(-1); 36239217Sgibbs } 36339217Sgibbs hz = clockinfo.stathz; 36439217Sgibbs 36539217Sgibbs /* this is used in calculating WCPU -- calculate it ahead of time */ 36639217Sgibbs logcpu = log(loaddouble(ccpu)); 36739217Sgibbs 36839217Sgibbs pbase = NULL; 36939217Sgibbs lbase = NULL; 37039217Sgibbs pref = NULL; 37139217Sgibbs nproc = 0; 37239217Sgibbs onproc = -1; 37339217Sgibbs nlwp = 0; 37439217Sgibbs onlwp = -1; 37539217Sgibbs /* get the page size with "getpagesize" and calculate pageshift from it */ 37639217Sgibbs pagesize = getpagesize(); 37739217Sgibbs pageshift = 0; 37839217Sgibbs while (pagesize > 1) { 37939217Sgibbs pageshift++; 38039217Sgibbs pagesize >>= 1; 38118781Sgibbs } 38239217Sgibbs 38339217Sgibbs /* we only need the amount of log(2)1024 for our conversion */ 38439217Sgibbs pageshift -= LOG1024; 38539217Sgibbs 38639217Sgibbs /* fill in the statics information */ 38739217Sgibbs#ifdef notyet 38839217Sgibbs statics->ncpu = ncpu; 38939217Sgibbs#endif 39039217Sgibbs statics->procstate_names = procstatenames; 39139217Sgibbs statics->cpustate_names = cpustatenames; 39239217Sgibbs statics->memory_names = memorynames; 39339217Sgibbs statics->swap_names = swapnames; 39439217Sgibbs statics->order_names = ordernames; 39539217Sgibbs statics->flags.threads = 1; 39639217Sgibbs statics->flags.fullcmds = 1; 39739217Sgibbs 39839217Sgibbs mib[0] = CTL_KERN; 39939217Sgibbs mib[1] = KERN_BOOTTIME; 40039217Sgibbs size = sizeof(boottime); 40139217Sgibbs if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && 40218781Sgibbs boottime.tv_sec != 0) 40318781Sgibbs statics->boottime = boottime.tv_sec; 40418781Sgibbs else 40518781Sgibbs statics->boottime = 0; 40618781Sgibbs /* all done! */ 40718781Sgibbs return(0); 40818781Sgibbs} 40918781Sgibbs 41018781Sgibbschar * 41118781Sgibbsformat_process_header(struct process_select *sel, caddr_t handle, int count) 41218781Sgibbs 41318781Sgibbs{ 41418781Sgibbs char *header; 41518781Sgibbs char *ptr; 41618781Sgibbs const char *uname_field = sel->usernames ? "USERNAME" : " UID "; 41718781Sgibbs 41818781Sgibbs if (sel->threads) { 41918781Sgibbs header = Thread_header; 42018781Sgibbs ptr = header + THREAD_UNAME_START; 42118781Sgibbs } else { 42218781Sgibbs header = Proc_header; 42318781Sgibbs ptr = header + PROC_UNAME_START; 42418781Sgibbs } 42518781Sgibbs 42618781Sgibbs while (*uname_field != '\0') { 42739217Sgibbs *ptr++ = *uname_field++; 42818781Sgibbs } 42918781Sgibbs 43018781Sgibbs return(header); 43118781Sgibbs} 43218781Sgibbs 43318781Sgibbschar * 43418781Sgibbsformat_header(char *uname_field) 43518781Sgibbs{ 43618781Sgibbs char *header = Proc_header; 43718781Sgibbs char *ptr = header + PROC_UNAME_START; 43818781Sgibbs 43918781Sgibbs while (*uname_field != '\0') { 44018781Sgibbs *ptr++ = *uname_field++; 44118781Sgibbs } 44218781Sgibbs 44318781Sgibbs return(header); 44439217Sgibbs} 44518781Sgibbs 44618781Sgibbsvoid 44718781Sgibbsget_system_info(struct system_info *si) 44818781Sgibbs{ 44918781Sgibbs size_t ssize; 45018781Sgibbs int mib[2]; 45139217Sgibbs struct uvmexp_sysctl uvmexp; 45218781Sgibbs struct swapent *sep; 45318781Sgibbs u_int64_t totalsize, totalinuse; 45418781Sgibbs int size, inuse, ncounted, i; 45518781Sgibbs int rnswap, nswap; 45618781Sgibbs 45718781Sgibbs mib[0] = CTL_KERN; 45839217Sgibbs mib[1] = KERN_CP_TIME; 45939217Sgibbs ssize = sizeof(cp_time[0]) * CPUSTATES * ncpu; 46039217Sgibbs if (sysctl(mib, 2, cp_time, &ssize, NULL, 0) < 0) { 46118781Sgibbs fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n", 46239217Sgibbs strerror(errno)); 46339217Sgibbs quit(23); 46439217Sgibbs } 46539217Sgibbs 46639217Sgibbs if (getloadavg(si->load_avg, NUM_AVERAGES) < 0) { 46739217Sgibbs int j; 46839217Sgibbs 46939217Sgibbs warn("can't getloadavg"); 47039217Sgibbs for (j = 0; j < NUM_AVERAGES; j++) 47139217Sgibbs si->load_avg[j] = 0.0; 47239217Sgibbs } 47339217Sgibbs 47439217Sgibbs /* convert cp_time counts to percentages */ 47539217Sgibbs for (i = 0; i < ncpu; i++) { 47618781Sgibbs int j = i * CPUSTATES; 47739217Sgibbs percentages64(CPUSTATES, cpu_states + j, cp_time + j, cp_old + j, 47818781Sgibbs cp_diff + j); 47939217Sgibbs } 48039217Sgibbs 48139217Sgibbs mib[0] = CTL_VM; 48239217Sgibbs mib[1] = VM_UVMEXP2; 48339217Sgibbs ssize = sizeof(uvmexp); 48439217Sgibbs if (sysctl(mib, 2, &uvmexp, &ssize, NULL, 0) < 0) { 48539217Sgibbs fprintf(stderr, "top: sysctl vm.uvmexp2 failed: %s\n", 48618781Sgibbs strerror(errno)); 48718781Sgibbs quit(23); 48818781Sgibbs } 48939217Sgibbs 49039217Sgibbs /* convert memory stats to Kbytes */ 49118781Sgibbs memory_stats[0] = pagetok(uvmexp.active); 49218781Sgibbs memory_stats[1] = pagetok(uvmexp.inactive); 49318781Sgibbs memory_stats[2] = pagetok(uvmexp.wired); 49418781Sgibbs memory_stats[3] = pagetok(uvmexp.execpages); 49518781Sgibbs memory_stats[4] = pagetok(uvmexp.filepages); 49618781Sgibbs memory_stats[5] = pagetok(uvmexp.free); 49718781Sgibbs 49818781Sgibbs swap_stats[0] = swap_stats[1] = swap_stats[2] = 0; 49918781Sgibbs 50018781Sgibbs do { 50118781Sgibbs nswap = swapctl(SWAP_NSWAP, 0, 0); 50218781Sgibbs if (nswap < 1) 50318781Sgibbs break; 50418781Sgibbs if (nswap > maxswap) { 50518781Sgibbs if (swapp) 50618781Sgibbs free(swapp); 50718781Sgibbs swapp = sep = malloc(nswap * sizeof(*sep)); 50818781Sgibbs if (sep == NULL) 50918781Sgibbs break; 51018781Sgibbs maxswap = nswap; 51118781Sgibbs } else 51218781Sgibbs sep = swapp; 51318781Sgibbs rnswap = swapctl(SWAP_STATS, (void *)sep, nswap); 51418781Sgibbs if (nswap != rnswap) 51518781Sgibbs break; 51618781Sgibbs 51718781Sgibbs totalsize = totalinuse = ncounted = 0; 51818781Sgibbs for (; rnswap-- > 0; sep++) { 51918781Sgibbs ncounted++; 52018781Sgibbs size = sep->se_nblks; 52118781Sgibbs inuse = sep->se_inuse; 52218781Sgibbs totalsize += size; 52318781Sgibbs totalinuse += inuse; 52418781Sgibbs } 52518781Sgibbs swap_stats[0] = dbtob(totalsize) / 1024; 52639217Sgibbs swap_stats[1] = dbtob(totalinuse) / 1024; 52739217Sgibbs swap_stats[2] = dbtob(totalsize) / 1024 - swap_stats[1]; 52818781Sgibbs } while (0); 52918781Sgibbs 53018781Sgibbs memory_stats[6] = -1; 53118781Sgibbs swap_stats[3] = -1; 53218781Sgibbs 53318781Sgibbs /* set arrays and strings */ 53418781Sgibbs si->cpustates = cpu_states; 53518781Sgibbs si->memory = memory_stats; 53618781Sgibbs si->swap = swap_stats; 53718781Sgibbs si->last_pid = -1; 53818781Sgibbs 53918781Sgibbs} 54018781Sgibbs 54118781Sgibbsstatic struct kinfo_proc2 * 54218781Sgibbsproc_from_thread(struct kinfo_lwp *pl) 54318781Sgibbs{ 54455945Sgibbs struct kinfo_proc2 *pp = thread_pbase; 54518781Sgibbs int i; 54618781Sgibbs 54755945Sgibbs for (i = 0; i < thread_nproc; i++, pp++) 54855945Sgibbs if ((pid_t)pp->p_pid == (pid_t)pl->l_pid) 54955945Sgibbs return pp; 55018781Sgibbs return NULL; 55118781Sgibbs} 55218781Sgibbs 55318781Sgibbsstatic int 55455945Sgibbsuid_from_thread(struct kinfo_lwp *pl) 55555945Sgibbs{ 55655945Sgibbs struct kinfo_proc2 *pp; 55718781Sgibbs 55855945Sgibbs if ((pp = proc_from_thread(pl)) == NULL) 55955945Sgibbs return -1; 56055945Sgibbs return pp->p_ruid; 56155945Sgibbs} 56255945Sgibbs 56318781Sgibbscaddr_t 56418781Sgibbsget_process_info(struct system_info *si, struct process_select *sel, int c) 56518781Sgibbs{ 56618781Sgibbs userprint = sel->usernames ? username : itoa7; 56739217Sgibbs 56818781Sgibbs if ((threadmode = sel->threads) != 0) 56918781Sgibbs return get_lwp_info(si, sel, proc_compares[c]); 57018781Sgibbs else 57118781Sgibbs return get_proc_info(si, sel, proc_compares[c]); 57218781Sgibbs} 57318781Sgibbs 57418781Sgibbsstatic caddr_t 57518781Sgibbsget_proc_info(struct system_info *si, struct process_select *sel, 57618781Sgibbs int (*compare)(struct proc **, struct proc **)) 57718781Sgibbs{ 57818781Sgibbs int i; 57918781Sgibbs int total_procs; 58018781Sgibbs int active_procs; 58118781Sgibbs struct kinfo_proc2 **prefp, **n; 58218781Sgibbs struct kinfo_proc2 *pp; 58318781Sgibbs int op, arg; 58418781Sgibbs 58518781Sgibbs /* these are copied out of sel for speed */ 58639217Sgibbs int show_idle; 58718781Sgibbs int show_system; 58818781Sgibbs int show_uid; 58939217Sgibbs int show_command; 59018781Sgibbs 59118781Sgibbs static struct handle handle; 59218781Sgibbs 59318781Sgibbs procgen++; 59439217Sgibbs 59539217Sgibbs if (sel->pid == (pid_t)-1) { 59618781Sgibbs op = KERN_PROC_ALL; 59718781Sgibbs arg = 0; 59818781Sgibbs } else { 59918781Sgibbs op = KERN_PROC_PID; 60018781Sgibbs arg = sel->pid; 60118781Sgibbs } 60218781Sgibbs 60318781Sgibbs pbase = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &nproc); 60418781Sgibbs if (pbase == NULL) { 60518781Sgibbs if (sel->pid != (pid_t)-1) { 60618781Sgibbs nproc = 0; 60718781Sgibbs } else { 60818781Sgibbs (void) fprintf(stderr, "top: Out of memory.\n"); 60918781Sgibbs quit(23); 61039217Sgibbs } 61118781Sgibbs } 61218781Sgibbs if (nproc > onproc) { 61318781Sgibbs n = (struct kinfo_proc2 **) realloc(pref, 61418781Sgibbs sizeof(struct kinfo_proc2 *) * nproc); 61518781Sgibbs if (n == NULL) { 61618781Sgibbs (void) fprintf(stderr, "top: Out of memory.\n"); 61718781Sgibbs quit(23); 61818781Sgibbs } 61918781Sgibbs pref = n; 62018781Sgibbs onproc = nproc; 62118781Sgibbs } 62218781Sgibbs /* get a pointer to the states summary array */ 62318781Sgibbs si->procstates = process_states; 62418781Sgibbs 62518781Sgibbs /* set up flags which define what we are going to select */ 62618781Sgibbs show_idle = sel->idle; 62718781Sgibbs show_system = sel->system; 62818781Sgibbs show_uid = sel->uid != -1; 62918781Sgibbs show_command = sel->command != NULL; 63018781Sgibbs 63118781Sgibbs /* count up process states and get pointers to interesting procs */ 63218781Sgibbs total_procs = 0; 63339217Sgibbs active_procs = 0; 63418781Sgibbs memset((char *)process_states, 0, sizeof(process_states)); 63518781Sgibbs prefp = pref; 63618781Sgibbs for (pp = pbase, i = 0; i < nproc; pp++, i++) { 63718781Sgibbs 63818781Sgibbs /* 63939217Sgibbs * Place pointers to each valid proc structure in pref[]. 64039217Sgibbs * Process slots that are actually in use have a non-zero 64118781Sgibbs * status field. Processes with P_SYSTEM set are system 64218781Sgibbs * processes---these get ignored unless show_sysprocs is set. 64318781Sgibbs */ 64418781Sgibbs if (pp->p_stat != 0 && (show_system || ((pp->p_flag & P_SYSTEM) == 0))) { 64518781Sgibbs total_procs++; 64618781Sgibbs process_states[(unsigned char) pp->p_stat]++; 64718781Sgibbs if (pp->p_stat != LSZOMB && 64818781Sgibbs (show_idle || (pp->p_pctcpu != 0) || 64918781Sgibbs (pp->p_stat == LSRUN || pp->p_stat == LSONPROC)) && 65018781Sgibbs (!show_uid || pp->p_ruid == (uid_t)sel->uid)) { 65118781Sgibbs *prefp++ = pp; 65218781Sgibbs active_procs++; 65318781Sgibbs } 65418781Sgibbs } 65518781Sgibbs } 65618781Sgibbs 65718781Sgibbs /* if requested, sort the "interesting" processes */ 65818781Sgibbs if (compare != NULL) { 65918781Sgibbs qsort((char *)pref, active_procs, sizeof(struct kinfo_proc2 *), 66018781Sgibbs (int (*)(const void *, const void *))compare); 66118781Sgibbs } 66218781Sgibbs 66318781Sgibbs /* remember active and total counts */ 66418781Sgibbs si->p_total = total_procs; 66518781Sgibbs si->p_active = pref_len = active_procs; 66639217Sgibbs 66739217Sgibbs /* pass back a handle */ 66839217Sgibbs handle.next_proc = pref; 66939217Sgibbs handle.remaining = active_procs; 67039217Sgibbs handle.sel = sel; 67139217Sgibbs return((caddr_t)&handle); 67239217Sgibbs} 67339217Sgibbs 67439217Sgibbsstatic caddr_t 67539217Sgibbsget_lwp_info(struct system_info *si, struct process_select *sel, 67639217Sgibbs int (*compare)(struct proc **, struct proc **)) 67739217Sgibbs{ 67839217Sgibbs int i; 67918781Sgibbs int total_lwps; 68039217Sgibbs int active_lwps; 68139217Sgibbs struct kinfo_lwp **lrefp, **n; 68218781Sgibbs struct kinfo_lwp *lp; 68339217Sgibbs struct kinfo_proc2 *pp; 68439217Sgibbs 68539217Sgibbs /* these are copied out of sel for speed */ 68639217Sgibbs int show_idle; 68718781Sgibbs int show_system; 68818781Sgibbs int show_uid; 68918781Sgibbs int show_command; 69018781Sgibbs 69118781Sgibbs static struct handle handle; 69218781Sgibbs 69318781Sgibbs pp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), 69418781Sgibbs &thread_nproc); 69518781Sgibbs if (pp == NULL) { 69618781Sgibbs (void) fprintf(stderr, "top: Out of memory.\n"); 69718781Sgibbs quit(23); 69818781Sgibbs } 69939217Sgibbs if (thread_pbase == NULL || thread_nproc != thread_onproc) { 70018781Sgibbs free(thread_pbase); 70139217Sgibbs thread_onproc = thread_nproc; 70239217Sgibbs thread_pbase = calloc(sizeof(struct kinfo_proc2), thread_nproc); 70339217Sgibbs if (thread_pbase == NULL) { 70439217Sgibbs (void) fprintf(stderr, "top: Out of memory.\n"); 70539217Sgibbs quit(23); 70639217Sgibbs } 70739217Sgibbs } 70839217Sgibbs memcpy(thread_pbase, pp, sizeof(struct kinfo_proc2) * thread_nproc); 70918781Sgibbs 71018781Sgibbs lbase = kvm_getlwps(kd, -1, 0, sizeof(struct kinfo_lwp), &nlwp); 71118781Sgibbs if (lbase == NULL) { 71218781Sgibbs#ifdef notyet 71318781Sgibbs if (sel->pid != (pid_t)-1) { 71418781Sgibbs nproc = 0; 71518781Sgibbs nlwp = 0; 71618781Sgibbs } 71718781Sgibbs else 71818781Sgibbs#endif 71939217Sgibbs { 72039217Sgibbs (void) fprintf(stderr, "top: Out of memory.\n"); 72118781Sgibbs quit(23); 72218781Sgibbs } 72339217Sgibbs } 72439217Sgibbs if (nlwp > onlwp) { 72518781Sgibbs n = (struct kinfo_lwp **) realloc(lref, 72655945Sgibbs sizeof(struct kinfo_lwp *) * nlwp); 72739505Sgibbs if (n == NULL) { 72839505Sgibbs (void) fprintf(stderr, "top: Out of memory.\n"); 72918781Sgibbs quit(23); 73018781Sgibbs } 73118781Sgibbs lref = n; 73218781Sgibbs onlwp = nlwp; 73318781Sgibbs } 73439217Sgibbs /* get a pointer to the states summary array */ 73539217Sgibbs si->procstates = process_states; 73618781Sgibbs 73718781Sgibbs /* set up flags which define what we are going to select */ 73818781Sgibbs show_idle = sel->idle; 73939217Sgibbs show_system = sel->system; 74039217Sgibbs show_uid = sel->uid != -1; 74139217Sgibbs show_command = sel->command != NULL; 74239217Sgibbs 74318781Sgibbs /* count up thread states and get pointers to interesting threads */ 74418781Sgibbs total_lwps = 0; 74518781Sgibbs active_lwps = 0; 74618781Sgibbs memset((char *)process_states, 0, sizeof(process_states)); 74718781Sgibbs lrefp = lref; 74818781Sgibbs for (lp = lbase, i = 0; i < nlwp; lp++, i++) { 74918781Sgibbs if (sel->pid != (pid_t)-1 && sel->pid != (pid_t)lp->l_pid) 75018781Sgibbs continue; 75118781Sgibbs 75239217Sgibbs /* 75339217Sgibbs * Place pointers to each valid lwp structure in lref[]. 75439217Sgibbs * thread slots that are actually in use have a non-zero 75539217Sgibbs * status field. threads with L_SYSTEM set are system 75639217Sgibbs * threads---these get ignored unless show_sysprocs is set. 75739217Sgibbs */ 75839217Sgibbs if (lp->l_stat != 0 && (show_system || ((lp->l_flag & LW_SYSTEM) == 0))) { 75939217Sgibbs total_lwps++; 76039217Sgibbs process_states[(unsigned char) lp->l_stat]++; 76139217Sgibbs if (lp->l_stat != LSZOMB && 76239217Sgibbs (show_idle || (lp->l_pctcpu != 0) || 76339217Sgibbs (lp->l_stat == LSRUN || lp->l_stat == LSONPROC)) && 76439217Sgibbs (!show_uid || uid_from_thread(lp) == sel->uid)) { 76539217Sgibbs *lrefp++ = lp; 76639217Sgibbs active_lwps++; 76739217Sgibbs } 76839217Sgibbs } 76939217Sgibbs } 77018781Sgibbs 77118781Sgibbs /* if requested, sort the "interesting" threads */ 77218781Sgibbs if (compare != NULL) { 77318781Sgibbs qsort((char *)lref, active_lwps, sizeof(struct kinfo_lwp *), 77439217Sgibbs (int (*)(const void *, const void *))compare); 77539217Sgibbs } 77639217Sgibbs 77739217Sgibbs /* remember active and total counts */ 77839217Sgibbs si->p_total = total_lwps; 77939217Sgibbs si->p_active = lref_len = active_lwps; 78039217Sgibbs 78139217Sgibbs /* pass back a handle */ 78239217Sgibbs handle.next_proc = (struct kinfo_proc2 **)lref; 78339217Sgibbs handle.remaining = active_lwps; 78439217Sgibbs handle.sel = sel; 78539217Sgibbs 78639217Sgibbs return((caddr_t)&handle); 78739217Sgibbs} 78839217Sgibbs 78939217Sgibbschar * 79039217Sgibbsformat_next_process(caddr_t handle, char *(*get_userid)(int)) 79139217Sgibbs{ 79239217Sgibbs 79339217Sgibbs if (threadmode) 79439217Sgibbs return format_next_lwp(handle, get_userid); 79539217Sgibbs else 79639217Sgibbs return format_next_proc(handle, get_userid); 79718781Sgibbs} 79839217Sgibbs 79918781Sgibbs 80018781Sgibbschar * 80118781Sgibbsformat_next_proc(caddr_t handle, char *(*get_userid)(int)) 80218781Sgibbs{ 80318781Sgibbs struct kinfo_proc2 *pp; 80418781Sgibbs long cputime; 80518781Sgibbs double pct, wcpu, cpu; 80639217Sgibbs struct handle *hp; 80739217Sgibbs const char *statep; 80818781Sgibbs#ifdef KI_NOCPU 80939217Sgibbs char state[10]; 81039217Sgibbs#endif 81118781Sgibbs char wmesg[KI_WMESGLEN + 1]; 81218781Sgibbs static char fmt[MAX_COLS]; /* static area where result is built */ 81318781Sgibbs 81418781Sgibbs /* find and remember the next proc structure */ 81518781Sgibbs hp = (struct handle *)handle; 81618781Sgibbs pp = *(hp->next_proc++); 81718781Sgibbs hp->remaining--; 81818781Sgibbs 81918781Sgibbs /* get the process's user struct and set cputime */ 82018781Sgibbs 82118781Sgibbs#if 0 82218781Sgibbs /* This does not produce the correct results */ 82318781Sgibbs cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks; 82418781Sgibbs#else 82518781Sgibbs cputime = pp->p_rtime_sec; /* This does not count interrupts */ 82618781Sgibbs#endif 82718781Sgibbs 82818781Sgibbs /* calculate the base for CPU percentages */ 82918781Sgibbs pct = pctdouble(pp->p_pctcpu); 83039217Sgibbs 83118781Sgibbs if (pp->p_stat == LSSLEEP) { 83240133Sgibbs strlcpy(wmesg, pp->p_wmesg, sizeof(wmesg)); 83355945Sgibbs statep = wmesg; 83455945Sgibbs } else 83540133Sgibbs statep = state_abbrev[(unsigned)pp->p_stat]; 83639217Sgibbs 83740133Sgibbs#ifdef KI_NOCPU 83855945Sgibbs /* Post-1.5 change: add CPU number if appropriate */ 83955945Sgibbs if (pp->p_cpuid != KI_NOCPU && ncpu > 1) { 84055945Sgibbs switch (pp->p_stat) { 84118781Sgibbs case LSONPROC: 84218781Sgibbs case LSRUN: 84318781Sgibbs case LSSLEEP: 84418781Sgibbs case LSIDL: 84518781Sgibbs (void)snprintf(state, sizeof(state), "%.6s/%u", 84618781Sgibbs statep, (unsigned int)pp->p_cpuid); 84718781Sgibbs statep = state; 84818781Sgibbs break; 84918781Sgibbs } 85018781Sgibbs } 85139217Sgibbs#endif 85218781Sgibbs wcpu = 100.0 * weighted_cpu(p_, pct, pp); 85339217Sgibbs cpu = 100.0 * pct; 85439217Sgibbs 85539217Sgibbs /* format this entry */ 85639217Sgibbs sprintf(fmt, 85739217Sgibbs Proc_format, 85839217Sgibbs pp->p_pid, 85939217Sgibbs (*userprint)(pp->p_ruid), 86039217Sgibbs pp->p_priority, 86139217Sgibbs pp->p_nice - NZERO, 86218781Sgibbs format_k(pagetok(PROCSIZE(pp))), 86318781Sgibbs format_k(pagetok(pp->p_vm_rssize)), 86418781Sgibbs statep, 86518781Sgibbs format_time(cputime), 86618781Sgibbs (wcpu >= 100.0) ? 0 : 2, wcpu, 86718781Sgibbs (cpu >= 100.0) ? 0 : 2, cpu, 86818781Sgibbs get_command(hp->sel, pp)); 86918781Sgibbs 87018781Sgibbs /* return the result */ 87118781Sgibbs return(fmt); 87218781Sgibbs} 87318781Sgibbs 87418781Sgibbsstatic char * 87518781Sgibbsformat_next_lwp(caddr_t handle, char *(*get_userid)(int)) 87618781Sgibbs{ 87718781Sgibbs struct kinfo_proc2 *pp; 87818781Sgibbs struct kinfo_lwp *pl; 87918781Sgibbs long cputime; 88039217Sgibbs double pct; 88118781Sgibbs struct handle *hp; 88218781Sgibbs const char *statep; 88318781Sgibbs#ifdef KI_NOCPU 88418781Sgibbs char state[10]; 88518781Sgibbs#endif 88618781Sgibbs char wmesg[KI_WMESGLEN + 1]; 88718781Sgibbs static char fmt[MAX_COLS]; /* static area where result is built */ 88818781Sgibbs int uid; 88918781Sgibbs 89018781Sgibbs /* find and remember the next proc structure */ 89118781Sgibbs hp = (struct handle *)handle; 89218781Sgibbs pl = (struct kinfo_lwp *)*(hp->next_proc++); 89318781Sgibbs hp->remaining--; 89418781Sgibbs pp = proc_from_thread(pl); 89539217Sgibbs 89618781Sgibbs /* get the process's user struct and set cputime */ 89718781Sgibbs uid = pp ? pp->p_ruid : 0; 89818781Sgibbs 89918781Sgibbs cputime = pl->l_rtime_sec; 90018781Sgibbs 90118781Sgibbs /* calculate the base for CPU percentages */ 90218781Sgibbs pct = pctdouble(pl->l_pctcpu); 90318781Sgibbs 90418781Sgibbs if (pl->l_stat == LSSLEEP) { 90518781Sgibbs strlcpy(wmesg, pl->l_wmesg, sizeof(wmesg)); 90618781Sgibbs statep = wmesg; 90718781Sgibbs } else 90818781Sgibbs statep = state_abbrev[(unsigned)pl->l_stat]; 90918781Sgibbs 91018781Sgibbs#ifdef KI_NOCPU 91118781Sgibbs /* Post-1.5 change: add CPU number if appropriate */ 91218781Sgibbs if (pl->l_cpuid != KI_NOCPU && ncpu > 1) { 91318781Sgibbs switch (pl->l_stat) { 91418781Sgibbs case LSONPROC: 91518781Sgibbs case LSRUN: 91618781Sgibbs case LSSLEEP: 91718781Sgibbs case LSIDL: 91818781Sgibbs (void)snprintf(state, sizeof(state), "%.6s/%u", 91918781Sgibbs statep, (unsigned int)pl->l_cpuid); 92018781Sgibbs statep = state; 92118781Sgibbs break; 92218781Sgibbs } 92318781Sgibbs } 92418781Sgibbs#endif 92518781Sgibbs 92618781Sgibbs if (pl->l_name[0] == '\0') { 92718781Sgibbs pl->l_name[0] = '-'; 92818781Sgibbs pl->l_name[1] = '\0'; 92918781Sgibbs } 93039217Sgibbs 93118781Sgibbs /* format this entry */ 93218781Sgibbs sprintf(fmt, 93339217Sgibbs Thread_format, 93439217Sgibbs pl->l_pid, 93539217Sgibbs pl->l_lid, 93618781Sgibbs (*userprint)(uid), 93718781Sgibbs pl->l_priority, 93818781Sgibbs statep, 93918781Sgibbs format_time(cputime), 94018781Sgibbs 100.0 * weighted_cpu(l_, pct, pl), 94118781Sgibbs 100.0 * pct, 94218781Sgibbs printable(pl->l_name), 94318781Sgibbs get_command(hp->sel, pp)); 94418781Sgibbs 94518781Sgibbs /* return the result */ 94618781Sgibbs return(fmt); 94739217Sgibbs} 94839217Sgibbs 94918781Sgibbs/* comparison routines for qsort */ 95039217Sgibbs 95139217Sgibbs/* 95239217Sgibbs * There are currently four possible comparison routines. main selects 95339217Sgibbs * one of these by indexing in to the array proc_compares. 95418781Sgibbs * 95539217Sgibbs * Possible keys are defined as macros below. Currently these keys are 95639217Sgibbs * defined: percent CPU, CPU ticks, process state, resident set size, 95739217Sgibbs * total virtual memory usage. The process states are ordered as follows 95839217Sgibbs * (from least to most important): WAIT, zombie, sleep, stop, start, run. 95939217Sgibbs * The array declaration below maps a process state index into a number 96039217Sgibbs * that reflects this ordering. 96139217Sgibbs */ 96239217Sgibbs 96339217Sgibbs/* 96439217Sgibbs * First, the possible comparison keys. These are defined in such a way 96539217Sgibbs * that they can be merely listed in the source code to define the actual 96639217Sgibbs * desired ordering. 96718781Sgibbs */ 96855945Sgibbs 96955945Sgibbs#define ORDERKEY_PCTCPU(pfx) \ 97055945Sgibbs if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\ 97155945Sgibbs (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 97255945Sgibbs 97318781Sgibbs#define ORDERKEY_CPTICKS(pfx) \ 97439217Sgibbs if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \ 97518781Sgibbs - (pctcpu)(p1)->pfx ## rtime_sec,\ 97618781Sgibbs (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 97739217Sgibbs 97839217Sgibbs#define ORDERKEY_STATE(pfx) \ 97939217Sgibbs if ((result = sorted_state[(int)(p2)->pfx ## stat] - \ 98039217Sgibbs sorted_state[(int)(p1)->pfx ## stat] ) == 0) 98139217Sgibbs 98239217Sgibbs#define ORDERKEY_PRIO(pfx) \ 98339217Sgibbs if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0) 98418781Sgibbs 98518781Sgibbs#define ORDERKEY_RSSIZE \ 98618781Sgibbs if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0) 98718781Sgibbs 98818781Sgibbs#define ORDERKEY_MEM \ 98939217Sgibbs if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0) 99039217Sgibbs#define ORDERKEY_SIZE(v1, v2) \ 99139217Sgibbs if ((result = (v2 - v1)) == 0) 99239217Sgibbs 99318781Sgibbs/* 99439217Sgibbs * Now the array that maps process state to a weight. 99539217Sgibbs * The order of the elements should match those in state_abbrev[] 99639217Sgibbs */ 99739217Sgibbs 99839217Sgibbsstatic int sorted_state[] = { 99939217Sgibbs 0, /* (not used) ? */ 100039217Sgibbs 1, /* "start" SIDL */ 100139217Sgibbs 4, /* "run" SRUN */ 100239217Sgibbs 3, /* "sleep" SSLEEP */ 100318781Sgibbs 3, /* "stop" SSTOP */ 100439217Sgibbs 2, /* "dead" SDEAD */ 100539217Sgibbs 1, /* "zomb" SZOMB */ 100639217Sgibbs 5, /* "onproc" SONPROC */ 100739217Sgibbs}; 100839217Sgibbs 100955945Sgibbs/* compare_cpu - the comparison function for sorting by CPU percentage */ 101055945Sgibbs 101155945Sgibbsstatic int 101239217Sgibbscompare_cpu(pp1, pp2) 101339217Sgibbs struct proc **pp1, **pp2; 101439217Sgibbs{ 101539217Sgibbs int result; 101639217Sgibbs pctcpu lresult; 101718781Sgibbs 101839217Sgibbs if (threadmode) { 101918781Sgibbs struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 102045846Sgibbs struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 102145846Sgibbs 102245846Sgibbs ORDERKEY_PCTCPU(l_) 102345846Sgibbs ORDERKEY_CPTICKS(l_) 102445846Sgibbs ORDERKEY_STATE(l_) 102545846Sgibbs ORDERKEY_PRIO(l_) 102645846Sgibbs return result; 102718781Sgibbs } else { 102839217Sgibbs struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 102918781Sgibbs struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 103018781Sgibbs 103118781Sgibbs ORDERKEY_PCTCPU(p_) 103218781Sgibbs ORDERKEY_CPTICKS(p_) 103318781Sgibbs ORDERKEY_STATE(p_) 103439217Sgibbs ORDERKEY_PRIO(p_) 103539217Sgibbs ORDERKEY_RSSIZE 103639217Sgibbs ORDERKEY_MEM 103718781Sgibbs return result; 103839217Sgibbs } 103939217Sgibbs 104039217Sgibbs return (result); 104139217Sgibbs} 104218781Sgibbs 104318781Sgibbs/* compare_prio - the comparison function for sorting by process priority */ 104418781Sgibbs 104518781Sgibbsstatic int 104639217Sgibbscompare_prio(pp1, pp2) 104739217Sgibbs struct proc **pp1, **pp2; 104855945Sgibbs{ 104939217Sgibbs int result; 105039217Sgibbs pctcpu lresult; 105139217Sgibbs 105255945Sgibbs if (threadmode) { 105355945Sgibbs struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 105455945Sgibbs struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 105539217Sgibbs 105640733Sgibbs ORDERKEY_PRIO(l_) 105740733Sgibbs ORDERKEY_PCTCPU(l_) 105839217Sgibbs ORDERKEY_CPTICKS(l_) 105939217Sgibbs ORDERKEY_STATE(l_) 106039217Sgibbs return result; 106139217Sgibbs } else { 106239217Sgibbs struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 106339217Sgibbs struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 106455945Sgibbs 106555945Sgibbs ORDERKEY_PRIO(p_) 106639217Sgibbs ORDERKEY_PCTCPU(p_) 106739217Sgibbs ORDERKEY_CPTICKS(p_) 106839217Sgibbs ORDERKEY_STATE(p_) 106918781Sgibbs ORDERKEY_RSSIZE 107039217Sgibbs ORDERKEY_MEM 107139217Sgibbs return result; 107239217Sgibbs } 107339217Sgibbs 107439217Sgibbs return (result); 107539217Sgibbs} 107639217Sgibbs 107739217Sgibbs/* compare_res - the comparison function for sorting by resident set size */ 107839217Sgibbs 107939217Sgibbsstatic int 108039217Sgibbscompare_res(pp1, pp2) 108139217Sgibbs struct proc **pp1, **pp2; 108239217Sgibbs{ 108339217Sgibbs int result; 108439217Sgibbs pctcpu lresult; 108539217Sgibbs 108639217Sgibbs if (threadmode) { 108739217Sgibbs struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 108839217Sgibbs struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 108939217Sgibbs 109039217Sgibbs ORDERKEY_PCTCPU(l_) 109139217Sgibbs ORDERKEY_CPTICKS(l_) 109239217Sgibbs ORDERKEY_STATE(l_) 109339217Sgibbs ORDERKEY_PRIO(l_) 109439217Sgibbs return result; 109539217Sgibbs } else { 109639217Sgibbs struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 109739217Sgibbs struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 109839217Sgibbs 109939217Sgibbs ORDERKEY_RSSIZE 110039217Sgibbs ORDERKEY_MEM 110139217Sgibbs ORDERKEY_PCTCPU(p_) 110239217Sgibbs ORDERKEY_CPTICKS(p_) 110339217Sgibbs ORDERKEY_STATE(p_) 110439217Sgibbs ORDERKEY_PRIO(p_) 110539217Sgibbs return result; 110639217Sgibbs } 110739217Sgibbs 110839217Sgibbs return (result); 110939217Sgibbs} 111039217Sgibbs 111139217Sgibbsstatic int 111239217Sgibbscompare_pid(pp1, pp2) 111339217Sgibbs struct proc **pp1, **pp2; 111439217Sgibbs{ 111539217Sgibbs if (threadmode) { 111639217Sgibbs struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1; 111718781Sgibbs struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2; 111839217Sgibbs struct kinfo_proc2 *p1 = proc_from_thread(l1); 111939217Sgibbs struct kinfo_proc2 *p2 = proc_from_thread(l2); 112018781Sgibbs return p2->p_pid - p1->p_pid; 112139217Sgibbs } else { 112239217Sgibbs struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 112318781Sgibbs struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 112439217Sgibbs return p2->p_pid - p1->p_pid; 112539217Sgibbs } 112639217Sgibbs} 112718781Sgibbs 112839217Sgibbsstatic int 112939217Sgibbscompare_command(pp1, pp2) 113039217Sgibbs struct proc **pp1, **pp2; 113139217Sgibbs{ 113239217Sgibbs if (threadmode) { 113339217Sgibbs struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1; 113439217Sgibbs struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2; 113539217Sgibbs struct kinfo_proc2 *p1 = proc_from_thread(l1); 113639217Sgibbs struct kinfo_proc2 *p2 = proc_from_thread(l2); 113739217Sgibbs return strcmp(p2->p_comm, p1->p_comm); 113839217Sgibbs } else { 113939217Sgibbs struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 114039217Sgibbs struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 114139217Sgibbs return strcmp(p2->p_comm, p1->p_comm); 114239217Sgibbs } 114339217Sgibbs} 114439217Sgibbs 114539217Sgibbsstatic int 114639217Sgibbscompare_username(pp1, pp2) 114739217Sgibbs struct proc **pp1, **pp2; 114839217Sgibbs{ 114939217Sgibbs if (threadmode) { 115039217Sgibbs struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1; 115139217Sgibbs struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2; 115239217Sgibbs struct kinfo_proc2 *p1 = proc_from_thread(l1); 115339217Sgibbs struct kinfo_proc2 *p2 = proc_from_thread(l2); 115439217Sgibbs return strcmp(p2->p_login, p1->p_login); 115539217Sgibbs } else { 115639217Sgibbs struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 115739217Sgibbs struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 115839217Sgibbs return strcmp(p2->p_login, p1->p_login); 115939217Sgibbs } 116039217Sgibbs} 116139217Sgibbs/* compare_size - the comparison function for sorting by total memory usage */ 116239217Sgibbs 116339217Sgibbsstatic int 116439217Sgibbscompare_size(pp1, pp2) 116539217Sgibbs struct proc **pp1, **pp2; 116639217Sgibbs{ 116739217Sgibbs int result; 116839217Sgibbs pctcpu lresult; 116939217Sgibbs 117039217Sgibbs if (threadmode) { 117139217Sgibbs struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 117239217Sgibbs struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 117339217Sgibbs 117439217Sgibbs ORDERKEY_PCTCPU(l_) 117539217Sgibbs ORDERKEY_CPTICKS(l_) 117639217Sgibbs ORDERKEY_STATE(l_) 117739217Sgibbs ORDERKEY_PRIO(l_) 117839217Sgibbs return result; 117939217Sgibbs } else { 118039217Sgibbs struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 118139217Sgibbs struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 118239217Sgibbs 118339217Sgibbs ORDERKEY_MEM 118439217Sgibbs ORDERKEY_RSSIZE 118539217Sgibbs ORDERKEY_PCTCPU(p_) 118639217Sgibbs ORDERKEY_CPTICKS(p_) 118739217Sgibbs ORDERKEY_STATE(p_) 118839217Sgibbs ORDERKEY_PRIO(p_) 118939217Sgibbs return result; 119039217Sgibbs } 119139217Sgibbs 119239217Sgibbs return (result); 119339217Sgibbs} 119439217Sgibbs 119518781Sgibbs/* compare_state - the comparison function for sorting by process state */ 119618781Sgibbs 119718781Sgibbsstatic int 119839217Sgibbscompare_state(pp1, pp2) 119939217Sgibbs struct proc **pp1, **pp2; 120039217Sgibbs{ 120139217Sgibbs int result; 120239217Sgibbs pctcpu lresult; 120339217Sgibbs 120439217Sgibbs if (threadmode) { 120518781Sgibbs struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 120618781Sgibbs struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 120718781Sgibbs 120818781Sgibbs ORDERKEY_STATE(l_) 120918781Sgibbs ORDERKEY_PCTCPU(l_) 121039217Sgibbs ORDERKEY_CPTICKS(l_) 121139217Sgibbs ORDERKEY_PRIO(l_) 121218781Sgibbs return result; 121318781Sgibbs } else { 121418781Sgibbs struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 121518781Sgibbs struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 121618781Sgibbs 121718781Sgibbs ORDERKEY_STATE(p_) 121839217Sgibbs ORDERKEY_PCTCPU(p_) 121939217Sgibbs ORDERKEY_CPTICKS(p_) 122018781Sgibbs ORDERKEY_PRIO(p_) 122118781Sgibbs ORDERKEY_RSSIZE 122218781Sgibbs ORDERKEY_MEM 122318781Sgibbs return result; 122418781Sgibbs } 122518781Sgibbs 122639217Sgibbs return (result); 122739217Sgibbs} 122818781Sgibbs 122918781Sgibbs/* compare_time - the comparison function for sorting by total CPU time */ 123039217Sgibbs 123139217Sgibbsstatic int 123218781Sgibbscompare_time(pp1, pp2) 123318781Sgibbs struct proc **pp1, **pp2; 123418781Sgibbs{ 123539217Sgibbs int result; 123618781Sgibbs pctcpu lresult; 123718781Sgibbs 123818781Sgibbs if (threadmode) { 123918781Sgibbs struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 124018781Sgibbs struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 124139217Sgibbs 124239217Sgibbs ORDERKEY_CPTICKS(l_) 124339217Sgibbs ORDERKEY_PCTCPU(l_) 124418781Sgibbs ORDERKEY_STATE(l_) 124518781Sgibbs ORDERKEY_PRIO(l_) 124618781Sgibbs return result; 124718781Sgibbs } else { 124839217Sgibbs struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 124939217Sgibbs struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 125018781Sgibbs 125118781Sgibbs ORDERKEY_CPTICKS(p_) 125218781Sgibbs ORDERKEY_PCTCPU(p_) 125318781Sgibbs ORDERKEY_STATE(p_) 125418781Sgibbs ORDERKEY_PRIO(p_) 125518781Sgibbs ORDERKEY_MEM 125639217Sgibbs ORDERKEY_RSSIZE 125718781Sgibbs return result; 125818781Sgibbs } 125918781Sgibbs 126018781Sgibbs return (result); 126118781Sgibbs} 126218781Sgibbs 126318781Sgibbs 126439217Sgibbs/* 126518781Sgibbs * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 126618781Sgibbs * the process does not exist. 126718781Sgibbs * It is EXTREMLY IMPORTANT that this function work correctly. 126818781Sgibbs * If top runs setuid root (as in SVR4), then this function 126918781Sgibbs * is the only thing that stands in the way of a serious 127018781Sgibbs * security problem. It validates requests for the "kill" 127118781Sgibbs * and "renice" commands. 127218781Sgibbs */ 127318781Sgibbs 127418781Sgibbsint 127518781Sgibbsproc_owner(pid) 127618781Sgibbs int pid; 127718781Sgibbs{ 127818781Sgibbs int cnt; 127918781Sgibbs struct kinfo_proc2 **prefp; 128018781Sgibbs struct kinfo_proc2 *pp; 128118781Sgibbs 128239217Sgibbs if (threadmode) 128318781Sgibbs return(-1); 128418781Sgibbs 128518781Sgibbs prefp = pref; 128618781Sgibbs cnt = pref_len; 128718781Sgibbs while (--cnt >= 0) { 128818781Sgibbs pp = *prefp++; 128918781Sgibbs if (pp->p_pid == (pid_t)pid) 129018781Sgibbs return(pp->p_ruid); 129118781Sgibbs } 129218781Sgibbs return(-1); 129318781Sgibbs} 129418781Sgibbs 129518781Sgibbs/* 129639217Sgibbs * percentages(cnt, out, new, old, diffs) - calculate percentage change 129739217Sgibbs * between array "old" and "new", putting the percentages i "out". 129818781Sgibbs * "cnt" is size of each array and "diffs" is used for scratch space. 129918781Sgibbs * The array "old" is updated on each call. 130039217Sgibbs * The routine assumes modulo arithmetic. This function is especially 130118781Sgibbs * useful on BSD mchines for calculating CPU state percentages. 130218781Sgibbs */ 130318781Sgibbs 130439217Sgibbsstatic void 130518781Sgibbspercentages64(cnt, out, new, old, diffs) 130618781Sgibbs int cnt; 130718781Sgibbs int *out; 130818781Sgibbs u_int64_t *new; 130918781Sgibbs u_int64_t *old; 131018781Sgibbs u_int64_t *diffs; 131118781Sgibbs{ 131218781Sgibbs int i; 131318781Sgibbs u_int64_t change; 131418781Sgibbs u_int64_t total_change; 131518781Sgibbs u_int64_t *dp; 131618781Sgibbs u_int64_t half_total; 131718781Sgibbs 131818781Sgibbs /* initialization */ 131918781Sgibbs total_change = 0; 132039217Sgibbs dp = diffs; 132118781Sgibbs 132218781Sgibbs /* calculate changes for each state and the overall change */ 132318781Sgibbs for (i = 0; i < cnt; i++) { 132418781Sgibbs /* 132518781Sgibbs * Don't worry about wrapping - even at hz=1GHz, a 132618781Sgibbs * u_int64_t will last at least 544 years. 132718781Sgibbs */ 132818781Sgibbs change = *new - *old; 132918781Sgibbs total_change += (*dp++ = change); 133018781Sgibbs *old++ = *new++; 133118781Sgibbs } 133218781Sgibbs 133318781Sgibbs /* avoid divide by zero potential */ 133418781Sgibbs if (total_change == 0) 133518781Sgibbs total_change = 1; 133618781Sgibbs 133718781Sgibbs /* calculate percentages based on overall change, rounding up */ 133818781Sgibbs half_total = total_change / 2; 133918781Sgibbs for (i = 0; i < cnt; i++) 134018781Sgibbs *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); 134118781Sgibbs} 134218781Sgibbs