machine.c revision 159520
1233294Sstas/* 2102644Snectar * top - a top users display for Unix 355682Smarkm * 4142403Snectar * SYNOPSIS: For FreeBSD-2.x and later 5233294Sstas * 6233294Sstas * DESCRIPTION: 755682Smarkm * Originally written for BSD4.4 system by Christos Zoulas. 855682Smarkm * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider 955682Smarkm * Order support hacked in from top-3.5beta6/machine/m_aix41.c 1055682Smarkm * by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/) 1155682Smarkm * 1255682Smarkm * This is the machine-dependent module for FreeBSD 2.2 1355682Smarkm * Works for: 1455682Smarkm * FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x 1555682Smarkm * 1690926Snectar * LIBS: -lkvm 1790926Snectar * 18233294Sstas * AUTHOR: Christos Zoulas <christos@ee.cornell.edu> 1990926Snectar * Steven Wallace <swallace@freebsd.org> 20233294Sstas * Wolfram Schneider <wosch@FreeBSD.org> 2190926Snectar * Thomas Moestl <tmoestl@gmx.net> 22233294Sstas * 2355682Smarkm * $FreeBSD: head/usr.bin/top/machine.c 159520 2006-06-11 19:18:39Z se $ 2455682Smarkm */ 2555682Smarkm 26233294Sstas#include <sys/param.h> 2755682Smarkm#include <sys/errno.h> 28233294Sstas#include <sys/file.h> 29102644Snectar#include <sys/proc.h> 30102644Snectar#include <sys/resource.h> 31102644Snectar#include <sys/rtprio.h> 32127808Snectar#include <sys/signal.h> 3390926Snectar#include <sys/sysctl.h> 34127808Snectar#include <sys/time.h> 3555682Smarkm#include <sys/user.h> 3655682Smarkm#include <sys/vmmeter.h> 3755682Smarkm 3855682Smarkm#include <kvm.h> 3955682Smarkm#include <math.h> 4055682Smarkm#include <nlist.h> 41178825Sdfr#include <paths.h> 4255682Smarkm#include <pwd.h> 43142403Snectar#include <stdio.h> 44142403Snectar#include <stdlib.h> 45142403Snectar#include <string.h> 46233294Sstas#include <strings.h> 47233294Sstas#include <unistd.h> 48178825Sdfr 49142403Snectar#include "top.h" 50233294Sstas#include "machine.h" 51142403Snectar#include "screen.h" 52142403Snectar#include "utils.h" 53142403Snectar 54233294Sstas#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) 55142403Snectar#define SMPUNAMELEN 13 56142403Snectar#define UPUNAMELEN 15 57142403Snectar 58142403Snectarextern struct process_select ps; 59142403Snectarextern char* printable(char *); 60142403Snectarstatic int smpmode; 61142403Snectarenum displaymodes displaymode; 62142403Snectarstatic int namelength = 8; 63142403Snectarstatic int cmdlengthdelta; 64142403Snectar 65142403Snectar/* Prototypes for top internals */ 66142403Snectarvoid quit(int); 67142403Snectar 68142403Snectar/* get_process_info passes back a handle. This is what it looks like: */ 69233294Sstas 70142403Snectarstruct handle { 71142403Snectar struct kinfo_proc **next_proc; /* points to next valid proc pointer */ 72142403Snectar int remaining; /* number of pointers remaining */ 73142403Snectar}; 74178825Sdfr 75142403Snectar/* declarations for load_avg */ 76142403Snectar#include "loadavg.h" 77142403Snectar 78142403Snectar/* define what weighted cpu is. */ 79142403Snectar#define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \ 80142403Snectar ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu)))) 81142403Snectar 82142403Snectar/* what we consider to be process size: */ 83233294Sstas#define PROCSIZE(pp) ((pp)->ki_size / 1024) 84233294Sstas 85233294Sstas#define RU(pp) (&(pp)->ki_rusage) 86233294Sstas#define RUTOT(pp) \ 87233294Sstas (RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt) 88233294Sstas 89178825Sdfr 90178825Sdfr/* definitions for indices in the nlist array */ 91178825Sdfr 92178825Sdfr/* 93178825Sdfr * These definitions control the format of the per-process area 94178825Sdfr */ 95178825Sdfr 96233294Sstasstatic char io_header[] = 97142403Snectar " PID %-*.*s VCSW IVCSW READ WRITE FAULT TOTAL PERCENT COMMAND"; 98142403Snectar 99178825Sdfr#define io_Proc_format \ 100142403Snectar "%5d %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s" 101142403Snectar 102233294Sstasstatic char smp_header_thr[] = 103178825Sdfr " PID %-*.*s THR PRI NICE SIZE RES STATE C TIME %6s COMMAND"; 104233294Sstasstatic char smp_header[] = 105178825Sdfr " PID %-*.*s " "PRI NICE SIZE RES STATE C TIME %6s COMMAND"; 106142403Snectar 107142403Snectar#define smp_Proc_format \ 108142403Snectar "%5d %-*.*s %s%3d %4s%7s %6s %-6.6s %1x%7s %5.2f%% %.*s" 109233294Sstas 110142403Snectarstatic char up_header_thr[] = 111142403Snectar " PID %-*.*s THR PRI NICE SIZE RES STATE TIME %6s COMMAND"; 112142403Snectarstatic char up_header[] = 113233294Sstas " PID %-*.*s " "PRI NICE SIZE RES STATE TIME %6s COMMAND"; 114233294Sstas 115233294Sstas#define up_Proc_format \ 116233294Sstas "%5d %-*.*s %s%3d %4s%7s %6s %-6.6s%.0d%7s %5.2f%% %.*s" 117233294Sstas 118233294Sstas 119233294Sstas/* process state names for the "STATE" column of the display */ 120233294Sstas/* the extra nulls in the string "run" are for adding a slash and 121233294Sstas the processor number when needed */ 122233294Sstas 123233294Sstaschar *state_abbrev[] = { 124233294Sstas "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK" 125233294Sstas}; 126142403Snectar 127142403Snectar 128142403Snectarstatic kvm_t *kd; 129142403Snectar 130142403Snectar/* values that we stash away in _init and use in later routines */ 131142403Snectar 132142403Snectarstatic double logcpu; 133142403Snectar 134178825Sdfr/* these are retrieved from the kernel in _init */ 135178825Sdfr 136178825Sdfrstatic load_avg ccpu; 137178825Sdfr 138178825Sdfr/* these are used in the get_ functions */ 139142403Snectar 140178825Sdfrstatic int lastpid; 141178825Sdfr 142142403Snectar/* these are for calculating cpu state percentages */ 143142403Snectar 144142403Snectarstatic long cp_time[CPUSTATES]; 145142403Snectarstatic long cp_old[CPUSTATES]; 146142403Snectarstatic long cp_diff[CPUSTATES]; 147142403Snectar 148178825Sdfr/* these are for detailing the process states */ 149178825Sdfr 150178825Sdfrint process_states[8]; 151142403Snectarchar *procstatenames[] = { 152142403Snectar "", " starting, ", " running, ", " sleeping, ", " stopped, ", 153142403Snectar " zombie, ", " waiting, ", " lock, ", 154178825Sdfr NULL 155178825Sdfr}; 156233294Sstas 157233294Sstas/* these are for detailing the cpu states */ 158142403Snectar 159142403Snectarint cpu_states[CPUSTATES]; 160142403Snectarchar *cpustatenames[] = { 161142403Snectar "user", "nice", "system", "interrupt", "idle", NULL 162142403Snectar}; 163142403Snectar 164233294Sstas/* these are for detailing the memory statistics */ 165233294Sstas 166233294Sstasint memory_stats[7]; 167142403Snectarchar *memorynames[] = { 168142403Snectar "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", 169178825Sdfr "K Free", NULL 170178825Sdfr}; 171178825Sdfr 172142403Snectarint swap_stats[7]; 173178825Sdfrchar *swapnames[] = { 174178825Sdfr "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", 175178825Sdfr NULL 176233294Sstas}; 177233294Sstas 178233294Sstas 179233294Sstas/* these are for keeping track of the proc array */ 180233294Sstas 181233294Sstasstatic int nproc; 182233294Sstasstatic int onproc = -1; 183233294Sstasstatic int pref_len; 184233294Sstasstatic struct kinfo_proc *pbase; 185233294Sstasstatic struct kinfo_proc **pref; 186233294Sstasstatic struct kinfo_proc *previous_procs; 187233294Sstasstatic struct kinfo_proc **previous_pref; 188233294Sstasstatic int previous_proc_count = 0; 189233294Sstasstatic int previous_proc_count_max = 0; 190233294Sstas 191233294Sstas/* total number of io operations */ 192233294Sstasstatic long total_inblock; 193233294Sstasstatic long total_oublock; 194233294Sstasstatic long total_majflt; 195233294Sstas 196233294Sstas/* these are for getting the memory statistics */ 197233294Sstas 198233294Sstasstatic int pageshift; /* log base 2 of the pagesize */ 199233294Sstas 200233294Sstas/* define pagetok in terms of pageshift */ 201233294Sstas 202233294Sstas#define pagetok(size) ((size) << pageshift) 203233294Sstas 204142403Snectar/* useful externals */ 205233294Sstaslong percentages(); 206142403Snectar 207142403Snectar#ifdef ORDER 208142403Snectar/* 209142403Snectar * Sorting orders. The first element is the default. 210127808Snectar */ 21155682Smarkmchar *ordernames[] = { 21272445Sassar "cpu", "size", "res", "time", "pri", "threads", 213127808Snectar "total", "read", "write", "fault", "vcsw", "ivcsw", NULL 214233294Sstas}; 215233294Sstas#endif 216127808Snectar 217127808Snectarstatic int compare_pid(const void *a, const void *b); 218127808Snectarstatic const char *format_nice(const struct kinfo_proc *pp); 21955682Smarkmstatic void getsysctl(const char *name, void *ptr, size_t len); 22055682Smarkmstatic int swapmode(int *retavail, int *retfree); 221233294Sstas 222233294Sstasint 22355682Smarkmmachine_init(struct statics *statics) 22455682Smarkm{ 22555682Smarkm int pagesize; 226233294Sstas size_t modelen; 227127808Snectar struct passwd *pw; 22890926Snectar 22972445Sassar modelen = sizeof(smpmode); 230127808Snectar if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, 231127808Snectar NULL, 0) != 0 && 232233294Sstas sysctlbyname("kern.smp.active", &smpmode, &modelen, 23355682Smarkm NULL, 0) != 0) || 234127808Snectar modelen != sizeof(smpmode)) 235233294Sstas smpmode = 0; 23690926Snectar 237178825Sdfr while ((pw = getpwent()) != NULL) { 238178825Sdfr if (strlen(pw->pw_name) > namelength) 23972445Sassar namelength = strlen(pw->pw_name); 240233294Sstas } 241233294Sstas if (smpmode && namelength > SMPUNAMELEN) 242233294Sstas namelength = SMPUNAMELEN; 243127808Snectar else if (namelength > UPUNAMELEN) 244127808Snectar namelength = UPUNAMELEN; 245127808Snectar 246127808Snectar kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); 247127808Snectar if (kd == NULL) 248233294Sstas return (-1); 249178825Sdfr 25055682Smarkm GETSYSCTL("kern.ccpu", ccpu); 25172445Sassar 252178825Sdfr /* this is used in calculating WCPU -- calculate it ahead of time */ 253127808Snectar logcpu = log(loaddouble(ccpu)); 254127808Snectar 255233294Sstas pbase = NULL; 256233294Sstas pref = NULL; 257127808Snectar nproc = 0; 258127808Snectar onproc = -1; 259233294Sstas 260178825Sdfr /* get the page size and calculate pageshift from it */ 261127808Snectar pagesize = getpagesize(); 262127808Snectar pageshift = 0; 263127808Snectar while (pagesize > 1) { 26490926Snectar pageshift++; 265233294Sstas pagesize >>= 1; 266127808Snectar } 267178825Sdfr 26855682Smarkm /* we only need the amount of log(2)1024 for our conversion */ 269102644Snectar pageshift -= LOG1024; 270102644Snectar 271178825Sdfr /* fill in the statics information */ 272127808Snectar statics->procstate_names = procstatenames; 273127808Snectar statics->cpustate_names = cpustatenames; 27455682Smarkm statics->memory_names = memorynames; 27555682Smarkm statics->swap_names = swapnames; 27690926Snectar#ifdef ORDER 277127808Snectar statics->order_names = ordernames; 278127808Snectar#endif 279127808Snectar 280127808Snectar /* all done! */ 281127808Snectar return (0); 28290926Snectar} 28390926Snectar 28490926Snectarchar * 285127808Snectarformat_header(char *uname_field) 286127808Snectar{ 287127808Snectar static char Header[128]; 288127808Snectar const char *prehead; 289233294Sstas 290127808Snectar switch (displaymode) { 291127808Snectar case DISP_CPU: 292233294Sstas /* 293178825Sdfr * The logic of picking the right header format seems reverse 294127808Snectar * here because we only want to display a THR column when 295127808Snectar * "thread mode" is off (and threads are not listed as 296127808Snectar * separate lines). 297127808Snectar */ 298127808Snectar prehead = smpmode ? 299127808Snectar (ps.thread ? smp_header : smp_header_thr) : 300127808Snectar (ps.thread ? up_header : up_header_thr); 301127808Snectar snprintf(Header, sizeof(Header), prehead, 302178825Sdfr namelength, namelength, uname_field, 303178825Sdfr ps.wcpu ? "WCPU" : "CPU"); 304178825Sdfr break; 305178825Sdfr case DISP_IO: 306127808Snectar prehead = io_header; 307127808Snectar snprintf(Header, sizeof(Header), prehead, 30855682Smarkm namelength, namelength, uname_field); 309127808Snectar break; 310233294Sstas } 311233294Sstas cmdlengthdelta = strlen(Header) - 7; 312127808Snectar return (Header); 313127808Snectar} 314127808Snectar 315127808Snectarstatic int swappgsin = -1; 316127808Snectarstatic int swappgsout = -1; 31755682Smarkmextern struct timeval timeout; 318127808Snectar 319127808Snectarvoid 320178825Sdfrget_system_info(struct system_info *si) 321127808Snectar{ 322127808Snectar long total; 32355682Smarkm struct loadavg sysload; 32455682Smarkm int mib[2]; 325127808Snectar struct timeval boottime; 326127808Snectar size_t bt_size; 327233294Sstas int i; 328127808Snectar 329127808Snectar /* get the cp_time array */ 330233294Sstas GETSYSCTL("kern.cp_time", cp_time); 33155682Smarkm GETSYSCTL("vm.loadavg", sysload); 33255682Smarkm GETSYSCTL("kern.lastpid", lastpid); 333120945Snectar 334127808Snectar /* convert load averages to doubles */ 335233294Sstas for (i = 0; i < 3; i++) 336178825Sdfr si->load_avg[i] = (double)sysload.ldavg[i] / sysload.fscale; 337233294Sstas 338233294Sstas /* convert cp_time counts to percentages */ 339233294Sstas total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 34055682Smarkm 341233294Sstas /* sum memory & swap statistics */ 342127808Snectar { 343233294Sstas static unsigned int swap_delay = 0; 344233294Sstas static int swapavail = 0; 34555682Smarkm static int swapfree = 0; 346127808Snectar static int bufspace = 0; 347127808Snectar static int nspgsin, nspgsout; 348127808Snectar 349127808Snectar GETSYSCTL("vfs.bufspace", bufspace); 350233294Sstas GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]); 351127808Snectar GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]); 352127808Snectar GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]); 353233294Sstas GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]); 354233294Sstas GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]); 355233294Sstas GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin); 356233294Sstas GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout); 35755682Smarkm /* convert memory stats to Kbytes */ 358233294Sstas memory_stats[0] = pagetok(memory_stats[0]); 359127808Snectar memory_stats[1] = pagetok(memory_stats[1]); 360127808Snectar memory_stats[2] = pagetok(memory_stats[2]); 361233294Sstas memory_stats[3] = pagetok(memory_stats[3]); 362233294Sstas memory_stats[4] = bufspace / 1024; 363102644Snectar memory_stats[5] = pagetok(memory_stats[5]); 36455682Smarkm memory_stats[6] = -1; 365178825Sdfr 36655682Smarkm /* first interval */ 36755682Smarkm if (swappgsin < 0) { 36855682Smarkm swap_stats[4] = 0; 369178825Sdfr swap_stats[5] = 0; 37090926Snectar } 37190926Snectar 37290926Snectar /* compute differences between old and new swap statistic */ 37390926Snectar else { 37455682Smarkm swap_stats[4] = pagetok(((nspgsin - swappgsin))); 375178825Sdfr swap_stats[5] = pagetok(((nspgsout - swappgsout))); 376178825Sdfr } 377178825Sdfr 378178825Sdfr swappgsin = nspgsin; 379178825Sdfr swappgsout = nspgsout; 380233294Sstas 381127808Snectar /* call CPU heavy swapmode() only for changes */ 382233294Sstas if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) { 383233294Sstas swap_stats[3] = swapmode(&swapavail, &swapfree); 384127808Snectar swap_stats[0] = swapavail; 385233294Sstas swap_stats[1] = swapavail - swapfree; 386178825Sdfr swap_stats[2] = swapfree; 387178825Sdfr } 388127808Snectar swap_delay = 1; 389127808Snectar swap_stats[6] = -1; 390127808Snectar } 391127808Snectar 392127808Snectar /* set arrays and strings */ 393127808Snectar si->cpustates = cpu_states; 394178825Sdfr si->memory = memory_stats; 395127808Snectar si->swap = swap_stats; 396178825Sdfr 397178825Sdfr 398102644Snectar if (lastpid > 0) { 399102644Snectar si->last_pid = lastpid; 400102644Snectar } else { 401178825Sdfr si->last_pid = -1; 402127808Snectar } 403127808Snectar 404127808Snectar /* 405127808Snectar * Print how long system has been up. 406127808Snectar * (Found by looking getting "boottime" from the kernel) 407127808Snectar */ 408178825Sdfr mib[0] = CTL_KERN; 409127808Snectar mib[1] = KERN_BOOTTIME; 410127808Snectar bt_size = sizeof(boottime); 41172445Sassar if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 && 412127808Snectar boottime.tv_sec != 0) { 413127808Snectar si->boottime = boottime; 414178825Sdfr } else { 415127808Snectar si->boottime.tv_sec = -1; 416127808Snectar } 417142403Snectar} 418127808Snectar 419178825Sdfr#define NOPROC ((void *)-1) 420127808Snectar 421127808Snectar/* 422178825Sdfr * We need to compare data from the old process entry with the new 423127808Snectar * process entry. 424127808Snectar * To facilitate doing this quickly we stash a pointer in the kinfo_proc 425178825Sdfr * structure to cache the mapping. We also use a negative cache pointer 426233294Sstas * of NOPROC to avoid duplicate lookups. 427127808Snectar * XXX: this could be done when the actual processes are fetched, we do 428127808Snectar * it here out of laziness. 429233294Sstas */ 430178825Sdfrconst struct kinfo_proc * 431178825Sdfrget_old_proc(struct kinfo_proc *pp) 432233294Sstas{ 433233294Sstas struct kinfo_proc **oldpp, *oldp; 434233294Sstas 435233294Sstas /* 436233294Sstas * If this is the first fetch of the kinfo_procs then we don't have 437102644Snectar * any previous entries. 43890926Snectar */ 43972445Sassar if (previous_proc_count == 0) 44055682Smarkm return (NULL); 441233294Sstas /* negative cache? */ 44255682Smarkm if (pp->ki_udata == NOPROC) 44355682Smarkm return (NULL); 44455682Smarkm /* cached? */ 44555682Smarkm if (pp->ki_udata != NULL) 44655682Smarkm return (pp->ki_udata); 44755682Smarkm /* 448233294Sstas * Not cached, 44955682Smarkm * 1) look up based on pid. 450120945Snectar * 2) compare process start. 45190926Snectar * If we fail here, then setup a negative cache entry, otherwise 45272445Sassar * cache it. 45355682Smarkm */ 45490926Snectar oldpp = bsearch(&pp, previous_pref, previous_proc_count, 455233294Sstas sizeof(*previous_pref), compare_pid); 45690926Snectar if (oldpp == NULL) { 457178825Sdfr pp->ki_udata = NOPROC; 458178825Sdfr return (NULL); 459178825Sdfr } 460178825Sdfr oldp = *oldpp; 461233294Sstas if (bcmp(&oldp->ki_start, &pp->ki_start, sizeof(pp->ki_start)) != 0) { 462233294Sstas pp->ki_udata = NOPROC; 463178825Sdfr return (NULL); 464233294Sstas } 465178825Sdfr pp->ki_udata = oldp; 46690926Snectar return (oldp); 46772445Sassar} 46872445Sassar 469178825Sdfr/* 470178825Sdfr * Return the total amount of IO done in blocks in/out and faults. 47172445Sassar * store the values individually in the pointers passed in. 472233294Sstas */ 47372445Sassarlong 47455682Smarkmget_io_stats(struct kinfo_proc *pp, long *inp, long *oup, long *flp, 47590926Snectar long *vcsw, long *ivcsw) 476178825Sdfr{ 477233294Sstas const struct kinfo_proc *oldp; 478233294Sstas static struct kinfo_proc dummy; 479233294Sstas long ret; 480233294Sstas 481233294Sstas oldp = get_old_proc(pp); 482233294Sstas if (oldp == NULL) { 483233294Sstas bzero(&dummy, sizeof(dummy)); 484178825Sdfr oldp = &dummy; 485178825Sdfr } 486178825Sdfr *inp = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; 487178825Sdfr *oup = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; 488178825Sdfr *flp = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; 489178825Sdfr *vcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; 490178825Sdfr *ivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; 491178825Sdfr ret = 492178825Sdfr (RU(pp)->ru_inblock - RU(oldp)->ru_inblock) + 493178825Sdfr (RU(pp)->ru_oublock - RU(oldp)->ru_oublock) + 494233294Sstas (RU(pp)->ru_majflt - RU(oldp)->ru_majflt); 495233294Sstas return (ret); 496233294Sstas} 497233294Sstas 49872445Sassar/* 49972445Sassar * Return the total number of block in/out and faults by a process. 500178825Sdfr */ 50172445Sassarlong 50272445Sassarget_io_total(struct kinfo_proc *pp) 50355682Smarkm{ 504233294Sstas long dummy; 505233294Sstas 506233294Sstas return (get_io_stats(pp, &dummy, &dummy, &dummy, &dummy, &dummy)); 507233294Sstas} 508233294Sstas 509233294Sstasstatic struct handle handle; 510233294Sstas 511233294Sstascaddr_t 512233294Sstasget_process_info(struct system_info *si, struct process_select *sel, 51390926Snectar int (*compare)(const void *, const void *)) 51455682Smarkm{ 51555682Smarkm int i; 516233294Sstas int total_procs; 517142403Snectar long p_io; 518142403Snectar long p_inblock, p_oublock, p_majflt, p_vcsw, p_ivcsw; 519142403Snectar int active_procs; 520142403Snectar struct kinfo_proc **prefp; 521233294Sstas struct kinfo_proc *pp; 522233294Sstas struct kinfo_proc *prev_pp = NULL; 523142403Snectar 524142403Snectar /* these are copied out of sel for speed */ 525142403Snectar int show_idle; 526233294Sstas int show_self; 527233294Sstas int show_system; 528233294Sstas int show_uid; 529142403Snectar int show_command; 530142403Snectar 531142403Snectar /* 532142403Snectar * Save the previous process info. 533142403Snectar */ 534142403Snectar if (previous_proc_count_max < nproc) { 535142403Snectar free(previous_procs); 536142403Snectar previous_procs = malloc(nproc * sizeof(*previous_procs)); 537142403Snectar free(previous_pref); 538142403Snectar previous_pref = malloc(nproc * sizeof(*previous_pref)); 539142403Snectar if (previous_procs == NULL || previous_pref == NULL) { 540142403Snectar (void) fprintf(stderr, "top: Out of memory.\n"); 541142403Snectar quit(23); 542142403Snectar } 543142403Snectar previous_proc_count_max = nproc; 544142403Snectar } 545142403Snectar if (nproc) { 546233294Sstas for (i = 0; i < nproc; i++) 54755682Smarkm previous_pref[i] = &previous_procs[i]; 54855682Smarkm bcopy(pbase, previous_procs, nproc * sizeof(*previous_procs)); 549178825Sdfr qsort(previous_pref, nproc, sizeof(*previous_pref), 550233294Sstas compare_pid); 551233294Sstas } 552233294Sstas previous_proc_count = nproc; 553233294Sstas 554233294Sstas pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc); 555233294Sstas if (nproc > onproc) 556233294Sstas pref = realloc(pref, sizeof(*pref) * (onproc = nproc)); 557233294Sstas if (pref == NULL || pbase == NULL) { 558233294Sstas (void) fprintf(stderr, "top: Out of memory.\n"); 559233294Sstas quit(23); 560233294Sstas } 561233294Sstas /* get a pointer to the states summary array */ 562233294Sstas si->procstates = process_states; 563233294Sstas 564233294Sstas /* set up flags which define what we are going to select */ 565233294Sstas show_idle = sel->idle; 566233294Sstas show_self = sel->self == -1; 567233294Sstas show_system = sel->system; 568233294Sstas show_uid = sel->uid != -1; 569233294Sstas show_command = sel->command != NULL; 570233294Sstas 57155682Smarkm /* count up process states and get pointers to interesting procs */ 57255682Smarkm total_procs = 0; 57355682Smarkm active_procs = 0; 574233294Sstas total_inblock = 0; 575233294Sstas total_oublock = 0; 576233294Sstas total_majflt = 0; 577233294Sstas memset((char *)process_states, 0, sizeof(process_states)); 578233294Sstas prefp = pref; 579233294Sstas for (pp = pbase, i = 0; i < nproc; pp++, i++) { 580233294Sstas 58155682Smarkm if (pp->ki_stat == 0) 58290926Snectar /* not in use */ 583233294Sstas continue; 584233294Sstas 585233294Sstas if (!show_self && pp->ki_pid == sel->self) 586233294Sstas /* skip self */ 587233294Sstas continue; 588233294Sstas 589233294Sstas if (!show_system && (pp->ki_flag & P_SYSTEM)) 590178825Sdfr /* skip system process */ 591178825Sdfr continue; 592178825Sdfr 593233294Sstas p_io = get_io_stats(pp, &p_inblock, &p_oublock, &p_majflt, 594233294Sstas &p_vcsw, &p_ivcsw); 595233294Sstas total_inblock += p_inblock; 596233294Sstas total_oublock += p_oublock; 597233294Sstas total_majflt += p_majflt; 598233294Sstas total_procs++; 599233294Sstas process_states[pp->ki_stat]++; 600233294Sstas 601233294Sstas if (pp->ki_stat == SZOMB) 602233294Sstas /* skip zombies */ 603233294Sstas continue; 604233294Sstas 605233294Sstas if (displaymode == DISP_CPU && !show_idle && 606233294Sstas (pp->ki_pctcpu == 0 || 607233294Sstas pp->ki_stat == SSTOP || pp->ki_stat == SIDL)) 608233294Sstas /* skip idle or non-running processes */ 609233294Sstas continue; 610233294Sstas 611233294Sstas if (displaymode == DISP_IO && !show_idle && p_io == 0) 612233294Sstas /* skip processes that aren't doing I/O */ 613233294Sstas continue; 61455682Smarkm 615178825Sdfr if (show_uid && pp->ki_ruid != (uid_t)sel->uid) 616178825Sdfr /* skip proc. that don't belong to the selected UID */ 617233294Sstas continue; 618233294Sstas 619233294Sstas /* 620233294Sstas * When not showing threads, take the first thread 621233294Sstas * for output and add the fields that we can from 622233294Sstas * the rest of the process's threads rather than 623233294Sstas * using the system's mostly-broken KERN_PROC_PROC. 624178825Sdfr */ 625178825Sdfr if (sel->thread || prev_pp == NULL || 626233294Sstas prev_pp->ki_pid != pp->ki_pid) { 627233294Sstas *prefp++ = pp; 628233294Sstas active_procs++; 629233294Sstas prev_pp = pp; 630233294Sstas } else { 631233294Sstas prev_pp->ki_pctcpu += pp->ki_pctcpu; 632233294Sstas } 633178825Sdfr } 63455682Smarkm 635233294Sstas /* if requested, sort the "interesting" processes */ 636233294Sstas if (compare != NULL) 637233294Sstas qsort(pref, active_procs, sizeof(*pref), compare); 638233294Sstas 639233294Sstas /* remember active and total counts */ 640233294Sstas si->p_total = total_procs; 641233294Sstas si->p_active = pref_len = active_procs; 64290926Snectar 64372445Sassar /* pass back a handle */ 644178825Sdfr handle.next_proc = pref; 645233294Sstas handle.remaining = active_procs; 646233294Sstas return ((caddr_t)&handle); 647233294Sstas} 64890926Snectar 64972445Sassarstatic char fmt[128]; /* static area where result is built */ 650178825Sdfr 65190926Snectarchar * 65255682Smarkmformat_next_process(caddr_t handle, char *(*get_userid)(int)) 653178825Sdfr{ 654178825Sdfr struct kinfo_proc *pp; 655178825Sdfr const struct kinfo_proc *oldp; 656178825Sdfr long cputime; 65790926Snectar double pct; 65855682Smarkm struct handle *hp; 659178825Sdfr char status[16]; 660178825Sdfr int state; 661178825Sdfr struct rusage ru, *rup; 662178825Sdfr long p_tot, s_tot; 66390926Snectar char *proc_fmt, thr_buf[6]; 66472445Sassar 665178825Sdfr /* find and remember the next proc structure */ 66690926Snectar hp = (struct handle *)handle; 66755682Smarkm pp = *(hp->next_proc++); 668178825Sdfr hp->remaining--; 66990926Snectar 67090926Snectar /* get the process's command name */ 671142403Snectar if ((pp->ki_sflag & PS_INMEM) == 0) { 67290926Snectar /* 67390926Snectar * Print swapped processes as <pname> 67490926Snectar */ 67590926Snectar size_t len; 676233294Sstas 677233294Sstas len = strlen(pp->ki_comm); 678233294Sstas if (len > sizeof(pp->ki_comm) - 3) 679233294Sstas len = sizeof(pp->ki_comm) - 3; 680233294Sstas memmove(pp->ki_comm + 1, pp->ki_comm, len); 681233294Sstas pp->ki_comm[0] = '<'; 682233294Sstas pp->ki_comm[len + 1] = '>'; 683233294Sstas pp->ki_comm[len + 2] = '\0'; 684233294Sstas } 685233294Sstas 686233294Sstas /* 687233294Sstas * Convert the process's runtime from microseconds to seconds. This 688233294Sstas * time includes the interrupt time although that is not wanted here. 689233294Sstas * ps(1) is similarly sloppy. 690233294Sstas */ 69172445Sassar cputime = (pp->ki_runtime + 500000) / 1000000; 692233294Sstas 693233294Sstas /* calculate the base for cpu percentages */ 694233294Sstas pct = pctdouble(pp->ki_pctcpu); 695233294Sstas 696233294Sstas /* generate "STATE" field */ 69790926Snectar switch (state = pp->ki_stat) { 69872445Sassar case SRUN: 699233294Sstas if (smpmode && pp->ki_oncpu != 0xff) 700233294Sstas sprintf(status, "CPU%d", pp->ki_oncpu); 701233294Sstas else 702233294Sstas strcpy(status, "RUN"); 703233294Sstas break; 70490926Snectar case SLOCK: 70572445Sassar if (pp->ki_kiflag & KI_LOCKBLOCK) { 706233294Sstas sprintf(status, "*%.6s", pp->ki_lockname); 707233294Sstas break; 708233294Sstas } 709233294Sstas /* fall through */ 710233294Sstas case SSLEEP: 711102644Snectar if (pp->ki_wmesg != NULL) { 712102644Snectar sprintf(status, "%.6s", pp->ki_wmesg); 713102644Snectar break; 714102644Snectar } 715102644Snectar /* FALLTHROUGH */ 716102644Snectar default: 717233294Sstas 71890926Snectar if (state >= 0 && 719178825Sdfr state < sizeof(state_abbrev) / sizeof(*state_abbrev)) 720233294Sstas sprintf(status, "%.6s", state_abbrev[state]); 721233294Sstas else 722233294Sstas sprintf(status, "?%5d", state); 723233294Sstas break; 724233294Sstas } 725233294Sstas 726233294Sstas if (displaymode == DISP_IO) { 727233294Sstas oldp = get_old_proc(pp); 728233294Sstas if (oldp != NULL) { 729233294Sstas ru.ru_inblock = RU(pp)->ru_inblock - 730233294Sstas RU(oldp)->ru_inblock; 731233294Sstas ru.ru_oublock = RU(pp)->ru_oublock - 732233294Sstas RU(oldp)->ru_oublock; 733233294Sstas ru.ru_majflt = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; 734233294Sstas ru.ru_nvcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; 735233294Sstas ru.ru_nivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; 73655682Smarkm rup = &ru; 737233294Sstas } else { 738233294Sstas rup = RU(pp); 739233294Sstas } 740233294Sstas p_tot = rup->ru_inblock + rup->ru_oublock + rup->ru_majflt; 741233294Sstas s_tot = total_inblock + total_oublock + total_majflt; 742233294Sstas 743233294Sstas sprintf(fmt, io_Proc_format, 74455682Smarkm pp->ki_pid, 74590926Snectar namelength, namelength, (*get_userid)(pp->ki_ruid), 746233294Sstas rup->ru_nvcsw, 747233294Sstas rup->ru_nivcsw, 748233294Sstas rup->ru_inblock, 749233294Sstas rup->ru_oublock, 750233294Sstas rup->ru_majflt, 751233294Sstas p_tot, 752233294Sstas s_tot == 0 ? 0.0 : (p_tot * 100.0 / s_tot), 753233294Sstas screen_width > cmdlengthdelta ? 754233294Sstas screen_width - cmdlengthdelta : 0, 755233294Sstas printable(pp->ki_comm)); 756233294Sstas return (fmt); 757233294Sstas } 758233294Sstas 759233294Sstas /* format this entry */ 760233294Sstas proc_fmt = smpmode ? smp_Proc_format : up_Proc_format; 761233294Sstas if (ps.thread != 0) 762233294Sstas thr_buf[0] = '\0'; 763233294Sstas else 764233294Sstas snprintf(thr_buf, sizeof(thr_buf), "%*d ", 765233294Sstas sizeof(thr_buf) - 2, pp->ki_numthreads); 766233294Sstas 767233294Sstas sprintf(fmt, proc_fmt, 768233294Sstas pp->ki_pid, 769233294Sstas namelength, namelength, (*get_userid)(pp->ki_ruid), 770233294Sstas thr_buf, 771233294Sstas pp->ki_pri.pri_level - PZERO, 772233294Sstas format_nice(pp), 773233294Sstas format_k2(PROCSIZE(pp)), 77455682Smarkm format_k2(pagetok(pp->ki_rssize)), 775233294Sstas status, 776233294Sstas smpmode ? pp->ki_lastcpu : 0, 777233294Sstas format_time(cputime), 778233294Sstas ps.wcpu ? 100.0 * weighted_cpu(pct, pp) : 100.0 * pct, 779233294Sstas screen_width > cmdlengthdelta ? screen_width - cmdlengthdelta : 0, 780233294Sstas printable(pp->ki_comm)); 78155682Smarkm 782233294Sstas /* return the result */ 783233294Sstas return (fmt); 784233294Sstas} 785233294Sstas 786233294Sstasstatic void 787233294Sstasgetsysctl(const char *name, void *ptr, size_t len) 788233294Sstas{ 789233294Sstas size_t nlen = len; 790233294Sstas 791233294Sstas if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 792233294Sstas fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name, 793233294Sstas strerror(errno)); 79472445Sassar quit(23); 795102644Snectar } 79672445Sassar if (nlen != len) { 79772445Sassar fprintf(stderr, "top: sysctl(%s...) expected %lu, got %lu\n", 79872445Sassar name, (unsigned long)len, (unsigned long)nlen); 799233294Sstas quit(23); 800233294Sstas } 801102644Snectar} 802142403Snectar 80355682Smarkmstatic 80472445Sassarconst char *format_nice(const struct kinfo_proc *pp) 80572445Sassar{ 806233294Sstas static char nicebuf[5]; 80755682Smarkm 808102644Snectar snprintf(nicebuf, sizeof(nicebuf), "%4d", 80972445Sassar /* 81072445Sassar * normal time -> nice value -20 - +20 81172445Sassar * real time 0 - 31 -> nice value -52 - -21 812233294Sstas * idle time 0 - 31 -> nice value +21 - +52 813233294Sstas */ 814233294Sstas (pp->ki_pri.pri_class == PRI_TIMESHARE ? 815233294Sstas pp->ki_nice - NZERO : 816178825Sdfr (PRI_IS_REALTIME(pp->ki_pri.pri_class) ? 817233294Sstas (PRIO_MIN - 1 - (PRI_MAX_REALTIME - pp->ki_pri.pri_level)) : 818233294Sstas (PRIO_MAX + 1 + pp->ki_pri.pri_level - PRI_MIN_IDLE)))); 819233294Sstas return (nicebuf); 820233294Sstas} 821233294Sstas 822233294Sstas/* comparison routines for qsort */ 823233294Sstas 824178825Sdfrstatic int 825127808Snectarcompare_pid(const void *p1, const void *p2) 826127808Snectar{ 827127808Snectar const struct kinfo_proc * const *pp1 = p1; 828127808Snectar const struct kinfo_proc * const *pp2 = p2; 829127808Snectar 830127808Snectar if ((*pp2)->ki_pid < 0 || (*pp1)->ki_pid < 0) 831127808Snectar abort(); 832233294Sstas 833233294Sstas return ((*pp1)->ki_pid - (*pp2)->ki_pid); 834233294Sstas} 835127808Snectar 836233294Sstas/* 837127808Snectar * proc_compare - comparison function for "qsort" 83878527Sassar * Compares the resource consumption of two processes using five 839102644Snectar * distinct keys. The keys (in descending order of importance) are: 840233294Sstas * percent cpu, cpu ticks, state, resident set size, total virtual 841233294Sstas * memory usage. The process states are ordered as follows (from least 84278527Sassar * to most important): WAIT, zombie, sleep, stop, start, run. The 84355682Smarkm * array declaration below maps a process state index into a number 844127808Snectar * that reflects this ordering. 84555682Smarkm */ 84655682Smarkm 847233294Sstasstatic int sorted_state[] = { 848233294Sstas 0, /* not used */ 849233294Sstas 3, /* sleep */ 850233294Sstas 1, /* ABANDONED (WAIT) */ 851233294Sstas 6, /* run */ 852233294Sstas 5, /* start */ 853233294Sstas 2, /* zombie */ 854233294Sstas 4 /* stop */ 855233294Sstas}; 856233294Sstas 857233294Sstas 858233294Sstas#define ORDERKEY_PCTCPU(a, b) do { \ 859233294Sstas long diff; \ 860178825Sdfr if (ps.wcpu) \ 861178825Sdfr diff = floor(1.0E6 * weighted_cpu(pctdouble((b)->ki_pctcpu), \ 862178825Sdfr (b))) - \ 863178825Sdfr floor(1.0E6 * weighted_cpu(pctdouble((a)->ki_pctcpu), \ 864178825Sdfr (a))); \ 865178825Sdfr else \ 866178825Sdfr diff = (long)(b)->ki_pctcpu - (long)(a)->ki_pctcpu; \ 867178825Sdfr if (diff != 0) \ 868178825Sdfr return (diff > 0 ? 1 : -1); \ 869178825Sdfr} while (0) 870178825Sdfr 871178825Sdfr#define ORDERKEY_CPTICKS(a, b) do { \ 872102644Snectar int64_t diff = (int64_t)(b)->ki_runtime - (int64_t)(a)->ki_runtime; \ 87355682Smarkm if (diff != 0) \ 874178825Sdfr return (diff > 0 ? 1 : -1); \ 875233294Sstas} while (0) 876233294Sstas 877233294Sstas#define ORDERKEY_STATE(a, b) do { \ 878102644Snectar int diff = sorted_state[(b)->ki_stat] - sorted_state[(a)->ki_stat]; \ 879233294Sstas if (diff != 0) \ 880233294Sstas return (diff > 0 ? 1 : -1); \ 881102644Snectar} while (0) 882233294Sstas 88355682Smarkm#define ORDERKEY_PRIO(a, b) do { \ 884233294Sstas int diff = (int)(b)->ki_pri.pri_level - (int)(a)->ki_pri.pri_level; \ 885233294Sstas if (diff != 0) \ 88672445Sassar return (diff > 0 ? 1 : -1); \ 88755682Smarkm} while (0) 88855682Smarkm 88990926Snectar#define ORDERKEY_THREADS(a, b) do { \ 890127808Snectar int diff = (int)(b)->ki_numthreads - (int)(a)->ki_numthreads; \ 89190926Snectar if (diff != 0) \ 89255682Smarkm return (diff > 0 ? 1 : -1); \ 89355682Smarkm} while (0) 89455682Smarkm 89590926Snectar#define ORDERKEY_RSSIZE(a, b) do { \ 89690926Snectar long diff = (long)(b)->ki_rssize - (long)(a)->ki_rssize; \ 897233294Sstas if (diff != 0) \ 898178825Sdfr return (diff > 0 ? 1 : -1); \ 899142403Snectar} while (0) 90090926Snectar 90155682Smarkm#define ORDERKEY_MEM(a, b) do { \ 90255682Smarkm long diff = (long)PROCSIZE((b)) - (long)PROCSIZE((a)); \ 90390926Snectar if (diff != 0) \ 90455682Smarkm return (diff > 0 ? 1 : -1); \ 90555682Smarkm} while (0) 90655682Smarkm 90790926Snectar/* compare_cpu - the comparison function for sorting by cpu percentage */ 90890926Snectar 90955682Smarkmint 91090926Snectar#ifdef ORDER 911127808Snectarcompare_cpu(void *arg1, void *arg2) 91290926Snectar#else 91390926Snectarproc_compare(void *arg1, void *arg2) 91455682Smarkm#endif 91555682Smarkm{ 91655682Smarkm struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 917178825Sdfr struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 91855682Smarkm 91955682Smarkm ORDERKEY_PCTCPU(p1, p2); 920178825Sdfr ORDERKEY_CPTICKS(p1, p2); 921233294Sstas ORDERKEY_STATE(p1, p2); 92255682Smarkm ORDERKEY_PRIO(p1, p2); 92355682Smarkm ORDERKEY_RSSIZE(p1, p2); 92490926Snectar ORDERKEY_MEM(p1, p2); 92590926Snectar 92690926Snectar return (0); 92755682Smarkm} 928178825Sdfr 929178825Sdfr#ifdef ORDER 93055682Smarkm/* "cpu" compare routines */ 93190926Snectarint compare_size(), compare_res(), compare_time(), compare_prio(), 932233294Sstas compare_threads(); 933127808Snectar 93490926Snectar/* 935178825Sdfr * "io" compare routines. Context switches aren't i/o, but are displayed 93655682Smarkm * on the "io" display. 93790926Snectar */ 93855682Smarkmint compare_iototal(), compare_ioread(), compare_iowrite(), compare_iofault(), 93990926Snectar compare_vcsw(), compare_ivcsw(); 94055682Smarkm 941142403Snectarint (*compares[])() = { 942142403Snectar compare_cpu, 943233294Sstas compare_size, 944233294Sstas compare_res, 94590926Snectar compare_time, 94655682Smarkm compare_prio, 94790926Snectar compare_threads, 94890926Snectar compare_iototal, 949120945Snectar compare_ioread, 950120945Snectar compare_iowrite, 951120945Snectar compare_iofault, 952178825Sdfr compare_vcsw, 953178825Sdfr compare_ivcsw, 954233294Sstas NULL 955233294Sstas}; 956178825Sdfr 95790926Snectar/* compare_size - the comparison function for sorting by total memory usage */ 95890926Snectar 959178825Sdfrint 960178825Sdfrcompare_size(void *arg1, void *arg2) 961233294Sstas{ 962233294Sstas struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 96390926Snectar struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 96490926Snectar 965233294Sstas ORDERKEY_MEM(p1, p2); 96690926Snectar ORDERKEY_RSSIZE(p1, p2); 967233294Sstas ORDERKEY_PCTCPU(p1, p2); 968233294Sstas ORDERKEY_CPTICKS(p1, p2); 969178825Sdfr ORDERKEY_STATE(p1, p2); 970178825Sdfr ORDERKEY_PRIO(p1, p2); 971233294Sstas 972233294Sstas return (0); 973178825Sdfr} 974178825Sdfr 975233294Sstas/* compare_res - the comparison function for sorting by resident set size */ 976233294Sstas 97790926Snectarint 97890926Snectarcompare_res(void *arg1, void *arg2) 97955682Smarkm{ 980233294Sstas struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 981127808Snectar struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 98290926Snectar 98355682Smarkm ORDERKEY_RSSIZE(p1, p2); 98490926Snectar ORDERKEY_MEM(p1, p2); 98555682Smarkm ORDERKEY_PCTCPU(p1, p2); 98690926Snectar ORDERKEY_CPTICKS(p1, p2); 98790926Snectar ORDERKEY_STATE(p1, p2); 98890926Snectar ORDERKEY_PRIO(p1, p2); 989127808Snectar 990127808Snectar return (0); 991127808Snectar} 992127808Snectar 993127808Snectar/* compare_time - the comparison function for sorting by total cpu time */ 994127808Snectar 995127808Snectarint 996127808Snectarcompare_time(void *arg1, void *arg2) 997178825Sdfr{ 998178825Sdfr struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 999178825Sdfr struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1000178825Sdfr 1001233294Sstas ORDERKEY_CPTICKS(p1, p2); 100290926Snectar ORDERKEY_PCTCPU(p1, p2); 1003233294Sstas ORDERKEY_STATE(p1, p2); 1004233294Sstas ORDERKEY_PRIO(p1, p2); 100590926Snectar ORDERKEY_RSSIZE(p1, p2); 1006127808Snectar ORDERKEY_MEM(p1, p2); 1007178825Sdfr 1008178825Sdfr return (0); 1009178825Sdfr} 1010178825Sdfr 1011178825Sdfr/* compare_prio - the comparison function for sorting by priority */ 1012178825Sdfr 1013178825Sdfrint 1014178825Sdfrcompare_prio(void *arg1, void *arg2) 1015233294Sstas{ 1016233294Sstas struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1017233294Sstas struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1018233294Sstas 1019233294Sstas ORDERKEY_PRIO(p1, p2); 1020233294Sstas ORDERKEY_CPTICKS(p1, p2); 1021233294Sstas ORDERKEY_PCTCPU(p1, p2); 1022233294Sstas ORDERKEY_STATE(p1, p2); 102390926Snectar ORDERKEY_RSSIZE(p1, p2); 102490926Snectar ORDERKEY_MEM(p1, p2); 102555682Smarkm 102655682Smarkm return (0); 102755682Smarkm} 102855682Smarkm 102955682Smarkm/* compare_threads - the comparison function for sorting by threads */ 103072445Sassarint 103172445Sassarcompare_threads(void *arg1, void *arg2) 103272445Sassar{ 103372445Sassar struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 103455682Smarkm struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 103555682Smarkm 103655682Smarkm ORDERKEY_THREADS(p1, p2); 1037178825Sdfr ORDERKEY_PCTCPU(p1, p2); 1038178825Sdfr ORDERKEY_CPTICKS(p1, p2); 103955682Smarkm ORDERKEY_STATE(p1, p2); 104055682Smarkm ORDERKEY_PRIO(p1, p2); 104155682Smarkm ORDERKEY_RSSIZE(p1, p2); 104255682Smarkm ORDERKEY_MEM(p1, p2); 104355682Smarkm 104455682Smarkm return (0); 104572445Sassar} 104672445Sassar#endif /* ORDER */ 104755682Smarkm 1048178825Sdfr/* assorted comparison functions for sorting by i/o */ 1049178825Sdfr 1050178825Sdfrint 1051178825Sdfr#ifdef ORDER 1052178825Sdfrcompare_iototal(void *arg1, void *arg2) 1053178825Sdfr#else 1054178825Sdfrio_compare(void *arg1, void *arg2) 1055178825Sdfr#endif 1056178825Sdfr{ 1057178825Sdfr struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1058178825Sdfr struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 105955682Smarkm 106055682Smarkm return (get_io_total(p2) - get_io_total(p1)); 106155682Smarkm} 1062102644Snectar 1063102644Snectar#ifdef ORDER 1064178825Sdfrint 1065178825Sdfrcompare_ioread(void *arg1, void *arg2) 1066102644Snectar{ 1067102644Snectar struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1068102644Snectar struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1069102644Snectar long dummy, inp1, inp2; 1070102644Snectar 1071102644Snectar (void) get_io_stats(p1, &inp1, &dummy, &dummy, &dummy, &dummy); 1072178825Sdfr (void) get_io_stats(p2, &inp2, &dummy, &dummy, &dummy, &dummy); 1073102644Snectar 1074102644Snectar return (inp2 - inp1); 1075102644Snectar} 1076102644Snectar 1077102644Snectarint 1078102644Snectarcompare_iowrite(void *arg1, void *arg2) 1079102644Snectar{ 1080102644Snectar struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1081102644Snectar struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1082102644Snectar long dummy, oup1, oup2; 1083102644Snectar 1084102644Snectar (void) get_io_stats(p1, &dummy, &oup1, &dummy, &dummy, &dummy); 1085102644Snectar (void) get_io_stats(p2, &dummy, &oup2, &dummy, &dummy, &dummy); 1086102644Snectar 1087102644Snectar return (oup2 - oup1); 1088178825Sdfr} 1089102644Snectar 1090102644Snectarint 1091102644Snectarcompare_iofault(void *arg1, void *arg2) 1092102644Snectar{ 1093233294Sstas struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1094233294Sstas struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1095233294Sstas long dummy, flp1, flp2; 109655682Smarkm 109755682Smarkm (void) get_io_stats(p1, &dummy, &dummy, &flp1, &dummy, &dummy); 109855682Smarkm (void) get_io_stats(p2, &dummy, &dummy, &flp2, &dummy, &dummy); 109955682Smarkm 110055682Smarkm return (flp2 - flp1); 110155682Smarkm} 110255682Smarkm 110355682Smarkmint 110455682Smarkmcompare_vcsw(void *arg1, void *arg2) 110555682Smarkm{ 110655682Smarkm struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 110755682Smarkm struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 110855682Smarkm long dummy, flp1, flp2; 110955682Smarkm 111055682Smarkm (void) get_io_stats(p1, &dummy, &dummy, &dummy, &flp1, &dummy); 111155682Smarkm (void) get_io_stats(p2, &dummy, &dummy, &dummy, &flp2, &dummy); 111255682Smarkm 111355682Smarkm return (flp2 - flp1); 111455682Smarkm} 111555682Smarkm 111655682Smarkmint 111755682Smarkmcompare_ivcsw(void *arg1, void *arg2) 111855682Smarkm{ 111955682Smarkm struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 112055682Smarkm struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 112155682Smarkm long dummy, flp1, flp2; 112255682Smarkm 112355682Smarkm (void) get_io_stats(p1, &dummy, &dummy, &dummy, &dummy, &flp1); 112455682Smarkm (void) get_io_stats(p2, &dummy, &dummy, &dummy, &dummy, &flp2); 112555682Smarkm 112655682Smarkm return (flp2 - flp1); 112755682Smarkm} 112855682Smarkm#endif /* ORDER */ 112955682Smarkm 113055682Smarkm/* 113155682Smarkm * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 113255682Smarkm * the process does not exist. 113355682Smarkm * It is EXTREMLY IMPORTANT that this function work correctly. 113455682Smarkm * If top runs setuid root (as in SVR4), then this function 113555682Smarkm * is the only thing that stands in the way of a serious 113655682Smarkm * security problem. It validates requests for the "kill" 113755682Smarkm * and "renice" commands. 113855682Smarkm */ 113955682Smarkm 114055682Smarkmint 114155682Smarkmproc_owner(int pid) 114255682Smarkm{ 114355682Smarkm int cnt; 114455682Smarkm struct kinfo_proc **prefp; 114555682Smarkm struct kinfo_proc *pp; 114655682Smarkm 114755682Smarkm prefp = pref; 114855682Smarkm cnt = pref_len; 114955682Smarkm while (--cnt >= 0) { 115055682Smarkm pp = *prefp++; 115155682Smarkm if (pp->ki_pid == (pid_t)pid) 115255682Smarkm return ((int)pp->ki_ruid); 115355682Smarkm } 115455682Smarkm return (-1); 115555682Smarkm} 115655682Smarkm 115755682Smarkmstatic int 115855682Smarkmswapmode(int *retavail, int *retfree) 115955682Smarkm{ 116072445Sassar int n; 1161178825Sdfr int pagesize = getpagesize(); 116255682Smarkm struct kvm_swap swapary[1]; 1163178825Sdfr 1164178825Sdfr *retavail = 0; 1165178825Sdfr *retfree = 0; 1166120945Snectar 1167178825Sdfr#define CONVERT(v) ((quad_t)(v) * pagesize / 1024) 116855682Smarkm 116955682Smarkm n = kvm_getswapinfo(kd, swapary, 1, 0); 117055682Smarkm if (n < 0 || swapary[0].ksw_total == 0) 117155682Smarkm return (0); 117255682Smarkm 117355682Smarkm *retavail = CONVERT(swapary[0].ksw_total); 1174178825Sdfr *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); 1175178825Sdfr 1176178825Sdfr n = (int)(swapary[0].ksw_used * 100.0 / swapary[0].ksw_total); 1177178825Sdfr return (n); 1178178825Sdfr} 1179178825Sdfr