machine.c revision 74524
190285Sobrien/* 290285Sobrien * top - a top users display for Unix 390285Sobrien * 418334Speter * SYNOPSIS: For FreeBSD-2.x and later 518334Speter * 618334Speter * DESCRIPTION: 718334Speter * Originally written for BSD4.4 system by Christos Zoulas. 818334Speter * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider 918334Speter * Order support hacked in from top-3.5beta6/machine/m_aix41.c 1018334Speter * by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/) 1118334Speter * 1218334Speter * This is the machine-dependent module for FreeBSD 2.2 1318334Speter * Works for: 1418334Speter * FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x 1518334Speter * 1618334Speter * LIBS: -lkvm 1718334Speter * 1818334Speter * AUTHOR: Christos Zoulas <christos@ee.cornell.edu> 1918334Speter * Steven Wallace <swallace@freebsd.org> 2090285Sobrien * Wolfram Schneider <wosch@FreeBSD.org> 2118334Speter * Thomas Moestl <tmoestl@gmx.net> 2218334Speter * 2318334Speter * $FreeBSD: head/usr.bin/top/machine.c 74524 2001-03-20 16:02:16Z tmm $ 2418334Speter */ 2518334Speter 2618334Speter 2718334Speter#include <sys/time.h> 2818334Speter#include <sys/types.h> 2918334Speter#include <sys/signal.h> 3018334Speter#include <sys/param.h> 3118334Speter 3218334Speter#include "os.h" 3390285Sobrien#include <stdio.h> 3490285Sobrien#include <nlist.h> 3590285Sobrien#include <math.h> 3618334Speter#include <kvm.h> 3790285Sobrien#include <pwd.h> 3852295Sobrien#include <sys/errno.h> 3952295Sobrien#include <sys/sysctl.h> 4018334Speter#include <sys/dkstat.h> 4118334Speter#include <sys/file.h> 4218334Speter#include <sys/time.h> 4318334Speter#include <sys/proc.h> 4418334Speter#include <sys/user.h> 4518334Speter#include <sys/vmmeter.h> 4618334Speter#include <sys/resource.h> 4718334Speter#include <sys/rtprio.h> 4818334Speter 4990285Sobrien/* Swap */ 5018334Speter#include <stdlib.h> 5190285Sobrien#include <sys/conf.h> 5218334Speter 5318334Speter#include <unistd.h> 5418334Speter#include <osreldate.h> /* for changes in kernel structures */ 5550654Sobrien 5650654Sobrien#include "top.h" 5750654Sobrien#include "machine.h" 5890285Sobrien#include "screen.h" 5990285Sobrien#include "utils.h" 6090285Sobrien 6190285Sobrienstatic void getsysctl __P((char *, void *, size_t)); 6290285Sobrien 6390285Sobrien#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) 6490285Sobrien 6590285Sobrienextern char* printable __P((char *)); 6690285Sobrienint swapmode __P((int *retavail, int *retfree)); 6790285Sobrienstatic int smpmode; 6890285Sobrienstatic int namelength; 6990285Sobrienstatic int cmdlengthdelta; 7090285Sobrien 7190285Sobrien/* Prototypes for top internals */ 7290285Sobrienvoid quit __P((int)); 7390285Sobrien 7490285Sobrien/* get_process_info passes back a handle. This is what it looks like: */ 7590285Sobrien 7690285Sobrienstruct handle 7790285Sobrien{ 7890285Sobrien struct kinfo_proc **next_proc; /* points to next valid proc pointer */ 7990285Sobrien int remaining; /* number of pointers remaining */ 8090285Sobrien}; 8190285Sobrien 8290285Sobrien/* declarations for load_avg */ 8390285Sobrien#include "loadavg.h" 8490285Sobrien 8590285Sobrien/* define what weighted cpu is. */ 8690285Sobrien#define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \ 8790285Sobrien ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu)))) 8890285Sobrien 8990285Sobrien/* what we consider to be process size: */ 9090285Sobrien#define PROCSIZE(pp) ((pp)->ki_size / 1024) 9190285Sobrien 9290285Sobrien/* definitions for indices in the nlist array */ 9390285Sobrien 9490285Sobrien/* 9590285Sobrien * These definitions control the format of the per-process area 9650654Sobrien */ 9750654Sobrien 9890285Sobrienstatic char smp_header[] = 9950654Sobrien " PID %-*.*s PRI NICE SIZE RES STATE C TIME WCPU CPU COMMAND"; 10018334Speter 10118334Speter#define smp_Proc_format \ 10218334Speter "%5d %-*.*s %3d %4d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %.*s" 10318334Speter 10418334Speterstatic char up_header[] = 10518334Speter " PID %-*.*s PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 10618334Speter 10790285Sobrien#define up_Proc_format \ 10818334Speter "%5d %-*.*s %3d %4d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s" 10918334Speter 11018334Speter 11118334Speter 11218334Speter/* process state names for the "STATE" column of the display */ 11390285Sobrien/* the extra nulls in the string "run" are for adding a slash and 11490285Sobrien the processor number when needed */ 11590285Sobrien 11690285Sobrienchar *state_abbrev[] = 11790285Sobrien{ 11890285Sobrien "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "MUTEX" 11990285Sobrien}; 12090285Sobrien 12190285Sobrien 12290285Sobrienstatic kvm_t *kd; 12390285Sobrien 12490285Sobrien/* values that we stash away in _init and use in later routines */ 12590285Sobrien 12690285Sobrienstatic double logcpu; 12790285Sobrien 12890285Sobrien/* these are retrieved from the kernel in _init */ 12990285Sobrien 13090285Sobrienstatic load_avg ccpu; 13190285Sobrien 13290285Sobrien/* these are used in the get_ functions */ 13390285Sobrien 13490285Sobrienstatic int lastpid; 13590285Sobrien 13690285Sobrien/* these are for calculating cpu state percentages */ 13790285Sobrien 13890285Sobrienstatic long cp_time[CPUSTATES]; 13990285Sobrienstatic long cp_old[CPUSTATES]; 14090285Sobrienstatic long cp_diff[CPUSTATES]; 14118334Speter 14218334Speter/* these are for detailing the process states */ 14318334Speter 14418334Speterint process_states[8]; 14518334Speterchar *procstatenames[] = { 14618334Speter "", " starting, ", " running, ", " sleeping, ", " stopped, ", 14718334Speter " zombie, ", " waiting, ", " mutex, ", 14818334Speter NULL 14918334Speter}; 15018334Speter 15118334Speter/* these are for detailing the cpu states */ 15218334Speter 15318334Speterint cpu_states[CPUSTATES]; 15418334Speterchar *cpustatenames[] = { 15590285Sobrien "user", "nice", "system", "interrupt", "idle", NULL 15690285Sobrien}; 15790285Sobrien 15890285Sobrien/* these are for detailing the memory statistics */ 15990285Sobrien 16090285Sobrienint memory_stats[7]; 16190285Sobrienchar *memorynames[] = { 16218334Speter "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free", 16318334Speter NULL 16418334Speter}; 16518334Speter 16618334Speterint swap_stats[7]; 16718334Speterchar *swapnames[] = { 16818334Speter/* 0 1 2 3 4 5 */ 16918334Speter "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", 17018334Speter NULL 17118334Speter}; 17218334Speter 17390285Sobrien 17418334Speter/* these are for keeping track of the proc array */ 17518334Speter 17690285Sobrienstatic int nproc; 17790285Sobrienstatic int onproc = -1; 17890285Sobrienstatic int pref_len; 17990285Sobrienstatic struct kinfo_proc *pbase; 18090285Sobrienstatic struct kinfo_proc **pref; 18118334Speter 18218334Speter/* these are for getting the memory statistics */ 18318334Speter 18418334Speterstatic int pageshift; /* log base 2 of the pagesize */ 18550654Sobrien 18690285Sobrien/* define pagetok in terms of pageshift */ 18790285Sobrien 18850654Sobrien#define pagetok(size) ((size) << pageshift) 18918334Speter 19090285Sobrien/* useful externals */ 19118334Speterlong percentages(); 19218334Speter 19390285Sobrien#ifdef ORDER 19418334Speter/* sorting orders. first is default */ 19590285Sobrienchar *ordernames[] = { 19690285Sobrien "cpu", "size", "res", "time", "pri", NULL 19790285Sobrien}; 19890285Sobrien#endif 19990285Sobrien 20090285Sobrienint 20190285Sobrienmachine_init(statics) 20290285Sobrien 20390285Sobrienstruct statics *statics; 20490285Sobrien 20518334Speter{ 20650654Sobrien register int pagesize; 20750654Sobrien size_t modelen; 20850654Sobrien struct passwd *pw; 20950654Sobrien 21052295Sobrien modelen = sizeof(smpmode); 21190285Sobrien if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 && 21290285Sobrien sysctlbyname("smp.smp_active", &smpmode, &modelen, NULL, 0) < 0) || 21352295Sobrien modelen != sizeof(smpmode)) 21452295Sobrien smpmode = 0; 21552295Sobrien 21652295Sobrien while ((pw = getpwent()) != NULL) { 21790285Sobrien if (strlen(pw->pw_name) > namelength) 21890285Sobrien namelength = strlen(pw->pw_name); 21990285Sobrien } 22090285Sobrien if (namelength < 8) 22190285Sobrien namelength = 8; 22290285Sobrien if (smpmode && namelength > 13) 22390285Sobrien namelength = 13; 22490285Sobrien else if (namelength > 15) 22590285Sobrien namelength = 15; 22690285Sobrien 22790285Sobrien if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY, "kvm_open")) == NULL) 22890285Sobrien return -1; 22996294Sobrien 23090285Sobrien GETSYSCTL("kern.ccpu", ccpu); 23152295Sobrien 23252295Sobrien /* this is used in calculating WCPU -- calculate it ahead of time */ 23352295Sobrien logcpu = log(loaddouble(ccpu)); 23452295Sobrien 23552295Sobrien pbase = NULL; 23652295Sobrien pref = NULL; 23790285Sobrien nproc = 0; 23890285Sobrien onproc = -1; 23990285Sobrien /* get the page size with "getpagesize" and calculate pageshift from it */ 24052295Sobrien pagesize = getpagesize(); 24190285Sobrien pageshift = 0; 24252295Sobrien while (pagesize > 1) 24390285Sobrien { 24490285Sobrien pageshift++; 24590285Sobrien pagesize >>= 1; 24690285Sobrien } 24790285Sobrien 24890285Sobrien /* we only need the amount of log(2)1024 for our conversion */ 24990285Sobrien pageshift -= LOG1024; 25090285Sobrien 25190285Sobrien /* fill in the statics information */ 25290285Sobrien statics->procstate_names = procstatenames; 25390285Sobrien statics->cpustate_names = cpustatenames; 25490285Sobrien statics->memory_names = memorynames; 25590285Sobrien statics->swap_names = swapnames; 25690285Sobrien#ifdef ORDER 25790285Sobrien statics->order_names = ordernames; 25890285Sobrien#endif 25990285Sobrien 26090285Sobrien /* all done! */ 26190285Sobrien return(0); 26290285Sobrien} 26390285Sobrien 26490285Sobrienchar *format_header(uname_field) 26590285Sobrien 26690285Sobrienregister char *uname_field; 26790285Sobrien 26890285Sobrien{ 26990285Sobrien static char Header[128]; 27052295Sobrien 27150654Sobrien snprintf(Header, sizeof(Header), smpmode ? smp_header : up_header, 27218334Speter namelength, namelength, uname_field); 27390285Sobrien 27490285Sobrien cmdlengthdelta = strlen(Header) - 7; 27518334Speter 27690285Sobrien return Header; 27790285Sobrien} 27890285Sobrien 27990285Sobrienstatic int swappgsin = -1; 28090285Sobrienstatic int swappgsout = -1; 28190285Sobrienextern struct timeval timeout; 28290285Sobrien 28390285Sobrienvoid 28490285Sobrienget_system_info(si) 28590285Sobrien 28690285Sobrienstruct system_info *si; 28790285Sobrien 28890285Sobrien{ 28996294Sobrien long total; 29096294Sobrien struct loadavg sysload; 29196294Sobrien int mib[2]; 29296294Sobrien struct timeval boottime; 29396294Sobrien size_t bt_size; 29490285Sobrien 29590285Sobrien /* get the cp_time array */ 29690285Sobrien GETSYSCTL("kern.cp_time", cp_time); 29790285Sobrien GETSYSCTL("vm.loadavg", sysload); 29890285Sobrien GETSYSCTL("kern.lastpid", lastpid); 29990285Sobrien 30096294Sobrien /* convert load averages to doubles */ 30196294Sobrien { 30296294Sobrien register int i; 30396294Sobrien register double *infoloadp; 30496294Sobrien 30596294Sobrien infoloadp = si->load_avg; 30690285Sobrien for (i = 0; i < 3; i++) 30790285Sobrien { 30890285Sobrien#ifdef notyet 30990285Sobrien *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale; 31090285Sobrien#endif 31190285Sobrien *infoloadp++ = loaddouble(sysload.ldavg[i]); 31290285Sobrien } 31390285Sobrien } 31490285Sobrien 31590285Sobrien /* convert cp_time counts to percentages */ 31690285Sobrien total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 31790285Sobrien 31890285Sobrien /* sum memory & swap statistics */ 31990285Sobrien { 32090285Sobrien static unsigned int swap_delay = 0; 32190285Sobrien static int swapavail = 0; 32290285Sobrien static int swapfree = 0; 32390285Sobrien static int bufspace = 0; 32490285Sobrien static int nspgsin, nspgsout; 32590285Sobrien 32690285Sobrien GETSYSCTL("vfs.bufspace", bufspace); 32790285Sobrien GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]); 32890285Sobrien GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]); 32990285Sobrien GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]); 33090285Sobrien GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]); 33190285Sobrien GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]); 33290285Sobrien GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin); 33390285Sobrien GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout); 33490285Sobrien /* convert memory stats to Kbytes */ 33590285Sobrien memory_stats[0] = pagetok(memory_stats[0]); 33690285Sobrien memory_stats[1] = pagetok(memory_stats[1]); 33790285Sobrien memory_stats[2] = pagetok(memory_stats[2]); 33890285Sobrien memory_stats[3] = pagetok(memory_stats[3]); 33990285Sobrien memory_stats[4] = bufspace / 1024; 34090285Sobrien memory_stats[5] = pagetok(memory_stats[5]); 34190285Sobrien memory_stats[6] = -1; 34290285Sobrien 34390285Sobrien /* first interval */ 34490285Sobrien if (swappgsin < 0) { 34590285Sobrien swap_stats[4] = 0; 34690285Sobrien swap_stats[5] = 0; 34790285Sobrien } 34890285Sobrien 34990285Sobrien /* compute differences between old and new swap statistic */ 35090285Sobrien else { 35190285Sobrien swap_stats[4] = pagetok(((nspgsin - swappgsin))); 35290285Sobrien swap_stats[5] = pagetok(((nspgsout - swappgsout))); 35390285Sobrien } 35490285Sobrien 35590285Sobrien swappgsin = nspgsin; 35690285Sobrien swappgsout = nspgsout; 35790285Sobrien 35890285Sobrien /* call CPU heavy swapmode() only for changes */ 35996294Sobrien if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) { 36090285Sobrien swap_stats[3] = swapmode(&swapavail, &swapfree); 36190285Sobrien swap_stats[0] = swapavail; 36296294Sobrien swap_stats[1] = swapavail - swapfree; 36390285Sobrien swap_stats[2] = swapfree; 36490285Sobrien } 36590285Sobrien swap_delay = 1; 36690285Sobrien swap_stats[6] = -1; 36796294Sobrien } 36890285Sobrien 36990285Sobrien /* set arrays and strings */ 37090285Sobrien si->cpustates = cpu_states; 37190285Sobrien si->memory = memory_stats; 37296294Sobrien si->swap = swap_stats; 37390285Sobrien 37490285Sobrien 37590285Sobrien if(lastpid > 0) { 37690285Sobrien si->last_pid = lastpid; 37790285Sobrien } else { 37890285Sobrien si->last_pid = -1; 37990285Sobrien } 38090285Sobrien 38190285Sobrien /* 38290285Sobrien * Print how long system has been up. 38390285Sobrien * (Found by looking getting "boottime" from the kernel) 38490285Sobrien */ 38590285Sobrien mib[0] = CTL_KERN; 38690285Sobrien mib[1] = KERN_BOOTTIME; 38790285Sobrien bt_size = sizeof(boottime); 38890285Sobrien if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 && 38990285Sobrien boottime.tv_sec != 0) { 39090285Sobrien si->boottime = boottime; 39190285Sobrien } else { 39290285Sobrien si->boottime.tv_sec = -1; 39390285Sobrien } 39490285Sobrien} 39590285Sobrien 39650654Sobrienstatic struct handle handle; 39750654Sobrien 39850654Sobriencaddr_t get_process_info(si, sel, compare) 39950654Sobrien 40090285Sobrienstruct system_info *si; 40190285Sobrienstruct process_select *sel; 40250654Sobrienint (*compare)(); 40350654Sobrien 40452295Sobrien{ 40590285Sobrien register int i; 40690285Sobrien register int total_procs; 40790285Sobrien register int active_procs; 40890285Sobrien register struct kinfo_proc **prefp; 40990285Sobrien register struct kinfo_proc *pp; 41090285Sobrien 41190285Sobrien /* these are copied out of sel for speed */ 41290285Sobrien int show_idle; 41390285Sobrien int show_self; 41490285Sobrien int show_system; 41550654Sobrien int show_uid; 41650654Sobrien int show_command; 41790285Sobrien 41850654Sobrien 41950654Sobrien pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc); 42050654Sobrien if (nproc > onproc) 42118334Speter pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *) 42218334Speter * (onproc = nproc)); 42318334Speter if (pref == NULL || pbase == NULL) { 42418334Speter (void) fprintf(stderr, "top: Out of memory.\n"); 42518334Speter quit(23); 42618334Speter } 42718334Speter /* get a pointer to the states summary array */ 42818334Speter si->procstates = process_states; 42918334Speter 43090285Sobrien /* set up flags which define what we are going to select */ 43190285Sobrien show_idle = sel->idle; 43290285Sobrien show_self = sel->self; 43390285Sobrien show_system = sel->system; 43490285Sobrien show_uid = sel->uid != -1; 43590285Sobrien show_command = sel->command != NULL; 43690285Sobrien 43790285Sobrien /* count up process states and get pointers to interesting procs */ 43890285Sobrien total_procs = 0; 43990285Sobrien active_procs = 0; 44090285Sobrien memset((char *)process_states, 0, sizeof(process_states)); 44190285Sobrien prefp = pref; 44290285Sobrien for (pp = pbase, i = 0; i < nproc; pp++, i++) 44390285Sobrien { 44490285Sobrien /* 44590285Sobrien * Place pointers to each valid proc structure in pref[]. 44690285Sobrien * Process slots that are actually in use have a non-zero 44790285Sobrien * status field. Processes with P_SYSTEM set are system 44890285Sobrien * processes---these get ignored unless show_sysprocs is set. 44990285Sobrien */ 45090285Sobrien if (pp->ki_stat != 0 && 45190285Sobrien (show_self != pp->ki_pid) && 45290285Sobrien (show_system || ((pp->ki_flag & P_SYSTEM) == 0))) 45396294Sobrien { 45490285Sobrien total_procs++; 45596294Sobrien process_states[(unsigned char) pp->ki_stat]++; 45690285Sobrien if ((pp->ki_stat != SZOMB) && 45790285Sobrien (show_idle || (pp->ki_pctcpu != 0) || 45890285Sobrien (pp->ki_stat == SRUN)) && 45918334Speter (!show_uid || pp->ki_ruid == (uid_t)sel->uid)) 46018334Speter { 46118334Speter *prefp++ = pp; 46218334Speter active_procs++; 46318334Speter } 46418334Speter } 46518334Speter } 46618334Speter 46718334Speter /* if requested, sort the "interesting" processes */ 46818334Speter if (compare != NULL) 46918334Speter { 47018334Speter qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare); 47118334Speter } 47218334Speter 47318334Speter /* remember active and total counts */ 47418334Speter si->p_total = total_procs; 47518334Speter si->p_active = pref_len = active_procs; 47650654Sobrien 47790285Sobrien /* pass back a handle */ 47890285Sobrien handle.next_proc = pref; 47950654Sobrien handle.remaining = active_procs; 48050654Sobrien return((caddr_t)&handle); 48150654Sobrien} 48250654Sobrien 48350654Sobrienchar fmt[128]; /* static area where result is built */ 48450654Sobrien 48590285Sobrienchar *format_next_process(handle, get_userid) 48690285Sobrien 48790285Sobriencaddr_t handle; 48890285Sobrienchar *(*get_userid)(); 48990285Sobrien 49090285Sobrien{ 49190285Sobrien register struct kinfo_proc *pp; 49290285Sobrien register long cputime; 49390285Sobrien register double pct; 49490285Sobrien struct handle *hp; 49590285Sobrien char status[16]; 49690285Sobrien int state; 49750654Sobrien 49818334Speter /* find and remember the next proc structure */ 49990285Sobrien hp = (struct handle *)handle; 50090285Sobrien pp = *(hp->next_proc++); 50190285Sobrien hp->remaining--; 50290285Sobrien 50390285Sobrien /* get the process's command name */ 50490285Sobrien if ((pp->ki_sflag & PS_INMEM) == 0) { 50590285Sobrien /* 50690285Sobrien * Print swapped processes as <pname> 50790285Sobrien */ 50890285Sobrien char *comm = pp->ki_comm; 50990285Sobrien#define COMSIZ sizeof(pp->ki_comm) 51090285Sobrien char buf[COMSIZ]; 51190285Sobrien (void) strncpy(buf, comm, COMSIZ); 51250654Sobrien comm[0] = '<'; 51390285Sobrien (void) strncpy(&comm[1], buf, COMSIZ - 2); 51490285Sobrien comm[COMSIZ - 2] = '\0'; 51590285Sobrien (void) strncat(comm, ">", COMSIZ - 1); 51690285Sobrien comm[COMSIZ - 1] = '\0'; 51750654Sobrien } 51890285Sobrien 51990285Sobrien /* 52052295Sobrien * Convert the process's runtime from microseconds to seconds. This 52190285Sobrien * time includes the interrupt time although that is not wanted here. 52290285Sobrien * ps(1) is similarly sloppy. 52352295Sobrien */ 52490285Sobrien cputime = (pp->ki_runtime + 500000) / 1000000; 52590285Sobrien 52650654Sobrien /* calculate the base for cpu percentages */ 52790285Sobrien pct = pctdouble(pp->ki_pctcpu); 52890285Sobrien 52950654Sobrien /* generate "STATE" field */ 53090285Sobrien switch (state = pp->ki_stat) { 53190285Sobrien case SRUN: 53290285Sobrien if (smpmode && pp->ki_oncpu != 0xff) 53390285Sobrien sprintf(status, "CPU%d", pp->ki_oncpu); 53490285Sobrien else 53590285Sobrien strcpy(status, "RUN"); 53690285Sobrien break; 53790285Sobrien case SMTX: 53890285Sobrien if (pp->ki_kiflag & KI_MTXBLOCK) { 53990285Sobrien sprintf(status, "*%.6s", pp->ki_mtxname); 54090285Sobrien break; 54190285Sobrien } 54290285Sobrien /* fall through */ 54390285Sobrien case SSLEEP: 54490285Sobrien if (pp->ki_wmesg != NULL) { 54590285Sobrien sprintf(status, "%.6s", pp->ki_wmesg); 54690285Sobrien break; 54790285Sobrien } 54890285Sobrien /* fall through */ 54990285Sobrien default: 55090285Sobrien 55190285Sobrien if (state >= 0 && 55290285Sobrien state < sizeof(state_abbrev) / sizeof(*state_abbrev)) 55390285Sobrien sprintf(status, "%.6s", state_abbrev[(unsigned char) state]); 55490285Sobrien else 55590285Sobrien sprintf(status, "?%5d", state); 55652295Sobrien break; 55790285Sobrien } 55850654Sobrien 55950654Sobrien /* format this entry */ 56050654Sobrien sprintf(fmt, 56190285Sobrien smpmode ? smp_Proc_format : up_Proc_format, 56290285Sobrien pp->ki_pid, 56390285Sobrien namelength, namelength, 56490285Sobrien (*get_userid)(pp->ki_ruid), 56590285Sobrien pp->ki_pri.pri_level - PZERO, 56690285Sobrien 56790285Sobrien /* 56890285Sobrien * normal time -> nice value -20 - +20 56990285Sobrien * real time 0 - 31 -> nice value -52 - -21 57090285Sobrien * idle time 0 - 31 -> nice value +21 - +52 57190285Sobrien */ 57290285Sobrien (pp->ki_pri.pri_class == PRI_TIMESHARE ? 57390285Sobrien pp->ki_nice - NZERO : 57490285Sobrien (PRI_IS_REALTIME(pp->ki_pri.pri_class) ? 57590285Sobrien (PRIO_MIN - 1 - (PRI_MAX_REALTIME - pp->ki_pri.pri_level)) : 57690285Sobrien (PRIO_MAX + 1 + pp->ki_pri.pri_level - PRI_MIN_IDLE))), 57790285Sobrien format_k2(PROCSIZE(pp)), 57890285Sobrien format_k2(pagetok(pp->ki_rssize)), 57990285Sobrien status, 58090285Sobrien smpmode ? pp->ki_lastcpu : 0, 58190285Sobrien format_time(cputime), 58290285Sobrien 100.0 * weighted_cpu(pct, pp), 58390285Sobrien 100.0 * pct, 58490285Sobrien screen_width > cmdlengthdelta ? 58590285Sobrien screen_width - cmdlengthdelta : 58690285Sobrien 0, 58790285Sobrien printable(pp->ki_comm)); 58890285Sobrien 58990285Sobrien /* return the result */ 59090285Sobrien return(fmt); 59190285Sobrien} 59290285Sobrien 59390285Sobrienstatic void getsysctl (name, ptr, len) 59490285Sobrien 59590285Sobrienchar *name; 59690285Sobrienvoid *ptr; 59790285Sobriensize_t len; 59890285Sobrien 59990285Sobrien{ 60090285Sobrien size_t nlen = len; 60190285Sobrien if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 60290285Sobrien fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name, 60390285Sobrien strerror(errno)); 60490285Sobrien quit(23); 60590285Sobrien } 60690285Sobrien if (nlen != len) { 60790285Sobrien fprintf(stderr, "top: sysctl(%s...) expected %d, got %d\n", name, 60890285Sobrien len, nlen); 60990285Sobrien quit(23); 61090285Sobrien } 61190285Sobrien} 61290285Sobrien 61390285Sobrien/* comparison routines for qsort */ 61490285Sobrien 61590285Sobrien/* 61690285Sobrien * proc_compare - comparison function for "qsort" 61790285Sobrien * Compares the resource consumption of two processes using five 61890285Sobrien * distinct keys. The keys (in descending order of importance) are: 61996294Sobrien * percent cpu, cpu ticks, state, resident set size, total virtual 62090285Sobrien * memory usage. The process states are ordered as follows (from least 62190285Sobrien * to most important): WAIT, zombie, sleep, stop, start, run. The 62296294Sobrien * array declaration below maps a process state index into a number 62390285Sobrien * that reflects this ordering. 62490285Sobrien */ 62590285Sobrien 62690285Sobrienstatic unsigned char sorted_state[] = 62790285Sobrien{ 62890285Sobrien 0, /* not used */ 62950654Sobrien 3, /* sleep */ 63090285Sobrien 1, /* ABANDONED (WAIT) */ 63190285Sobrien 6, /* run */ 63290285Sobrien 5, /* start */ 63390285Sobrien 2, /* zombie */ 63490285Sobrien 4 /* stop */ 63550654Sobrien}; 63690285Sobrien 63790285Sobrien 63890285Sobrien#define ORDERKEY_PCTCPU \ 63990285Sobrien if (lresult = (long) p2->ki_pctcpu - (long) p1->ki_pctcpu, \ 64090285Sobrien (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 64190285Sobrien 64290285Sobrien#define ORDERKEY_CPTICKS \ 64390285Sobrien if ((result = p2->ki_runtime > p1->ki_runtime ? 1 : \ 64450654Sobrien p2->ki_runtime < p1->ki_runtime ? -1 : 0) == 0) 64550654Sobrien 64690285Sobrien#define ORDERKEY_STATE \ 64750654Sobrien if ((result = sorted_state[(unsigned char) p2->ki_stat] - \ 64850654Sobrien sorted_state[(unsigned char) p1->ki_stat]) == 0) 64950654Sobrien 65050654Sobrien#define ORDERKEY_PRIO \ 65150654Sobrien if ((result = p2->ki_pri.pri_level - p1->ki_pri.pri_level) == 0) 65250654Sobrien 65350654Sobrien#define ORDERKEY_RSSIZE \ 65450654Sobrien if ((result = p2->ki_rssize - p1->ki_rssize) == 0) 65550654Sobrien 65650654Sobrien#define ORDERKEY_MEM \ 65750654Sobrien if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 ) 65850654Sobrien 65950654Sobrien/* compare_cpu - the comparison function for sorting by cpu percentage */ 66050654Sobrien 66150654Sobrienint 66250654Sobrien#ifdef ORDER 66350654Sobriencompare_cpu(pp1, pp2) 66450654Sobrien#else 66550654Sobrienproc_compare(pp1, pp2) 66690285Sobrien#endif 66790285Sobrien 66890285Sobrienstruct proc **pp1; 66990285Sobrienstruct proc **pp2; 67090285Sobrien 67150654Sobrien{ 67250654Sobrien register struct kinfo_proc *p1; 67350654Sobrien register struct kinfo_proc *p2; 67418334Speter register int result; 67518334Speter register pctcpu lresult; 67690285Sobrien 67790285Sobrien /* remove one level of indirection */ 67890285Sobrien p1 = *(struct kinfo_proc **) pp1; 67990285Sobrien p2 = *(struct kinfo_proc **) pp2; 68090285Sobrien 68190285Sobrien ORDERKEY_PCTCPU 68290285Sobrien ORDERKEY_CPTICKS 68390285Sobrien ORDERKEY_STATE 68490285Sobrien ORDERKEY_PRIO 68590285Sobrien ORDERKEY_RSSIZE 68690285Sobrien ORDERKEY_MEM 68790285Sobrien ; 68890285Sobrien 68990285Sobrien return(result); 69090285Sobrien} 69190285Sobrien 69218334Speter#ifdef ORDER 69390285Sobrien/* compare routines */ 69490285Sobrienint compare_size(), compare_res(), compare_time(), compare_prio(); 69590285Sobrien 69690285Sobrienint (*proc_compares[])() = { 69790285Sobrien compare_cpu, 69890285Sobrien compare_size, 69990285Sobrien compare_res, 70090285Sobrien compare_time, 70190285Sobrien compare_prio, 70290285Sobrien NULL 70390285Sobrien}; 70490285Sobrien 70590285Sobrien/* compare_size - the comparison function for sorting by total memory usage */ 70690285Sobrien 70790285Sobrienint 70890285Sobriencompare_size(pp1, pp2) 70990285Sobrien 71018334Speterstruct proc **pp1; 71118334Speterstruct proc **pp2; 71290285Sobrien 71318334Speter{ 71418334Speter register struct kinfo_proc *p1; 71518334Speter register struct kinfo_proc *p2; 71618334Speter register int result; 71718334Speter register pctcpu lresult; 71818334Speter 71918334Speter /* remove one level of indirection */ 72018334Speter p1 = *(struct kinfo_proc **) pp1; 72118334Speter p2 = *(struct kinfo_proc **) pp2; 72218334Speter 72318334Speter ORDERKEY_MEM 72418334Speter ORDERKEY_RSSIZE 72518334Speter ORDERKEY_PCTCPU 72618334Speter ORDERKEY_CPTICKS 72718334Speter ORDERKEY_STATE 72818334Speter ORDERKEY_PRIO 72918334Speter ; 73018334Speter 73118334Speter return(result); 73218334Speter} 73318334Speter 73418334Speter/* compare_res - the comparison function for sorting by resident set size */ 73518334Speter 73690285Sobrienint 73718334Spetercompare_res(pp1, pp2) 73818334Speter 73990285Sobrienstruct proc **pp1; 74090285Sobrienstruct proc **pp2; 74118334Speter 74218334Speter{ 74318334Speter register struct kinfo_proc *p1; 74490285Sobrien register struct kinfo_proc *p2; 74518334Speter register int result; 74618334Speter register pctcpu lresult; 74790285Sobrien 74818334Speter /* remove one level of indirection */ 74990285Sobrien p1 = *(struct kinfo_proc **) pp1; 75090285Sobrien p2 = *(struct kinfo_proc **) pp2; 75118334Speter 75252295Sobrien ORDERKEY_RSSIZE 75352295Sobrien ORDERKEY_MEM 75490285Sobrien ORDERKEY_PCTCPU 75552295Sobrien ORDERKEY_CPTICKS 75690285Sobrien ORDERKEY_STATE 75790285Sobrien ORDERKEY_PRIO 75890285Sobrien ; 75990285Sobrien 76090285Sobrien return(result); 76190285Sobrien} 76218334Speter 76390285Sobrien/* compare_time - the comparison function for sorting by total cpu time */ 76490285Sobrien 76518334Speterint 76690285Sobriencompare_time(pp1, pp2) 76718334Speter 76890285Sobrienstruct proc **pp1; 76990285Sobrienstruct proc **pp2; 77018334Speter 77118334Speter{ 77218334Speter register struct kinfo_proc *p1; 77390285Sobrien register struct kinfo_proc *p2; 77490285Sobrien register int result; 77590285Sobrien register pctcpu lresult; 77690285Sobrien 77718334Speter /* remove one level of indirection */ 77890285Sobrien p1 = *(struct kinfo_proc **) pp1; 77990285Sobrien p2 = *(struct kinfo_proc **) pp2; 78090285Sobrien 78190285Sobrien ORDERKEY_CPTICKS 78290285Sobrien ORDERKEY_PCTCPU 78390285Sobrien ORDERKEY_STATE 78490285Sobrien ORDERKEY_PRIO 78590285Sobrien ORDERKEY_RSSIZE 78690285Sobrien ORDERKEY_MEM 78790285Sobrien ; 78890285Sobrien 78990285Sobrien return(result); 79090285Sobrien } 79190285Sobrien 79290285Sobrien/* compare_prio - the comparison function for sorting by cpu percentage */ 79390285Sobrien 79490285Sobrienint 79590285Sobriencompare_prio(pp1, pp2) 79650654Sobrien 79790285Sobrienstruct proc **pp1; 79850654Sobrienstruct proc **pp2; 79950654Sobrien 80050654Sobrien{ 80150654Sobrien register struct kinfo_proc *p1; 80250654Sobrien register struct kinfo_proc *p2; 80350654Sobrien register int result; 80450654Sobrien register pctcpu lresult; 80550654Sobrien 80650654Sobrien /* remove one level of indirection */ 80750654Sobrien p1 = *(struct kinfo_proc **) pp1; 80890285Sobrien p2 = *(struct kinfo_proc **) pp2; 80950654Sobrien 81050654Sobrien ORDERKEY_PRIO 81150654Sobrien ORDERKEY_CPTICKS 81250654Sobrien ORDERKEY_PCTCPU 81350654Sobrien ORDERKEY_STATE 81450654Sobrien ORDERKEY_RSSIZE 81550654Sobrien ORDERKEY_MEM 81650654Sobrien ; 81750654Sobrien 81850654Sobrien return(result); 81950654Sobrien} 82050654Sobrien#endif 82150654Sobrien 82290285Sobrien/* 82350654Sobrien * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 82452295Sobrien * the process does not exist. 82552295Sobrien * It is EXTREMLY IMPORTANT that this function work correctly. 82652295Sobrien * If top runs setuid root (as in SVR4), then this function 82752295Sobrien * is the only thing that stands in the way of a serious 82852295Sobrien * security problem. It validates requests for the "kill" 82952295Sobrien * and "renice" commands. 83052295Sobrien */ 83152295Sobrien 83252295Sobrienint proc_owner(pid) 83352295Sobrien 83490285Sobrienint pid; 83552295Sobrien 83690285Sobrien{ 83790285Sobrien register int cnt; 83890285Sobrien register struct kinfo_proc **prefp; 83990285Sobrien register struct kinfo_proc *pp; 84090285Sobrien 84190285Sobrien prefp = pref; 84290285Sobrien cnt = pref_len; 84318334Speter while (--cnt >= 0) 84418334Speter { 84518334Speter pp = *prefp++; 84618334Speter if (pp->ki_pid == (pid_t)pid) 84718334Speter { 84818334Speter return((int)pp->ki_ruid); 84918334Speter } 85018334Speter } 85118334Speter return(-1); 85218334Speter} 85318334Speter 85418334Speterint 85590285Sobrienswapmode(retavail, retfree) 85618334Speter int *retavail; 85718334Speter int *retfree; 85890285Sobrien{ 85990285Sobrien int n; 86090285Sobrien int pagesize = getpagesize(); 86118334Speter struct kvm_swap swapary[1]; 86218334Speter 86318334Speter *retavail = 0; 86418334Speter *retfree = 0; 86518334Speter 86618334Speter#define CONVERT(v) ((quad_t)(v) * pagesize / 1024) 86718334Speter 86818334Speter n = kvm_getswapinfo(kd, swapary, 1, 0); 86918334Speter if (n < 0 || swapary[0].ksw_total == 0) 87018334Speter return(0); 87118334Speter 87218334Speter *retavail = CONVERT(swapary[0].ksw_total); 87318334Speter *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); 87418334Speter 87518334Speter n = (int)((double)swapary[0].ksw_used * 100.0 / 87690285Sobrien (double)swapary[0].ksw_total); 87718334Speter return(n); 87890285Sobrien} 87918334Speter 88090285Sobrien