machine.c revision 168710
124143Sjoerg/* 224143Sjoerg * top - a top users display for Unix 324143Sjoerg * 447901Sn_hibma * SYNOPSIS: For FreeBSD-2.x and later 524143Sjoerg * 624143Sjoerg * DESCRIPTION: 724143Sjoerg * Originally written for BSD4.4 system by Christos Zoulas. 824143Sjoerg * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider 938278Swosch * Order support hacked in from top-3.5beta6/machine/m_aix41.c 1038278Swosch * by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/) 1124143Sjoerg * 1224143Sjoerg * This is the machine-dependent module for FreeBSD 2.2 1324143Sjoerg * Works for: 1447901Sn_hibma * FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x 1524143Sjoerg * 1624143Sjoerg * LIBS: -lkvm 1724143Sjoerg * 1824143Sjoerg * AUTHOR: Christos Zoulas <christos@ee.cornell.edu> 1924143Sjoerg * Steven Wallace <swallace@freebsd.org> 2024143Sjoerg * Wolfram Schneider <wosch@FreeBSD.org> 2172951Srwatson * Thomas Moestl <tmoestl@gmx.net> 2224143Sjoerg * 2350477Speter * $FreeBSD: head/usr.bin/top/machine.c 168710 2007-04-14 10:16:52Z stas $ 2424143Sjoerg */ 2524143Sjoerg 2624143Sjoerg#include <sys/param.h> 2724143Sjoerg#include <sys/errno.h> 28131621Sdes#include <sys/file.h> 29131621Sdes#include <sys/proc.h> 30131621Sdes#include <sys/resource.h> 31131621Sdes#include <sys/rtprio.h> 32131621Sdes#include <sys/signal.h> 3324143Sjoerg#include <sys/sysctl.h> 3424143Sjoerg#include <sys/time.h> 3524143Sjoerg#include <sys/user.h> 3624143Sjoerg#include <sys/vmmeter.h> 3724143Sjoerg 38131621Sdes#include <kvm.h> 39131621Sdes#include <math.h> 40131621Sdes#include <nlist.h> 41131626Sdes#include <paths.h> 42131621Sdes#include <pwd.h> 43131621Sdes#include <stdio.h> 4424143Sjoerg#include <stdlib.h> 45144636Sstefanf#include <string.h> 46144636Sstefanf#include <strings.h> 4772951Srwatson#include <unistd.h> 48168710Sstas#include <vis.h> 4924143Sjoerg 5024143Sjoerg#include "top.h" 5124143Sjoerg#include "machine.h" 5269375Sjhb#include "screen.h" 5372951Srwatson#include "utils.h" 5424143Sjoerg 5572951Srwatson#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) 56146291Sobrien#define SMPUNAMELEN 13 57146291Sobrien#define UPUNAMELEN 15 5872951Srwatson 59145073Skeramidaextern struct process_select ps; 6092922Simpextern char* printable(char *); 6127340Speterstatic int smpmode; 62131402Salfredenum displaymodes displaymode; 63146291Sobrienstatic int namelength = 8; 6469375Sjhbstatic int cmdlengthdelta; 6524143Sjoerg 6672951Srwatson/* Prototypes for top internals */ 6792922Simpvoid quit(int); 6824143Sjoerg 6924143Sjoerg/* get_process_info passes back a handle. This is what it looks like: */ 7024143Sjoerg 71158280Sbdestruct handle { 72131623Sdes struct kinfo_proc **next_proc; /* points to next valid proc pointer */ 73131623Sdes int remaining; /* number of pointers remaining */ 7424143Sjoerg}; 7524143Sjoerg 7624143Sjoerg/* declarations for load_avg */ 7724143Sjoerg#include "loadavg.h" 7824143Sjoerg 7924143Sjoerg/* define what weighted cpu is. */ 8069896Smckusick#define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \ 8169896Smckusick ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu)))) 8224143Sjoerg 8324143Sjoerg/* what we consider to be process size: */ 8469896Smckusick#define PROCSIZE(pp) ((pp)->ki_size / 1024) 8524143Sjoerg 86131402Salfred#define RU(pp) (&(pp)->ki_rusage) 87131402Salfred#define RUTOT(pp) \ 88131402Salfred (RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt) 89131402Salfred 90131402Salfred 9124143Sjoerg/* definitions for indices in the nlist array */ 9224143Sjoerg 9324143Sjoerg/* 9424143Sjoerg * These definitions control the format of the per-process area 9524143Sjoerg */ 9624143Sjoerg 97131402Salfredstatic char io_header[] = 98158280Sbde " PID %-*.*s VCSW IVCSW READ WRITE FAULT TOTAL PERCENT COMMAND"; 99131402Salfred 100131402Salfred#define io_Proc_format \ 101158280Sbde "%5d %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s" 102131402Salfred 103145073Skeramidastatic char smp_header_thr[] = 104158280Sbde " PID %-*.*s THR PRI NICE SIZE RES STATE C TIME %6s COMMAND"; 10527340Speterstatic char smp_header[] = 106158280Sbde " PID %-*.*s " "PRI NICE SIZE RES STATE C TIME %6s COMMAND"; 10724143Sjoerg 10827340Speter#define smp_Proc_format \ 109158282Sbde "%5d %-*.*s %s%3d %4s%7s %6s %-6.6s %1x%7s %5.2f%% %.*s" 11024143Sjoerg 111145073Skeramidastatic char up_header_thr[] = 112158280Sbde " PID %-*.*s THR PRI NICE SIZE RES STATE TIME %6s COMMAND"; 11327340Speterstatic char up_header[] = 114158280Sbde " PID %-*.*s " "PRI NICE SIZE RES STATE TIME %6s COMMAND"; 11524143Sjoerg 11627340Speter#define up_Proc_format \ 117158282Sbde "%5d %-*.*s %s%3d %4s%7s %6s %-6.6s%.0d%7s %5.2f%% %.*s" 11824143Sjoerg 11924143Sjoerg 12024143Sjoerg/* process state names for the "STATE" column of the display */ 12124143Sjoerg/* the extra nulls in the string "run" are for adding a slash and 12224143Sjoerg the processor number when needed */ 12324143Sjoerg 124158280Sbdechar *state_abbrev[] = { 125131623Sdes "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK" 12624143Sjoerg}; 12724143Sjoerg 12824143Sjoerg 12924143Sjoergstatic kvm_t *kd; 13024143Sjoerg 13124143Sjoerg/* values that we stash away in _init and use in later routines */ 13224143Sjoerg 13324143Sjoergstatic double logcpu; 13424143Sjoerg 13524143Sjoerg/* these are retrieved from the kernel in _init */ 13624143Sjoerg 13724143Sjoergstatic load_avg ccpu; 13824143Sjoerg 13972951Srwatson/* these are used in the get_ functions */ 14024143Sjoerg 14172951Srwatsonstatic int lastpid; 14224143Sjoerg 14324143Sjoerg/* these are for calculating cpu state percentages */ 14424143Sjoerg 14524143Sjoergstatic long cp_time[CPUSTATES]; 14624143Sjoergstatic long cp_old[CPUSTATES]; 14724143Sjoergstatic long cp_diff[CPUSTATES]; 14824143Sjoerg 14924143Sjoerg/* these are for detailing the process states */ 15024143Sjoerg 15165557Sjasoneint process_states[8]; 15224143Sjoergchar *procstatenames[] = { 153131623Sdes "", " starting, ", " running, ", " sleeping, ", " stopped, ", 154131623Sdes " zombie, ", " waiting, ", " lock, ", 155131623Sdes NULL 15624143Sjoerg}; 15724143Sjoerg 15824143Sjoerg/* these are for detailing the cpu states */ 15924143Sjoerg 16024143Sjoergint cpu_states[CPUSTATES]; 16124143Sjoergchar *cpustatenames[] = { 162131623Sdes "user", "nice", "system", "interrupt", "idle", NULL 16324143Sjoerg}; 16424143Sjoerg 16524143Sjoerg/* these are for detailing the memory statistics */ 16624143Sjoerg 16724143Sjoergint memory_stats[7]; 16824143Sjoergchar *memorynames[] = { 169158280Sbde "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", 170158280Sbde "K Free", NULL 17124143Sjoerg}; 17224143Sjoerg 17324143Sjoergint swap_stats[7]; 17424143Sjoergchar *swapnames[] = { 175131623Sdes "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", 176131623Sdes NULL 17724143Sjoerg}; 17824143Sjoerg 17924143Sjoerg 18024143Sjoerg/* these are for keeping track of the proc array */ 18124143Sjoerg 18224143Sjoergstatic int nproc; 18324143Sjoergstatic int onproc = -1; 18424143Sjoergstatic int pref_len; 18524143Sjoergstatic struct kinfo_proc *pbase; 18624143Sjoergstatic struct kinfo_proc **pref; 187131402Salfredstatic struct kinfo_proc *previous_procs; 188131402Salfredstatic struct kinfo_proc **previous_pref; 189131402Salfredstatic int previous_proc_count = 0; 190131402Salfredstatic int previous_proc_count_max = 0; 19124143Sjoerg 192131412Salfred/* total number of io operations */ 193131412Salfredstatic long total_inblock; 194131412Salfredstatic long total_oublock; 195131412Salfredstatic long total_majflt; 196131412Salfred 19724143Sjoerg/* these are for getting the memory statistics */ 19824143Sjoerg 19924143Sjoergstatic int pageshift; /* log base 2 of the pagesize */ 20024143Sjoerg 20124143Sjoerg/* define pagetok in terms of pageshift */ 20224143Sjoerg 20324143Sjoerg#define pagetok(size) ((size) << pageshift) 20424143Sjoerg 20524143Sjoerg/* useful externals */ 20624143Sjoerglong percentages(); 20724143Sjoerg 20838278Swosch#ifdef ORDER 209131829Skeramida/* 210145073Skeramida * Sorting orders. The first element is the default. 211131829Skeramida */ 212133817Salfredchar *ordernames[] = { 213145073Skeramida "cpu", "size", "res", "time", "pri", "threads", 214133817Salfred "total", "read", "write", "fault", "vcsw", "ivcsw", NULL 21538278Swosch}; 21638278Swosch#endif 21738278Swosch 218158282Sbdestatic int compare_pid(const void *a, const void *b); 219158282Sbdestatic const char *format_nice(const struct kinfo_proc *pp); 220158282Sbdestatic void getsysctl(const char *name, void *ptr, size_t len); 221158282Sbdestatic int swapmode(int *retavail, int *retfree); 222158282Sbde 22324143Sjoergint 224131622Sdesmachine_init(struct statics *statics) 22524143Sjoerg{ 226131623Sdes int pagesize; 227131623Sdes size_t modelen; 228131623Sdes struct passwd *pw; 22924143Sjoerg 230131623Sdes modelen = sizeof(smpmode); 231158280Sbde if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, 232158280Sbde NULL, 0) != 0 && 233158280Sbde sysctlbyname("kern.smp.active", &smpmode, &modelen, 234158280Sbde NULL, 0) != 0) || 235131623Sdes modelen != sizeof(smpmode)) 236131623Sdes smpmode = 0; 23727340Speter 238131623Sdes while ((pw = getpwent()) != NULL) { 239131623Sdes if (strlen(pw->pw_name) > namelength) 240131623Sdes namelength = strlen(pw->pw_name); 241131623Sdes } 242146291Sobrien if (smpmode && namelength > SMPUNAMELEN) 243146291Sobrien namelength = SMPUNAMELEN; 244146291Sobrien else if (namelength > UPUNAMELEN) 245146291Sobrien namelength = UPUNAMELEN; 24627390Speter 247131626Sdes kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); 248131626Sdes if (kd == NULL) 249131626Sdes return (-1); 25024143Sjoerg 251131623Sdes GETSYSCTL("kern.ccpu", ccpu); 25224143Sjoerg 253131623Sdes /* this is used in calculating WCPU -- calculate it ahead of time */ 254131623Sdes logcpu = log(loaddouble(ccpu)); 25524143Sjoerg 256131623Sdes pbase = NULL; 257131623Sdes pref = NULL; 258131623Sdes nproc = 0; 259131623Sdes onproc = -1; 260158280Sbde 261158280Sbde /* get the page size and calculate pageshift from it */ 262131623Sdes pagesize = getpagesize(); 263131623Sdes pageshift = 0; 264131626Sdes while (pagesize > 1) { 265131623Sdes pageshift++; 266131623Sdes pagesize >>= 1; 267131623Sdes } 26824143Sjoerg 269131623Sdes /* we only need the amount of log(2)1024 for our conversion */ 270131623Sdes pageshift -= LOG1024; 27124143Sjoerg 272131623Sdes /* fill in the statics information */ 273131623Sdes statics->procstate_names = procstatenames; 274131623Sdes statics->cpustate_names = cpustatenames; 275131623Sdes statics->memory_names = memorynames; 276131623Sdes statics->swap_names = swapnames; 27738278Swosch#ifdef ORDER 278133817Salfred statics->order_names = ordernames; 27938278Swosch#endif 28024143Sjoerg 281131623Sdes /* all done! */ 282131623Sdes return (0); 28324143Sjoerg} 28424143Sjoerg 285131310Salfredchar * 286131622Sdesformat_header(char *uname_field) 28724143Sjoerg{ 288131623Sdes static char Header[128]; 289131623Sdes const char *prehead; 29024143Sjoerg 291131623Sdes switch (displaymode) { 292131623Sdes case DISP_CPU: 293145073Skeramida /* 294145073Skeramida * The logic of picking the right header format seems reverse 295145073Skeramida * here because we only want to display a THR column when 296145073Skeramida * "thread mode" is off (and threads are not listed as 297145073Skeramida * separate lines). 298145073Skeramida */ 299145073Skeramida prehead = smpmode ? 300145073Skeramida (ps.thread ? smp_header : smp_header_thr) : 301145073Skeramida (ps.thread ? up_header : up_header_thr); 302146342Skeramida snprintf(Header, sizeof(Header), prehead, 303146342Skeramida namelength, namelength, uname_field, 304146342Skeramida ps.wcpu ? "WCPU" : "CPU"); 305131623Sdes break; 306131623Sdes case DISP_IO: 307131623Sdes prehead = io_header; 308146342Skeramida snprintf(Header, sizeof(Header), prehead, 309146342Skeramida namelength, namelength, uname_field); 310131623Sdes break; 311131623Sdes } 312131623Sdes cmdlengthdelta = strlen(Header) - 7; 313131623Sdes return (Header); 31424143Sjoerg} 31524143Sjoerg 31624143Sjoergstatic int swappgsin = -1; 31724143Sjoergstatic int swappgsout = -1; 31824143Sjoergextern struct timeval timeout; 31924143Sjoerg 32024143Sjoergvoid 321131622Sdesget_system_info(struct system_info *si) 32224143Sjoerg{ 323131623Sdes long total; 324131623Sdes struct loadavg sysload; 325131623Sdes int mib[2]; 326131623Sdes struct timeval boottime; 327131623Sdes size_t bt_size; 328131626Sdes int i; 32924143Sjoerg 330131623Sdes /* get the cp_time array */ 331131623Sdes GETSYSCTL("kern.cp_time", cp_time); 332131623Sdes GETSYSCTL("vm.loadavg", sysload); 333131623Sdes GETSYSCTL("kern.lastpid", lastpid); 33424143Sjoerg 335131623Sdes /* convert load averages to doubles */ 336131626Sdes for (i = 0; i < 3; i++) 337131626Sdes si->load_avg[i] = (double)sysload.ldavg[i] / sysload.fscale; 33824143Sjoerg 339131623Sdes /* convert cp_time counts to percentages */ 340131623Sdes total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 34124143Sjoerg 342131623Sdes /* sum memory & swap statistics */ 343131623Sdes { 344131623Sdes static unsigned int swap_delay = 0; 345131623Sdes static int swapavail = 0; 346131623Sdes static int swapfree = 0; 347131623Sdes static int bufspace = 0; 348131623Sdes static int nspgsin, nspgsout; 34924143Sjoerg 350131623Sdes GETSYSCTL("vfs.bufspace", bufspace); 351131623Sdes GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]); 352131623Sdes GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]); 353131623Sdes GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]); 354131623Sdes GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]); 355131623Sdes GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]); 356131623Sdes GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin); 357131623Sdes GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout); 358131623Sdes /* convert memory stats to Kbytes */ 359131623Sdes memory_stats[0] = pagetok(memory_stats[0]); 360131623Sdes memory_stats[1] = pagetok(memory_stats[1]); 361131623Sdes memory_stats[2] = pagetok(memory_stats[2]); 362131623Sdes memory_stats[3] = pagetok(memory_stats[3]); 363131623Sdes memory_stats[4] = bufspace / 1024; 364131623Sdes memory_stats[5] = pagetok(memory_stats[5]); 365131623Sdes memory_stats[6] = -1; 36624143Sjoerg 367131623Sdes /* first interval */ 368131623Sdes if (swappgsin < 0) { 369131623Sdes swap_stats[4] = 0; 370131623Sdes swap_stats[5] = 0; 371131623Sdes } 37224143Sjoerg 373131623Sdes /* compute differences between old and new swap statistic */ 374131623Sdes else { 375131623Sdes swap_stats[4] = pagetok(((nspgsin - swappgsin))); 376131623Sdes swap_stats[5] = pagetok(((nspgsout - swappgsout))); 377131623Sdes } 37824143Sjoerg 379131623Sdes swappgsin = nspgsin; 380131623Sdes swappgsout = nspgsout; 38124143Sjoerg 382131623Sdes /* call CPU heavy swapmode() only for changes */ 383131623Sdes if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) { 384131623Sdes swap_stats[3] = swapmode(&swapavail, &swapfree); 385131623Sdes swap_stats[0] = swapavail; 386131623Sdes swap_stats[1] = swapavail - swapfree; 387131623Sdes swap_stats[2] = swapfree; 388131623Sdes } 389131623Sdes swap_delay = 1; 390131623Sdes swap_stats[6] = -1; 39124143Sjoerg } 39224143Sjoerg 393131623Sdes /* set arrays and strings */ 394131623Sdes si->cpustates = cpu_states; 395131623Sdes si->memory = memory_stats; 396131623Sdes si->swap = swap_stats; 39724143Sjoerg 39824143Sjoerg 399131623Sdes if (lastpid > 0) { 400131623Sdes si->last_pid = lastpid; 401131623Sdes } else { 402131623Sdes si->last_pid = -1; 403131623Sdes } 40442447Sobrien 405131623Sdes /* 406131623Sdes * Print how long system has been up. 407131623Sdes * (Found by looking getting "boottime" from the kernel) 408131623Sdes */ 409131623Sdes mib[0] = CTL_KERN; 410131623Sdes mib[1] = KERN_BOOTTIME; 411131623Sdes bt_size = sizeof(boottime); 412131623Sdes if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 && 413131623Sdes boottime.tv_sec != 0) { 414131623Sdes si->boottime = boottime; 415131623Sdes } else { 416131623Sdes si->boottime.tv_sec = -1; 417131623Sdes } 41824143Sjoerg} 41924143Sjoerg 420132015Salfred#define NOPROC ((void *)-1) 421132015Salfred 422132955Salfred/* 423132955Salfred * We need to compare data from the old process entry with the new 424132955Salfred * process entry. 425132955Salfred * To facilitate doing this quickly we stash a pointer in the kinfo_proc 426132955Salfred * structure to cache the mapping. We also use a negative cache pointer 427132955Salfred * of NOPROC to avoid duplicate lookups. 428132955Salfred * XXX: this could be done when the actual processes are fetched, we do 429132955Salfred * it here out of laziness. 430132955Salfred */ 431131402Salfredconst struct kinfo_proc * 432131402Salfredget_old_proc(struct kinfo_proc *pp) 433131402Salfred{ 434131402Salfred struct kinfo_proc **oldpp, *oldp; 435131402Salfred 436132955Salfred /* 437132955Salfred * If this is the first fetch of the kinfo_procs then we don't have 438132955Salfred * any previous entries. 439132955Salfred */ 440131402Salfred if (previous_proc_count == 0) 441131402Salfred return (NULL); 442132955Salfred /* negative cache? */ 443132015Salfred if (pp->ki_udata == NOPROC) 444132015Salfred return (NULL); 445132955Salfred /* cached? */ 446132015Salfred if (pp->ki_udata != NULL) 447132015Salfred return (pp->ki_udata); 448132955Salfred /* 449132955Salfred * Not cached, 450132955Salfred * 1) look up based on pid. 451132955Salfred * 2) compare process start. 452132955Salfred * If we fail here, then setup a negative cache entry, otherwise 453132955Salfred * cache it. 454132955Salfred */ 455131402Salfred oldpp = bsearch(&pp, previous_pref, previous_proc_count, 456131626Sdes sizeof(*previous_pref), compare_pid); 457132015Salfred if (oldpp == NULL) { 458132015Salfred pp->ki_udata = NOPROC; 459131402Salfred return (NULL); 460132015Salfred } 461131402Salfred oldp = *oldpp; 462132015Salfred if (bcmp(&oldp->ki_start, &pp->ki_start, sizeof(pp->ki_start)) != 0) { 463132015Salfred pp->ki_udata = NOPROC; 464131402Salfred return (NULL); 465132015Salfred } 466132015Salfred pp->ki_udata = oldp; 467131402Salfred return (oldp); 468131402Salfred} 469131402Salfred 470132955Salfred/* 471132955Salfred * Return the total amount of IO done in blocks in/out and faults. 472132955Salfred * store the values individually in the pointers passed in. 473132955Salfred */ 474131402Salfredlong 475158280Sbdeget_io_stats(struct kinfo_proc *pp, long *inp, long *oup, long *flp, 476158280Sbde long *vcsw, long *ivcsw) 477131402Salfred{ 478131402Salfred const struct kinfo_proc *oldp; 479131402Salfred static struct kinfo_proc dummy; 480131402Salfred long ret; 481131402Salfred 482131402Salfred oldp = get_old_proc(pp); 483131402Salfred if (oldp == NULL) { 484131402Salfred bzero(&dummy, sizeof(dummy)); 485131402Salfred oldp = &dummy; 486131402Salfred } 487131412Salfred *inp = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; 488131412Salfred *oup = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; 489131412Salfred *flp = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; 490133817Salfred *vcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; 491133817Salfred *ivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; 492131402Salfred ret = 493131402Salfred (RU(pp)->ru_inblock - RU(oldp)->ru_inblock) + 494131402Salfred (RU(pp)->ru_oublock - RU(oldp)->ru_oublock) + 495131402Salfred (RU(pp)->ru_majflt - RU(oldp)->ru_majflt); 496131402Salfred return (ret); 497131402Salfred} 498131402Salfred 499132955Salfred/* 500132955Salfred * Return the total number of block in/out and faults by a process. 501132955Salfred */ 502131412Salfredlong 503131412Salfredget_io_total(struct kinfo_proc *pp) 504131412Salfred{ 505131412Salfred long dummy; 506131412Salfred 507133817Salfred return (get_io_stats(pp, &dummy, &dummy, &dummy, &dummy, &dummy)); 508131412Salfred} 509131412Salfred 51024143Sjoergstatic struct handle handle; 51124143Sjoerg 512131310Salfredcaddr_t 513131622Sdesget_process_info(struct system_info *si, struct process_select *sel, 514131626Sdes int (*compare)(const void *, const void *)) 51524143Sjoerg{ 516131623Sdes int i; 517131623Sdes int total_procs; 518131623Sdes long p_io; 519133817Salfred long p_inblock, p_oublock, p_majflt, p_vcsw, p_ivcsw; 520131623Sdes int active_procs; 521131623Sdes struct kinfo_proc **prefp; 522131623Sdes struct kinfo_proc *pp; 523131623Sdes struct kinfo_proc *prev_pp = NULL; 52424143Sjoerg 525131623Sdes /* these are copied out of sel for speed */ 526131623Sdes int show_idle; 527131623Sdes int show_self; 528131623Sdes int show_system; 529131623Sdes int show_uid; 530131623Sdes int show_command; 53124143Sjoerg 532131623Sdes /* 533131623Sdes * Save the previous process info. 534131623Sdes */ 535131623Sdes if (previous_proc_count_max < nproc) { 536131623Sdes free(previous_procs); 537131626Sdes previous_procs = malloc(nproc * sizeof(*previous_procs)); 538131623Sdes free(previous_pref); 539131626Sdes previous_pref = malloc(nproc * sizeof(*previous_pref)); 540131623Sdes if (previous_procs == NULL || previous_pref == NULL) { 541131623Sdes (void) fprintf(stderr, "top: Out of memory.\n"); 542131623Sdes quit(23); 543131623Sdes } 544131623Sdes previous_proc_count_max = nproc; 545131623Sdes } 546131623Sdes if (nproc) { 547131623Sdes for (i = 0; i < nproc; i++) 548131623Sdes previous_pref[i] = &previous_procs[i]; 549131626Sdes bcopy(pbase, previous_procs, nproc * sizeof(*previous_procs)); 550158280Sbde qsort(previous_pref, nproc, sizeof(*previous_pref), 551158280Sbde compare_pid); 552131623Sdes } 553131623Sdes previous_proc_count = nproc; 554131402Salfred 555131623Sdes pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc); 556131623Sdes if (nproc > onproc) 557131626Sdes pref = realloc(pref, sizeof(*pref) * (onproc = nproc)); 558131623Sdes if (pref == NULL || pbase == NULL) { 559131623Sdes (void) fprintf(stderr, "top: Out of memory.\n"); 560131623Sdes quit(23); 561131623Sdes } 562131623Sdes /* get a pointer to the states summary array */ 563131623Sdes si->procstates = process_states; 56424143Sjoerg 565131623Sdes /* set up flags which define what we are going to select */ 566131623Sdes show_idle = sel->idle; 567132024Sdes show_self = sel->self == -1; 568131623Sdes show_system = sel->system; 569131623Sdes show_uid = sel->uid != -1; 570131623Sdes show_command = sel->command != NULL; 57124143Sjoerg 572131623Sdes /* count up process states and get pointers to interesting procs */ 573131623Sdes total_procs = 0; 574131623Sdes active_procs = 0; 575131623Sdes total_inblock = 0; 576131623Sdes total_oublock = 0; 577131623Sdes total_majflt = 0; 578131623Sdes memset((char *)process_states, 0, sizeof(process_states)); 579131623Sdes prefp = pref; 580131626Sdes for (pp = pbase, i = 0; i < nproc; pp++, i++) { 581131619Sdes 582131623Sdes if (pp->ki_stat == 0) 583132024Sdes /* not in use */ 584132024Sdes continue; 585131619Sdes 586131623Sdes if (!show_self && pp->ki_pid == sel->self) 587131623Sdes /* skip self */ 588131623Sdes continue; 589131619Sdes 590131623Sdes if (!show_system && (pp->ki_flag & P_SYSTEM)) 591131623Sdes /* skip system process */ 592131623Sdes continue; 593131619Sdes 594158280Sbde p_io = get_io_stats(pp, &p_inblock, &p_oublock, &p_majflt, 595158280Sbde &p_vcsw, &p_ivcsw); 596131623Sdes total_inblock += p_inblock; 597131623Sdes total_oublock += p_oublock; 598131623Sdes total_majflt += p_majflt; 599131623Sdes total_procs++; 600131626Sdes process_states[pp->ki_stat]++; 601131619Sdes 602131623Sdes if (pp->ki_stat == SZOMB) 603131623Sdes /* skip zombies */ 604131623Sdes continue; 605131619Sdes 606131623Sdes if (displaymode == DISP_CPU && !show_idle && 607159520Sse (pp->ki_pctcpu == 0 || 608159520Sse pp->ki_stat == SSTOP || pp->ki_stat == SIDL)) 609131623Sdes /* skip idle or non-running processes */ 610131623Sdes continue; 611131619Sdes 612131623Sdes if (displaymode == DISP_IO && !show_idle && p_io == 0) 613131623Sdes /* skip processes that aren't doing I/O */ 614131623Sdes continue; 615131619Sdes 616131623Sdes if (show_uid && pp->ki_ruid != (uid_t)sel->uid) 617158280Sbde /* skip proc. that don't belong to the selected UID */ 618131623Sdes continue; 619131619Sdes 620131623Sdes /* 621131623Sdes * When not showing threads, take the first thread 622131623Sdes * for output and add the fields that we can from 623131623Sdes * the rest of the process's threads rather than 624131623Sdes * using the system's mostly-broken KERN_PROC_PROC. 625131623Sdes */ 626131626Sdes if (sel->thread || prev_pp == NULL || 627131626Sdes prev_pp->ki_pid != pp->ki_pid) { 628131623Sdes *prefp++ = pp; 629131623Sdes active_procs++; 630131623Sdes prev_pp = pp; 631131623Sdes } else { 632131623Sdes prev_pp->ki_pctcpu += pp->ki_pctcpu; 633131623Sdes } 634131623Sdes } 635131623Sdes 636131623Sdes /* if requested, sort the "interesting" processes */ 637131623Sdes if (compare != NULL) 638131626Sdes qsort(pref, active_procs, sizeof(*pref), compare); 63924143Sjoerg 640131623Sdes /* remember active and total counts */ 641131623Sdes si->p_total = total_procs; 642131623Sdes si->p_active = pref_len = active_procs; 64324143Sjoerg 644131623Sdes /* pass back a handle */ 645131623Sdes handle.next_proc = pref; 646131623Sdes handle.remaining = active_procs; 647131623Sdes return ((caddr_t)&handle); 64824143Sjoerg} 64924143Sjoerg 650131626Sdesstatic char fmt[128]; /* static area where result is built */ 65124143Sjoerg 652131310Salfredchar * 653168710Sstasformat_next_process(caddr_t handle, char *(*get_userid)(int), int flags) 65424143Sjoerg{ 655131623Sdes struct kinfo_proc *pp; 656131623Sdes const struct kinfo_proc *oldp; 657131623Sdes long cputime; 658131623Sdes double pct; 659131623Sdes struct handle *hp; 660131623Sdes char status[16]; 661131623Sdes int state; 662131623Sdes struct rusage ru, *rup; 663131623Sdes long p_tot, s_tot; 664145155Skeramida char *proc_fmt, thr_buf[6]; 665168710Sstas char *cmdbuf = NULL; 666168710Sstas char **args; 66724143Sjoerg 668131623Sdes /* find and remember the next proc structure */ 669131623Sdes hp = (struct handle *)handle; 670131623Sdes pp = *(hp->next_proc++); 671131623Sdes hp->remaining--; 672131620Sdes 673131623Sdes /* get the process's command name */ 674131623Sdes if ((pp->ki_sflag & PS_INMEM) == 0) { 675131623Sdes /* 676131623Sdes * Print swapped processes as <pname> 677131623Sdes */ 678158280Sbde size_t len; 679158280Sbde 680158280Sbde len = strlen(pp->ki_comm); 681131626Sdes if (len > sizeof(pp->ki_comm) - 3) 682131626Sdes len = sizeof(pp->ki_comm) - 3; 683131626Sdes memmove(pp->ki_comm + 1, pp->ki_comm, len); 684131626Sdes pp->ki_comm[0] = '<'; 685131626Sdes pp->ki_comm[len + 1] = '>'; 686131626Sdes pp->ki_comm[len + 2] = '\0'; 687131623Sdes } 688131623Sdes 68924143Sjoerg /* 690131623Sdes * Convert the process's runtime from microseconds to seconds. This 691131623Sdes * time includes the interrupt time although that is not wanted here. 692131623Sdes * ps(1) is similarly sloppy. 69324143Sjoerg */ 694131623Sdes cputime = (pp->ki_runtime + 500000) / 1000000; 69524143Sjoerg 696131623Sdes /* calculate the base for cpu percentages */ 697131623Sdes pct = pctdouble(pp->ki_pctcpu); 69824143Sjoerg 699131623Sdes /* generate "STATE" field */ 700131623Sdes switch (state = pp->ki_stat) { 70124143Sjoerg case SRUN: 702131623Sdes if (smpmode && pp->ki_oncpu != 0xff) 703131623Sdes sprintf(status, "CPU%d", pp->ki_oncpu); 704131623Sdes else 705131623Sdes strcpy(status, "RUN"); 706131623Sdes break; 707104388Sjhb case SLOCK: 708131623Sdes if (pp->ki_kiflag & KI_LOCKBLOCK) { 709131623Sdes sprintf(status, "*%.6s", pp->ki_lockname); 710131623Sdes break; 711131623Sdes } 712131623Sdes /* fall through */ 71324143Sjoerg case SSLEEP: 714131623Sdes if (pp->ki_wmesg != NULL) { 715131623Sdes sprintf(status, "%.6s", pp->ki_wmesg); 716131623Sdes break; 717131623Sdes } 718131623Sdes /* FALLTHROUGH */ 71924143Sjoerg default: 72043720Sfenner 721131623Sdes if (state >= 0 && 722131623Sdes state < sizeof(state_abbrev) / sizeof(*state_abbrev)) 723131626Sdes sprintf(status, "%.6s", state_abbrev[state]); 724131623Sdes else 725131623Sdes sprintf(status, "?%5d", state); 726131623Sdes break; 727131623Sdes } 72824143Sjoerg 729168710Sstas cmdbuf = (char *)malloc(cmdlengthdelta + 1); 730168710Sstas if (cmdbuf == NULL) { 731168710Sstas warn("malloc(%d)", cmdlengthdelta + 1); 732168710Sstas return NULL; 733168710Sstas } 734168710Sstas 735168710Sstas if (!(flags & FMT_SHOWARGS)) { 736168710Sstas snprintf(cmdbuf, cmdlengthdelta, "%s", pp->ki_comm); 737168710Sstas } 738168710Sstas else if (pp->ki_args == NULL || 739168710Sstas (args = kvm_getargv(kd, pp, cmdlengthdelta)) == NULL || !(*args)) 740168710Sstas snprintf(cmdbuf, cmdlengthdelta, "[%s]", pp->ki_comm); 741168710Sstas else { 742168710Sstas char *src, *dst, *argbuf; 743168710Sstas char *cmd; 744168710Sstas size_t argbuflen; 745168710Sstas size_t len; 746168710Sstas 747168710Sstas argbuflen = cmdlengthdelta * 4; 748168710Sstas argbuf = (char *)malloc(argbuflen + 1); 749168710Sstas if (argbuf == NULL) { 750168710Sstas warn("malloc(%d)", argbuflen + 1); 751168710Sstas free(cmdbuf); 752168710Sstas return NULL; 753168710Sstas } 754168710Sstas 755168710Sstas dst = argbuf; 756168710Sstas 757168710Sstas /* Extract cmd name from argv */ 758168710Sstas cmd = strrchr(*args, '/'); 759168710Sstas if (cmd == NULL) 760168710Sstas cmd = *args; 761168710Sstas else 762168710Sstas cmd++; 763168710Sstas 764168710Sstas for (; (src = *args++) != NULL; ) { 765168710Sstas if (*src == '\0') 766168710Sstas continue; 767168710Sstas len = (argbuflen - (dst - argbuf) - 1) / 4; 768168710Sstas strvisx(dst, src, strlen(src) < len ? strlen(src) : len, 769168710Sstas VIS_NL | VIS_CSTYLE); 770168710Sstas while (*dst != '\0') 771168710Sstas dst++; 772168710Sstas if ((argbuflen - (dst - argbuf) - 1) / 4 > 0) 773168710Sstas *dst++ = ' '; /* add delimiting space */ 774168710Sstas } 775168710Sstas if (dst != argbuf && dst[-1] == ' ') 776168710Sstas dst--; 777168710Sstas *dst = '\0'; 778168710Sstas 779168710Sstas if (strcmp(cmd, pp->ki_comm) != 0 ) 780168710Sstas snprintf(cmdbuf, cmdlengthdelta, "%s (%s)",argbuf, \ 781168710Sstas pp->ki_comm); 782168710Sstas else 783168710Sstas strlcpy(cmdbuf, argbuf, cmdlengthdelta); 784168710Sstas 785168710Sstas free(argbuf); 786168710Sstas } 787168710Sstas 788131623Sdes if (displaymode == DISP_IO) { 789131623Sdes oldp = get_old_proc(pp); 790131623Sdes if (oldp != NULL) { 791158280Sbde ru.ru_inblock = RU(pp)->ru_inblock - 792158280Sbde RU(oldp)->ru_inblock; 793158280Sbde ru.ru_oublock = RU(pp)->ru_oublock - 794158280Sbde RU(oldp)->ru_oublock; 795131623Sdes ru.ru_majflt = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; 796133817Salfred ru.ru_nvcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; 797133817Salfred ru.ru_nivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; 798131623Sdes rup = &ru; 799131623Sdes } else { 800131623Sdes rup = RU(pp); 801131623Sdes } 802131623Sdes p_tot = rup->ru_inblock + rup->ru_oublock + rup->ru_majflt; 803131623Sdes s_tot = total_inblock + total_oublock + total_majflt; 804131402Salfred 805131623Sdes sprintf(fmt, io_Proc_format, 806131623Sdes pp->ki_pid, 807158280Sbde namelength, namelength, (*get_userid)(pp->ki_ruid), 808133817Salfred rup->ru_nvcsw, 809133817Salfred rup->ru_nivcsw, 810131626Sdes rup->ru_inblock, 811131626Sdes rup->ru_oublock, 812131626Sdes rup->ru_majflt, 813131626Sdes p_tot, 814131626Sdes s_tot == 0 ? 0.0 : (p_tot * 100.0 / s_tot), 815131623Sdes screen_width > cmdlengthdelta ? 816131623Sdes screen_width - cmdlengthdelta : 0, 817168710Sstas printable(cmdbuf)); 818168710Sstas 819168710Sstas free(cmdbuf); 820168710Sstas 821131623Sdes return (fmt); 822131623Sdes } 823145073Skeramida 824131623Sdes /* format this entry */ 825145073Skeramida proc_fmt = smpmode ? smp_Proc_format : up_Proc_format; 826145073Skeramida if (ps.thread != 0) 827145073Skeramida thr_buf[0] = '\0'; 828145073Skeramida else 829145073Skeramida snprintf(thr_buf, sizeof(thr_buf), "%*d ", 830145073Skeramida sizeof(thr_buf) - 2, pp->ki_numthreads); 831145073Skeramida 832145073Skeramida sprintf(fmt, proc_fmt, 83369896Smckusick pp->ki_pid, 834158280Sbde namelength, namelength, (*get_userid)(pp->ki_ruid), 835145073Skeramida thr_buf, 83672377Sjake pp->ki_pri.pri_level - PZERO, 837158282Sbde format_nice(pp), 83837100Sdt format_k2(PROCSIZE(pp)), 83969896Smckusick format_k2(pagetok(pp->ki_rssize)), 84024143Sjoerg status, 84169896Smckusick smpmode ? pp->ki_lastcpu : 0, 84224143Sjoerg format_time(cputime), 843146342Skeramida ps.wcpu ? 100.0 * weighted_cpu(pct, pp) : 100.0 * pct, 844158280Sbde screen_width > cmdlengthdelta ? screen_width - cmdlengthdelta : 0, 845168710Sstas printable(cmdbuf)); 84624143Sjoerg 847168710Sstas free(cmdbuf); 848168710Sstas 849131623Sdes /* return the result */ 850131623Sdes return (fmt); 85124143Sjoerg} 85224143Sjoerg 853131310Salfredstatic void 854158282Sbdegetsysctl(const char *name, void *ptr, size_t len) 85524143Sjoerg{ 856131623Sdes size_t nlen = len; 857131310Salfred 858131623Sdes if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 859131623Sdes fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name, 860131623Sdes strerror(errno)); 861131623Sdes quit(23); 862131623Sdes } 863131623Sdes if (nlen != len) { 864158280Sbde fprintf(stderr, "top: sysctl(%s...) expected %lu, got %lu\n", 865158280Sbde name, (unsigned long)len, (unsigned long)nlen); 866131623Sdes quit(23); 867131623Sdes } 86824143Sjoerg} 86972951Srwatson 870164058Sbdestatic const char * 871164058Sbdeformat_nice(const struct kinfo_proc *pp) 872158282Sbde{ 873164058Sbde const char *fifo, *kthread; 874164058Sbde int rtpri; 875164058Sbde static char nicebuf[4 + 1]; 876158282Sbde 877164058Sbde fifo = PRI_NEED_RR(pp->ki_pri.pri_class) ? "" : "F"; 878164058Sbde kthread = (pp->ki_flag & P_KTHREAD) ? "k" : ""; 879164058Sbde switch (PRI_BASE(pp->ki_pri.pri_class)) { 880164058Sbde case PRI_ITHD: 881164058Sbde return ("-"); 882164058Sbde case PRI_REALTIME: 883164058Sbde rtpri = pp->ki_pri.pri_level - PRI_MIN_REALTIME; 884164058Sbde snprintf(nicebuf, sizeof(nicebuf), "%sr%d%s", 885164058Sbde kthread, rtpri, fifo); 886164058Sbde break; 887164058Sbde case PRI_TIMESHARE: 888164058Sbde if (pp->ki_flag & P_KTHREAD) 889164058Sbde return ("-"); 890164058Sbde snprintf(nicebuf, sizeof(nicebuf), "%d", pp->ki_nice - NZERO); 891164058Sbde break; 892164058Sbde case PRI_IDLE: 893164058Sbde rtpri = pp->ki_pri.pri_level - PRI_MIN_IDLE; 894164058Sbde snprintf(nicebuf, sizeof(nicebuf), "%si%d%s", 895164058Sbde kthread, rtpri, fifo); 896164058Sbde break; 897164058Sbde default: 898164058Sbde return ("?"); 899164058Sbde } 900158282Sbde return (nicebuf); 901158282Sbde} 902158282Sbde 90338278Swosch/* comparison routines for qsort */ 90424143Sjoerg 905158282Sbdestatic int 906131622Sdescompare_pid(const void *p1, const void *p2) 907131402Salfred{ 908131623Sdes const struct kinfo_proc * const *pp1 = p1; 909131623Sdes const struct kinfo_proc * const *pp2 = p2; 910131402Salfred 911131623Sdes if ((*pp2)->ki_pid < 0 || (*pp1)->ki_pid < 0) 912131623Sdes abort(); 913131402Salfred 914131623Sdes return ((*pp1)->ki_pid - (*pp2)->ki_pid); 915131402Salfred} 916131402Salfred 91724143Sjoerg/* 91824143Sjoerg * proc_compare - comparison function for "qsort" 91924143Sjoerg * Compares the resource consumption of two processes using five 920131620Sdes * distinct keys. The keys (in descending order of importance) are: 921131620Sdes * percent cpu, cpu ticks, state, resident set size, total virtual 922131620Sdes * memory usage. The process states are ordered as follows (from least 923131620Sdes * to most important): WAIT, zombie, sleep, stop, start, run. The 924131620Sdes * array declaration below maps a process state index into a number 925131620Sdes * that reflects this ordering. 92624143Sjoerg */ 92724143Sjoerg 928158280Sbdestatic int sorted_state[] = { 929131623Sdes 0, /* not used */ 930131623Sdes 3, /* sleep */ 931131623Sdes 1, /* ABANDONED (WAIT) */ 932131623Sdes 6, /* run */ 933131623Sdes 5, /* start */ 934131623Sdes 2, /* zombie */ 935131623Sdes 4 /* stop */ 93624143Sjoerg}; 93738278Swosch 938131620Sdes 939146343Skeramida#define ORDERKEY_PCTCPU(a, b) do { \ 940146343Skeramida long diff; \ 941146343Skeramida if (ps.wcpu) \ 942158280Sbde diff = floor(1.0E6 * weighted_cpu(pctdouble((b)->ki_pctcpu), \ 943158280Sbde (b))) - \ 944158280Sbde floor(1.0E6 * weighted_cpu(pctdouble((a)->ki_pctcpu), \ 945158280Sbde (a))); \ 946146343Skeramida else \ 947146343Skeramida diff = (long)(b)->ki_pctcpu - (long)(a)->ki_pctcpu; \ 948146343Skeramida if (diff != 0) \ 949146343Skeramida return (diff > 0 ? 1 : -1); \ 950131626Sdes} while (0) 95138278Swosch 952131626Sdes#define ORDERKEY_CPTICKS(a, b) do { \ 953131628Sdes int64_t diff = (int64_t)(b)->ki_runtime - (int64_t)(a)->ki_runtime; \ 954131626Sdes if (diff != 0) \ 955131626Sdes return (diff > 0 ? 1 : -1); \ 956131626Sdes} while (0) 95738278Swosch 958131626Sdes#define ORDERKEY_STATE(a, b) do { \ 959131626Sdes int diff = sorted_state[(b)->ki_stat] - sorted_state[(a)->ki_stat]; \ 960131626Sdes if (diff != 0) \ 961131626Sdes return (diff > 0 ? 1 : -1); \ 962131626Sdes} while (0) 96338278Swosch 964131626Sdes#define ORDERKEY_PRIO(a, b) do { \ 965131628Sdes int diff = (int)(b)->ki_pri.pri_level - (int)(a)->ki_pri.pri_level; \ 966131626Sdes if (diff != 0) \ 967131626Sdes return (diff > 0 ? 1 : -1); \ 968131626Sdes} while (0) 96938278Swosch 970145073Skeramida#define ORDERKEY_THREADS(a, b) do { \ 971145073Skeramida int diff = (int)(b)->ki_numthreads - (int)(a)->ki_numthreads; \ 972145073Skeramida if (diff != 0) \ 973145073Skeramida return (diff > 0 ? 1 : -1); \ 974145073Skeramida} while (0) 975145073Skeramida 976131626Sdes#define ORDERKEY_RSSIZE(a, b) do { \ 977131628Sdes long diff = (long)(b)->ki_rssize - (long)(a)->ki_rssize; \ 978131626Sdes if (diff != 0) \ 979131626Sdes return (diff > 0 ? 1 : -1); \ 980131626Sdes} while (0) 98138278Swosch 982131626Sdes#define ORDERKEY_MEM(a, b) do { \ 983131628Sdes long diff = (long)PROCSIZE((b)) - (long)PROCSIZE((a)); \ 984131626Sdes if (diff != 0) \ 985131626Sdes return (diff > 0 ? 1 : -1); \ 986131626Sdes} while (0) 98738278Swosch 98838278Swosch/* compare_cpu - the comparison function for sorting by cpu percentage */ 98938278Swosch 99024143Sjoergint 99138278Swosch#ifdef ORDER 992131626Sdescompare_cpu(void *arg1, void *arg2) 99338278Swosch#else 994131626Sdesproc_compare(void *arg1, void *arg2) 99538278Swosch#endif 99624143Sjoerg{ 997131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 998131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 99924143Sjoerg 1000131626Sdes ORDERKEY_PCTCPU(p1, p2); 1001131626Sdes ORDERKEY_CPTICKS(p1, p2); 1002131626Sdes ORDERKEY_STATE(p1, p2); 1003131626Sdes ORDERKEY_PRIO(p1, p2); 1004131626Sdes ORDERKEY_RSSIZE(p1, p2); 1005131626Sdes ORDERKEY_MEM(p1, p2); 100624143Sjoerg 1007131626Sdes return (0); 100824143Sjoerg} 100924143Sjoerg 101038278Swosch#ifdef ORDER 1011158280Sbde/* "cpu" compare routines */ 1012158280Sbdeint compare_size(), compare_res(), compare_time(), compare_prio(), 1013158280Sbde compare_threads(); 101424143Sjoerg 1015158280Sbde/* 1016158280Sbde * "io" compare routines. Context switches aren't i/o, but are displayed 1017158280Sbde * on the "io" display. 1018158280Sbde */ 1019158280Sbdeint compare_iototal(), compare_ioread(), compare_iowrite(), compare_iofault(), 1020158280Sbde compare_vcsw(), compare_ivcsw(); 1021158280Sbde 1022133817Salfredint (*compares[])() = { 1023131623Sdes compare_cpu, 1024131623Sdes compare_size, 1025131623Sdes compare_res, 1026131623Sdes compare_time, 1027131623Sdes compare_prio, 1028145073Skeramida compare_threads, 1029133817Salfred compare_iototal, 1030133817Salfred compare_ioread, 1031133817Salfred compare_iowrite, 1032133817Salfred compare_iofault, 1033133817Salfred compare_vcsw, 1034133817Salfred compare_ivcsw, 1035131623Sdes NULL 103638278Swosch}; 103738278Swosch 103838278Swosch/* compare_size - the comparison function for sorting by total memory usage */ 103938278Swosch 104038278Swoschint 1041131626Sdescompare_size(void *arg1, void *arg2) 104238278Swosch{ 1043131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1044131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 104538278Swosch 1046131626Sdes ORDERKEY_MEM(p1, p2); 1047131626Sdes ORDERKEY_RSSIZE(p1, p2); 1048131626Sdes ORDERKEY_PCTCPU(p1, p2); 1049131626Sdes ORDERKEY_CPTICKS(p1, p2); 1050131626Sdes ORDERKEY_STATE(p1, p2); 1051131626Sdes ORDERKEY_PRIO(p1, p2); 105238278Swosch 1053131626Sdes return (0); 105438278Swosch} 105538278Swosch 105638278Swosch/* compare_res - the comparison function for sorting by resident set size */ 105738278Swosch 105838278Swoschint 1059131626Sdescompare_res(void *arg1, void *arg2) 106038278Swosch{ 1061131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1062131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 106338278Swosch 1064131626Sdes ORDERKEY_RSSIZE(p1, p2); 1065131626Sdes ORDERKEY_MEM(p1, p2); 1066131626Sdes ORDERKEY_PCTCPU(p1, p2); 1067131626Sdes ORDERKEY_CPTICKS(p1, p2); 1068131626Sdes ORDERKEY_STATE(p1, p2); 1069131626Sdes ORDERKEY_PRIO(p1, p2); 107038278Swosch 1071131626Sdes return (0); 107238278Swosch} 107338278Swosch 107438278Swosch/* compare_time - the comparison function for sorting by total cpu time */ 107538278Swosch 107638278Swoschint 1077131626Sdescompare_time(void *arg1, void *arg2) 1078131310Salfred{ 1079131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1080131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 108138278Swosch 1082131626Sdes ORDERKEY_CPTICKS(p1, p2); 1083131626Sdes ORDERKEY_PCTCPU(p1, p2); 1084131626Sdes ORDERKEY_STATE(p1, p2); 1085131626Sdes ORDERKEY_PRIO(p1, p2); 1086131626Sdes ORDERKEY_RSSIZE(p1, p2); 1087131626Sdes ORDERKEY_MEM(p1, p2); 108838278Swosch 1089131626Sdes return (0); 1090131623Sdes} 1091131310Salfred 1092131626Sdes/* compare_prio - the comparison function for sorting by priority */ 109338278Swosch 109438278Swoschint 1095131626Sdescompare_prio(void *arg1, void *arg2) 109638278Swosch{ 1097131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1098131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 109938278Swosch 1100131626Sdes ORDERKEY_PRIO(p1, p2); 1101131626Sdes ORDERKEY_CPTICKS(p1, p2); 1102131626Sdes ORDERKEY_PCTCPU(p1, p2); 1103131626Sdes ORDERKEY_STATE(p1, p2); 1104131626Sdes ORDERKEY_RSSIZE(p1, p2); 1105131626Sdes ORDERKEY_MEM(p1, p2); 110638278Swosch 1107131626Sdes return (0); 110838278Swosch} 1109145073Skeramida 1110145073Skeramida/* compare_threads - the comparison function for sorting by threads */ 1111145073Skeramidaint 1112145073Skeramidacompare_threads(void *arg1, void *arg2) 1113145073Skeramida{ 1114145073Skeramida struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1115145073Skeramida struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1116145073Skeramida 1117145073Skeramida ORDERKEY_THREADS(p1, p2); 1118145073Skeramida ORDERKEY_PCTCPU(p1, p2); 1119145073Skeramida ORDERKEY_CPTICKS(p1, p2); 1120145073Skeramida ORDERKEY_STATE(p1, p2); 1121145073Skeramida ORDERKEY_PRIO(p1, p2); 1122145073Skeramida ORDERKEY_RSSIZE(p1, p2); 1123145073Skeramida ORDERKEY_MEM(p1, p2); 1124145073Skeramida 1125145073Skeramida return (0); 1126145073Skeramida} 1127158280Sbde#endif /* ORDER */ 112838278Swosch 1129158280Sbde/* assorted comparison functions for sorting by i/o */ 1130131829Skeramida 1131131402Salfredint 1132131829Skeramida#ifdef ORDER 1133131829Skeramidacompare_iototal(void *arg1, void *arg2) 1134131829Skeramida#else 1135131626Sdesio_compare(void *arg1, void *arg2) 1136131829Skeramida#endif 1137131402Salfred{ 1138131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1139131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1140131402Salfred 1141131626Sdes return (get_io_total(p2) - get_io_total(p1)); 1142131402Salfred} 1143131829Skeramida 1144131829Skeramida#ifdef ORDER 1145131829Skeramidaint 1146131829Skeramidacompare_ioread(void *arg1, void *arg2) 1147131829Skeramida{ 1148131829Skeramida struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1149131829Skeramida struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1150131829Skeramida long dummy, inp1, inp2; 1151131829Skeramida 1152133817Salfred (void) get_io_stats(p1, &inp1, &dummy, &dummy, &dummy, &dummy); 1153133817Salfred (void) get_io_stats(p2, &inp2, &dummy, &dummy, &dummy, &dummy); 1154131829Skeramida 1155131829Skeramida return (inp2 - inp1); 1156131829Skeramida} 1157131829Skeramida 1158131829Skeramidaint 1159131829Skeramidacompare_iowrite(void *arg1, void *arg2) 1160131829Skeramida{ 1161131829Skeramida struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1162131829Skeramida struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1163131829Skeramida long dummy, oup1, oup2; 1164131829Skeramida 1165133817Salfred (void) get_io_stats(p1, &dummy, &oup1, &dummy, &dummy, &dummy); 1166133817Salfred (void) get_io_stats(p2, &dummy, &oup2, &dummy, &dummy, &dummy); 1167131829Skeramida 1168131829Skeramida return (oup2 - oup1); 1169131829Skeramida} 1170131829Skeramida 1171131829Skeramidaint 1172131829Skeramidacompare_iofault(void *arg1, void *arg2) 1173131829Skeramida{ 1174131829Skeramida struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1175131829Skeramida struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1176131829Skeramida long dummy, flp1, flp2; 1177131829Skeramida 1178133817Salfred (void) get_io_stats(p1, &dummy, &dummy, &flp1, &dummy, &dummy); 1179133817Salfred (void) get_io_stats(p2, &dummy, &dummy, &flp2, &dummy, &dummy); 1180131829Skeramida 1181131829Skeramida return (flp2 - flp1); 1182131829Skeramida} 1183131829Skeramida 1184133817Salfredint 1185133817Salfredcompare_vcsw(void *arg1, void *arg2) 1186133817Salfred{ 1187133817Salfred struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1188133817Salfred struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1189133817Salfred long dummy, flp1, flp2; 1190133817Salfred 1191133817Salfred (void) get_io_stats(p1, &dummy, &dummy, &dummy, &flp1, &dummy); 1192133817Salfred (void) get_io_stats(p2, &dummy, &dummy, &dummy, &flp2, &dummy); 1193133817Salfred 1194133817Salfred return (flp2 - flp1); 1195133817Salfred} 1196133817Salfred 1197133817Salfredint 1198133817Salfredcompare_ivcsw(void *arg1, void *arg2) 1199133817Salfred{ 1200133817Salfred struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1201133817Salfred struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1202133817Salfred long dummy, flp1, flp2; 1203133817Salfred 1204133817Salfred (void) get_io_stats(p1, &dummy, &dummy, &dummy, &dummy, &flp1); 1205133817Salfred (void) get_io_stats(p2, &dummy, &dummy, &dummy, &dummy, &flp2); 1206133817Salfred 1207133817Salfred return (flp2 - flp1); 1208133817Salfred} 1209131829Skeramida#endif /* ORDER */ 1210131829Skeramida 121124143Sjoerg/* 121224143Sjoerg * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 121324143Sjoerg * the process does not exist. 121424143Sjoerg * It is EXTREMLY IMPORTANT that this function work correctly. 121524143Sjoerg * If top runs setuid root (as in SVR4), then this function 121624143Sjoerg * is the only thing that stands in the way of a serious 121724143Sjoerg * security problem. It validates requests for the "kill" 121824143Sjoerg * and "renice" commands. 121924143Sjoerg */ 122024143Sjoerg 1221131310Salfredint 1222131622Sdesproc_owner(int pid) 122324143Sjoerg{ 1224131623Sdes int cnt; 1225131623Sdes struct kinfo_proc **prefp; 1226131623Sdes struct kinfo_proc *pp; 122724143Sjoerg 1228131623Sdes prefp = pref; 1229131623Sdes cnt = pref_len; 1230131626Sdes while (--cnt >= 0) { 1231131623Sdes pp = *prefp++; 1232131623Sdes if (pp->ki_pid == (pid_t)pid) 1233131623Sdes return ((int)pp->ki_ruid); 123424143Sjoerg } 1235131623Sdes return (-1); 123624143Sjoerg} 123724143Sjoerg 1238158282Sbdestatic int 1239131622Sdesswapmode(int *retavail, int *retfree) 124024143Sjoerg{ 124143053Sdillon int n; 124243053Sdillon int pagesize = getpagesize(); 124343053Sdillon struct kvm_swap swapary[1]; 124424143Sjoerg 124543053Sdillon *retavail = 0; 124643053Sdillon *retfree = 0; 124724143Sjoerg 124843053Sdillon#define CONVERT(v) ((quad_t)(v) * pagesize / 1024) 124924143Sjoerg 125043053Sdillon n = kvm_getswapinfo(kd, swapary, 1, 0); 125143697Sdillon if (n < 0 || swapary[0].ksw_total == 0) 1252131623Sdes return (0); 125324143Sjoerg 125443053Sdillon *retavail = CONVERT(swapary[0].ksw_total); 125543053Sdillon *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); 125624143Sjoerg 1257131626Sdes n = (int)(swapary[0].ksw_used * 100.0 / swapary[0].ksw_total); 1258131623Sdes return (n); 125943053Sdillon} 1260