machine.c revision 144636
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 144636 2005-04-04 21:19:48Z stefanf $ 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> 4824143Sjoerg 4924143Sjoerg#include "top.h" 5024143Sjoerg#include "machine.h" 5169375Sjhb#include "screen.h" 5272951Srwatson#include "utils.h" 5324143Sjoerg 5492922Simpstatic void getsysctl(char *, void *, size_t); 5572951Srwatson 5672951Srwatson#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) 5772951Srwatson 5892922Simpextern char* printable(char *); 5992922Simpint swapmode(int *retavail, int *retfree); 6027340Speterstatic int smpmode; 61131402Salfredenum displaymodes displaymode; 6227390Speterstatic int namelength; 6369375Sjhbstatic int cmdlengthdelta; 6424143Sjoerg 6572951Srwatson/* Prototypes for top internals */ 6692922Simpvoid quit(int); 67131402Salfredint compare_pid(const void *a, const void *b); 6824143Sjoerg 6924143Sjoerg/* get_process_info passes back a handle. This is what it looks like: */ 7024143Sjoerg 7124143Sjoergstruct handle 7224143Sjoerg{ 73131623Sdes struct kinfo_proc **next_proc; /* points to next valid proc pointer */ 74131623Sdes int remaining; /* number of pointers remaining */ 7524143Sjoerg}; 7624143Sjoerg 7724143Sjoerg/* declarations for load_avg */ 7824143Sjoerg#include "loadavg.h" 7924143Sjoerg 8024143Sjoerg/* define what weighted cpu is. */ 8169896Smckusick#define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \ 8269896Smckusick ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu)))) 8324143Sjoerg 8424143Sjoerg/* what we consider to be process size: */ 8569896Smckusick#define PROCSIZE(pp) ((pp)->ki_size / 1024) 8624143Sjoerg 87131402Salfred#define RU(pp) (&(pp)->ki_rusage) 88131402Salfred#define RUTOT(pp) \ 89131402Salfred (RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt) 90131402Salfred 91131402Salfred 9224143Sjoerg/* definitions for indices in the nlist array */ 9324143Sjoerg 9424143Sjoerg/* 9524143Sjoerg * These definitions control the format of the per-process area 9624143Sjoerg */ 9724143Sjoerg 98131402Salfredstatic char io_header[] = 99133817Salfred " PID %-*.*s VCSW IVCSW READ WRITE FAULT TOTAL PERCENT COMMAND"; 100131402Salfred 101131402Salfred#define io_Proc_format \ 102133817Salfred "%5d %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s" 103131402Salfred 10427340Speterstatic char smp_header[] = 105131626Sdes " PID %-*.*s PRI NICE SIZE RES STATE C TIME WCPU CPU COMMAND"; 10624143Sjoerg 10727340Speter#define smp_Proc_format \ 10872647Smarkm "%5d %-*.*s %3d %4d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %.*s" 10924143Sjoerg 11027340Speterstatic char up_header[] = 111131626Sdes " PID %-*.*s PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 11224143Sjoerg 11327340Speter#define up_Proc_format \ 11472647Smarkm "%5d %-*.*s %3d %4d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s" 11524143Sjoerg 11624143Sjoerg 11724143Sjoerg 11824143Sjoerg/* process state names for the "STATE" column of the display */ 11924143Sjoerg/* the extra nulls in the string "run" are for adding a slash and 12024143Sjoerg the processor number when needed */ 12124143Sjoerg 12224143Sjoergchar *state_abbrev[] = 12324143Sjoerg{ 124131623Sdes "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK" 12524143Sjoerg}; 12624143Sjoerg 12724143Sjoerg 12824143Sjoergstatic kvm_t *kd; 12924143Sjoerg 13024143Sjoerg/* values that we stash away in _init and use in later routines */ 13124143Sjoerg 13224143Sjoergstatic double logcpu; 13324143Sjoerg 13424143Sjoerg/* these are retrieved from the kernel in _init */ 13524143Sjoerg 13624143Sjoergstatic load_avg ccpu; 13724143Sjoerg 13872951Srwatson/* these are used in the get_ functions */ 13924143Sjoerg 14072951Srwatsonstatic int lastpid; 14124143Sjoerg 14224143Sjoerg/* these are for calculating cpu state percentages */ 14324143Sjoerg 14424143Sjoergstatic long cp_time[CPUSTATES]; 14524143Sjoergstatic long cp_old[CPUSTATES]; 14624143Sjoergstatic long cp_diff[CPUSTATES]; 14724143Sjoerg 14824143Sjoerg/* these are for detailing the process states */ 14924143Sjoerg 15065557Sjasoneint process_states[8]; 15124143Sjoergchar *procstatenames[] = { 152131623Sdes "", " starting, ", " running, ", " sleeping, ", " stopped, ", 153131623Sdes " zombie, ", " waiting, ", " lock, ", 154131623Sdes NULL 15524143Sjoerg}; 15624143Sjoerg 15724143Sjoerg/* these are for detailing the cpu states */ 15824143Sjoerg 15924143Sjoergint cpu_states[CPUSTATES]; 16024143Sjoergchar *cpustatenames[] = { 161131623Sdes "user", "nice", "system", "interrupt", "idle", NULL 16224143Sjoerg}; 16324143Sjoerg 16424143Sjoerg/* these are for detailing the memory statistics */ 16524143Sjoerg 16624143Sjoergint memory_stats[7]; 16724143Sjoergchar *memorynames[] = { 168131623Sdes /* 0 1 2 3 4 5 */ 169131623Sdes "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free", 170131623Sdes NULL 17124143Sjoerg}; 17224143Sjoerg 17324143Sjoergint swap_stats[7]; 17424143Sjoergchar *swapnames[] = { 175131623Sdes /* 0 1 2 3 4 5 */ 176131623Sdes "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", 177131623Sdes NULL 17824143Sjoerg}; 17924143Sjoerg 18024143Sjoerg 18124143Sjoerg/* these are for keeping track of the proc array */ 18224143Sjoerg 18324143Sjoergstatic int nproc; 18424143Sjoergstatic int onproc = -1; 18524143Sjoergstatic int pref_len; 18624143Sjoergstatic struct kinfo_proc *pbase; 18724143Sjoergstatic struct kinfo_proc **pref; 188131402Salfredstatic struct kinfo_proc *previous_procs; 189131402Salfredstatic struct kinfo_proc **previous_pref; 190131402Salfredstatic int previous_proc_count = 0; 191131402Salfredstatic int previous_proc_count_max = 0; 19224143Sjoerg 193131412Salfred/* total number of io operations */ 194131412Salfredstatic long total_inblock; 195131412Salfredstatic long total_oublock; 196131412Salfredstatic long total_majflt; 197131412Salfred 19824143Sjoerg/* these are for getting the memory statistics */ 19924143Sjoerg 20024143Sjoergstatic int pageshift; /* log base 2 of the pagesize */ 20124143Sjoerg 20224143Sjoerg/* define pagetok in terms of pageshift */ 20324143Sjoerg 20424143Sjoerg#define pagetok(size) ((size) << pageshift) 20524143Sjoerg 20624143Sjoerg/* useful externals */ 20724143Sjoerglong percentages(); 20824143Sjoerg 20938278Swosch#ifdef ORDER 210131829Skeramida/* 211131829Skeramida * Sorting orders. One vector per display mode. 212131829Skeramida * The first element is the default for each mode. 213131829Skeramida */ 214133817Salfredchar *ordernames[] = { 215133817Salfred "cpu", "size", "res", "time", "pri", 216133817Salfred "total", "read", "write", "fault", "vcsw", "ivcsw", NULL 21738278Swosch}; 21838278Swosch#endif 21938278Swosch 22024143Sjoergint 221131622Sdesmachine_init(struct statics *statics) 22224143Sjoerg{ 223131623Sdes int pagesize; 224131623Sdes size_t modelen; 225131623Sdes struct passwd *pw; 22624143Sjoerg 227131623Sdes modelen = sizeof(smpmode); 228131623Sdes if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 && 229131623Sdes sysctlbyname("kern.smp.active", &smpmode, &modelen, NULL, 0) < 0) || 230131623Sdes modelen != sizeof(smpmode)) 231131623Sdes smpmode = 0; 23227340Speter 233131623Sdes while ((pw = getpwent()) != NULL) { 234131623Sdes if (strlen(pw->pw_name) > namelength) 235131623Sdes namelength = strlen(pw->pw_name); 236131623Sdes } 237131623Sdes if (namelength < 8) 238131623Sdes namelength = 8; 239131623Sdes if (smpmode && namelength > 13) 240131623Sdes namelength = 13; 241131623Sdes else if (namelength > 15) 242131623Sdes namelength = 15; 24327390Speter 244131626Sdes kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); 245131626Sdes if (kd == NULL) 246131626Sdes return (-1); 24724143Sjoerg 248131623Sdes GETSYSCTL("kern.ccpu", ccpu); 24924143Sjoerg 250131623Sdes /* this is used in calculating WCPU -- calculate it ahead of time */ 251131623Sdes logcpu = log(loaddouble(ccpu)); 25224143Sjoerg 253131623Sdes pbase = NULL; 254131623Sdes pref = NULL; 255131623Sdes nproc = 0; 256131623Sdes onproc = -1; 257131623Sdes /* get the page size with "getpagesize" and calculate pageshift from it */ 258131623Sdes pagesize = getpagesize(); 259131623Sdes pageshift = 0; 260131626Sdes while (pagesize > 1) { 261131623Sdes pageshift++; 262131623Sdes pagesize >>= 1; 263131623Sdes } 26424143Sjoerg 265131623Sdes /* we only need the amount of log(2)1024 for our conversion */ 266131623Sdes pageshift -= LOG1024; 26724143Sjoerg 268131623Sdes /* fill in the statics information */ 269131623Sdes statics->procstate_names = procstatenames; 270131623Sdes statics->cpustate_names = cpustatenames; 271131623Sdes statics->memory_names = memorynames; 272131623Sdes statics->swap_names = swapnames; 27338278Swosch#ifdef ORDER 274133817Salfred statics->order_names = ordernames; 27538278Swosch#endif 27624143Sjoerg 277131623Sdes /* all done! */ 278131623Sdes return (0); 27924143Sjoerg} 28024143Sjoerg 281131310Salfredchar * 282131622Sdesformat_header(char *uname_field) 28324143Sjoerg{ 284131623Sdes static char Header[128]; 285131623Sdes const char *prehead; 28624143Sjoerg 287131623Sdes switch (displaymode) { 288131623Sdes case DISP_CPU: 289131623Sdes prehead = smpmode ? smp_header : up_header; 290131623Sdes break; 291131623Sdes case DISP_IO: 292131623Sdes prehead = io_header; 293131623Sdes break; 294131623Sdes } 295131402Salfred 296131623Sdes snprintf(Header, sizeof(Header), prehead, 297131623Sdes namelength, namelength, uname_field); 29827340Speter 299131623Sdes cmdlengthdelta = strlen(Header) - 7; 30024143Sjoerg 301131623Sdes return (Header); 30224143Sjoerg} 30324143Sjoerg 30424143Sjoergstatic int swappgsin = -1; 30524143Sjoergstatic int swappgsout = -1; 30624143Sjoergextern struct timeval timeout; 30724143Sjoerg 30824143Sjoergvoid 309131622Sdesget_system_info(struct system_info *si) 31024143Sjoerg{ 311131623Sdes long total; 312131623Sdes struct loadavg sysload; 313131623Sdes int mib[2]; 314131623Sdes struct timeval boottime; 315131623Sdes size_t bt_size; 316131626Sdes int i; 31724143Sjoerg 318131623Sdes /* get the cp_time array */ 319131623Sdes GETSYSCTL("kern.cp_time", cp_time); 320131623Sdes GETSYSCTL("vm.loadavg", sysload); 321131623Sdes GETSYSCTL("kern.lastpid", lastpid); 32224143Sjoerg 323131623Sdes /* convert load averages to doubles */ 324131626Sdes for (i = 0; i < 3; i++) 325131626Sdes si->load_avg[i] = (double)sysload.ldavg[i] / sysload.fscale; 32624143Sjoerg 327131623Sdes /* convert cp_time counts to percentages */ 328131623Sdes total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 32924143Sjoerg 330131623Sdes /* sum memory & swap statistics */ 331131623Sdes { 332131623Sdes static unsigned int swap_delay = 0; 333131623Sdes static int swapavail = 0; 334131623Sdes static int swapfree = 0; 335131623Sdes static int bufspace = 0; 336131623Sdes static int nspgsin, nspgsout; 33724143Sjoerg 338131623Sdes GETSYSCTL("vfs.bufspace", bufspace); 339131623Sdes GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]); 340131623Sdes GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]); 341131623Sdes GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]); 342131623Sdes GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]); 343131623Sdes GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]); 344131623Sdes GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin); 345131623Sdes GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout); 346131623Sdes /* convert memory stats to Kbytes */ 347131623Sdes memory_stats[0] = pagetok(memory_stats[0]); 348131623Sdes memory_stats[1] = pagetok(memory_stats[1]); 349131623Sdes memory_stats[2] = pagetok(memory_stats[2]); 350131623Sdes memory_stats[3] = pagetok(memory_stats[3]); 351131623Sdes memory_stats[4] = bufspace / 1024; 352131623Sdes memory_stats[5] = pagetok(memory_stats[5]); 353131623Sdes memory_stats[6] = -1; 35424143Sjoerg 355131623Sdes /* first interval */ 356131623Sdes if (swappgsin < 0) { 357131623Sdes swap_stats[4] = 0; 358131623Sdes swap_stats[5] = 0; 359131623Sdes } 36024143Sjoerg 361131623Sdes /* compute differences between old and new swap statistic */ 362131623Sdes else { 363131623Sdes swap_stats[4] = pagetok(((nspgsin - swappgsin))); 364131623Sdes swap_stats[5] = pagetok(((nspgsout - swappgsout))); 365131623Sdes } 36624143Sjoerg 367131623Sdes swappgsin = nspgsin; 368131623Sdes swappgsout = nspgsout; 36924143Sjoerg 370131623Sdes /* call CPU heavy swapmode() only for changes */ 371131623Sdes if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) { 372131623Sdes swap_stats[3] = swapmode(&swapavail, &swapfree); 373131623Sdes swap_stats[0] = swapavail; 374131623Sdes swap_stats[1] = swapavail - swapfree; 375131623Sdes swap_stats[2] = swapfree; 376131623Sdes } 377131623Sdes swap_delay = 1; 378131623Sdes swap_stats[6] = -1; 37924143Sjoerg } 38024143Sjoerg 381131623Sdes /* set arrays and strings */ 382131623Sdes si->cpustates = cpu_states; 383131623Sdes si->memory = memory_stats; 384131623Sdes si->swap = swap_stats; 38524143Sjoerg 38624143Sjoerg 387131623Sdes if (lastpid > 0) { 388131623Sdes si->last_pid = lastpid; 389131623Sdes } else { 390131623Sdes si->last_pid = -1; 391131623Sdes } 39242447Sobrien 393131623Sdes /* 394131623Sdes * Print how long system has been up. 395131623Sdes * (Found by looking getting "boottime" from the kernel) 396131623Sdes */ 397131623Sdes mib[0] = CTL_KERN; 398131623Sdes mib[1] = KERN_BOOTTIME; 399131623Sdes bt_size = sizeof(boottime); 400131623Sdes if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 && 401131623Sdes boottime.tv_sec != 0) { 402131623Sdes si->boottime = boottime; 403131623Sdes } else { 404131623Sdes si->boottime.tv_sec = -1; 405131623Sdes } 40624143Sjoerg} 40724143Sjoerg 408132015Salfred#define NOPROC ((void *)-1) 409132015Salfred 410132955Salfred/* 411132955Salfred * We need to compare data from the old process entry with the new 412132955Salfred * process entry. 413132955Salfred * To facilitate doing this quickly we stash a pointer in the kinfo_proc 414132955Salfred * structure to cache the mapping. We also use a negative cache pointer 415132955Salfred * of NOPROC to avoid duplicate lookups. 416132955Salfred * XXX: this could be done when the actual processes are fetched, we do 417132955Salfred * it here out of laziness. 418132955Salfred */ 419131402Salfredconst struct kinfo_proc * 420131402Salfredget_old_proc(struct kinfo_proc *pp) 421131402Salfred{ 422131402Salfred struct kinfo_proc **oldpp, *oldp; 423131402Salfred 424132955Salfred /* 425132955Salfred * If this is the first fetch of the kinfo_procs then we don't have 426132955Salfred * any previous entries. 427132955Salfred */ 428131402Salfred if (previous_proc_count == 0) 429131402Salfred return (NULL); 430132955Salfred /* negative cache? */ 431132015Salfred if (pp->ki_udata == NOPROC) 432132015Salfred return (NULL); 433132955Salfred /* cached? */ 434132015Salfred if (pp->ki_udata != NULL) 435132015Salfred return (pp->ki_udata); 436132955Salfred /* 437132955Salfred * Not cached, 438132955Salfred * 1) look up based on pid. 439132955Salfred * 2) compare process start. 440132955Salfred * If we fail here, then setup a negative cache entry, otherwise 441132955Salfred * cache it. 442132955Salfred */ 443131402Salfred oldpp = bsearch(&pp, previous_pref, previous_proc_count, 444131626Sdes sizeof(*previous_pref), compare_pid); 445132015Salfred if (oldpp == NULL) { 446132015Salfred pp->ki_udata = NOPROC; 447131402Salfred return (NULL); 448132015Salfred } 449131402Salfred oldp = *oldpp; 450132015Salfred if (bcmp(&oldp->ki_start, &pp->ki_start, sizeof(pp->ki_start)) != 0) { 451132015Salfred pp->ki_udata = NOPROC; 452131402Salfred return (NULL); 453132015Salfred } 454132015Salfred pp->ki_udata = oldp; 455131402Salfred return (oldp); 456131402Salfred} 457131402Salfred 458132955Salfred/* 459132955Salfred * Return the total amount of IO done in blocks in/out and faults. 460132955Salfred * store the values individually in the pointers passed in. 461132955Salfred */ 462131402Salfredlong 463133817Salfredget_io_stats(struct kinfo_proc *pp, long *inp, long *oup, long *flp, long *vcsw, long *ivcsw) 464131402Salfred{ 465131402Salfred const struct kinfo_proc *oldp; 466131402Salfred static struct kinfo_proc dummy; 467131402Salfred long ret; 468131402Salfred 469131402Salfred oldp = get_old_proc(pp); 470131402Salfred if (oldp == NULL) { 471131402Salfred bzero(&dummy, sizeof(dummy)); 472131402Salfred oldp = &dummy; 473131402Salfred } 474131402Salfred 475131412Salfred *inp = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; 476131412Salfred *oup = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; 477131412Salfred *flp = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; 478133817Salfred *vcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; 479133817Salfred *ivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; 480131402Salfred ret = 481131402Salfred (RU(pp)->ru_inblock - RU(oldp)->ru_inblock) + 482131402Salfred (RU(pp)->ru_oublock - RU(oldp)->ru_oublock) + 483131402Salfred (RU(pp)->ru_majflt - RU(oldp)->ru_majflt); 484131402Salfred return (ret); 485131402Salfred} 486131402Salfred 487132955Salfred/* 488132955Salfred * Return the total number of block in/out and faults by a process. 489132955Salfred */ 490131412Salfredlong 491131412Salfredget_io_total(struct kinfo_proc *pp) 492131412Salfred{ 493131412Salfred long dummy; 494131412Salfred 495133817Salfred return (get_io_stats(pp, &dummy, &dummy, &dummy, &dummy, &dummy)); 496131412Salfred} 497131412Salfred 49824143Sjoergstatic struct handle handle; 49924143Sjoerg 500131310Salfredcaddr_t 501131622Sdesget_process_info(struct system_info *si, struct process_select *sel, 502131626Sdes int (*compare)(const void *, const void *)) 50324143Sjoerg{ 504131623Sdes int i; 505131623Sdes int total_procs; 506131623Sdes long p_io; 507133817Salfred long p_inblock, p_oublock, p_majflt, p_vcsw, p_ivcsw; 508131623Sdes int active_procs; 509131623Sdes struct kinfo_proc **prefp; 510131623Sdes struct kinfo_proc *pp; 511131623Sdes struct kinfo_proc *prev_pp = NULL; 51224143Sjoerg 513131623Sdes /* these are copied out of sel for speed */ 514131623Sdes int show_idle; 515131623Sdes int show_self; 516131623Sdes int show_system; 517131623Sdes int show_uid; 518131623Sdes int show_command; 51924143Sjoerg 520131623Sdes /* 521131623Sdes * Save the previous process info. 522131623Sdes */ 523131623Sdes if (previous_proc_count_max < nproc) { 524131623Sdes free(previous_procs); 525131626Sdes previous_procs = malloc(nproc * sizeof(*previous_procs)); 526131623Sdes free(previous_pref); 527131626Sdes previous_pref = malloc(nproc * sizeof(*previous_pref)); 528131623Sdes if (previous_procs == NULL || previous_pref == NULL) { 529131623Sdes (void) fprintf(stderr, "top: Out of memory.\n"); 530131623Sdes quit(23); 531131623Sdes } 532131623Sdes previous_proc_count_max = nproc; 533131623Sdes } 534131623Sdes if (nproc) { 535131623Sdes for (i = 0; i < nproc; i++) 536131623Sdes previous_pref[i] = &previous_procs[i]; 537131626Sdes bcopy(pbase, previous_procs, nproc * sizeof(*previous_procs)); 538131626Sdes qsort(previous_pref, nproc, sizeof(*previous_pref), compare_pid); 539131623Sdes } 540131623Sdes previous_proc_count = nproc; 541131402Salfred 542131623Sdes pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc); 543131623Sdes if (nproc > onproc) 544131626Sdes pref = realloc(pref, sizeof(*pref) * (onproc = nproc)); 545131623Sdes if (pref == NULL || pbase == NULL) { 546131623Sdes (void) fprintf(stderr, "top: Out of memory.\n"); 547131623Sdes quit(23); 548131623Sdes } 549131623Sdes /* get a pointer to the states summary array */ 550131623Sdes si->procstates = process_states; 55124143Sjoerg 552131623Sdes /* set up flags which define what we are going to select */ 553131623Sdes show_idle = sel->idle; 554132024Sdes show_self = sel->self == -1; 555131623Sdes show_system = sel->system; 556131623Sdes show_uid = sel->uid != -1; 557131623Sdes show_command = sel->command != NULL; 55824143Sjoerg 559131623Sdes /* count up process states and get pointers to interesting procs */ 560131623Sdes total_procs = 0; 561131623Sdes active_procs = 0; 562131623Sdes total_inblock = 0; 563131623Sdes total_oublock = 0; 564131623Sdes total_majflt = 0; 565131623Sdes memset((char *)process_states, 0, sizeof(process_states)); 566131623Sdes prefp = pref; 567131626Sdes for (pp = pbase, i = 0; i < nproc; pp++, i++) { 568131619Sdes 569131623Sdes if (pp->ki_stat == 0) 570132024Sdes /* not in use */ 571132024Sdes continue; 572131619Sdes 573131623Sdes if (!show_self && pp->ki_pid == sel->self) 574131623Sdes /* skip self */ 575131623Sdes continue; 576131619Sdes 577131623Sdes if (!show_system && (pp->ki_flag & P_SYSTEM)) 578131623Sdes /* skip system process */ 579131623Sdes continue; 580131619Sdes 581133817Salfred p_io = get_io_stats(pp, &p_inblock, &p_oublock, &p_majflt, &p_vcsw, &p_ivcsw); 582131623Sdes total_inblock += p_inblock; 583131623Sdes total_oublock += p_oublock; 584131623Sdes total_majflt += p_majflt; 585131623Sdes total_procs++; 586131626Sdes process_states[pp->ki_stat]++; 587131619Sdes 588131623Sdes if (pp->ki_stat == SZOMB) 589131623Sdes /* skip zombies */ 590131623Sdes continue; 591131619Sdes 592131623Sdes if (displaymode == DISP_CPU && !show_idle && 593131623Sdes (pp->ki_pctcpu == 0 || pp->ki_stat != SRUN)) 594131623Sdes /* skip idle or non-running processes */ 595131623Sdes continue; 596131619Sdes 597131623Sdes if (displaymode == DISP_IO && !show_idle && p_io == 0) 598131623Sdes /* skip processes that aren't doing I/O */ 599131623Sdes continue; 600131619Sdes 601131623Sdes if (show_uid && pp->ki_ruid != (uid_t)sel->uid) 602131623Sdes /* skip processes which don't belong to the selected UID */ 603131623Sdes continue; 604131619Sdes 605131623Sdes /* 606131623Sdes * When not showing threads, take the first thread 607131623Sdes * for output and add the fields that we can from 608131623Sdes * the rest of the process's threads rather than 609131623Sdes * using the system's mostly-broken KERN_PROC_PROC. 610131623Sdes */ 611131626Sdes if (sel->thread || prev_pp == NULL || 612131626Sdes prev_pp->ki_pid != pp->ki_pid) { 613131623Sdes *prefp++ = pp; 614131623Sdes active_procs++; 615131623Sdes prev_pp = pp; 616131623Sdes } else { 617131623Sdes prev_pp->ki_pctcpu += pp->ki_pctcpu; 618131623Sdes } 619131623Sdes } 620131623Sdes 621131623Sdes /* if requested, sort the "interesting" processes */ 622131623Sdes if (compare != NULL) 623131626Sdes qsort(pref, active_procs, sizeof(*pref), compare); 62424143Sjoerg 625131623Sdes /* remember active and total counts */ 626131623Sdes si->p_total = total_procs; 627131623Sdes si->p_active = pref_len = active_procs; 62824143Sjoerg 629131623Sdes /* pass back a handle */ 630131623Sdes handle.next_proc = pref; 631131623Sdes handle.remaining = active_procs; 632131623Sdes return ((caddr_t)&handle); 63324143Sjoerg} 63424143Sjoerg 635131626Sdesstatic char fmt[128]; /* static area where result is built */ 63624143Sjoerg 637131310Salfredchar * 638131626Sdesformat_next_process(caddr_t handle, char *(*get_userid)(int)) 63924143Sjoerg{ 640131623Sdes struct kinfo_proc *pp; 641131623Sdes const struct kinfo_proc *oldp; 642131623Sdes long cputime; 643131623Sdes double pct; 644131623Sdes struct handle *hp; 645131623Sdes char status[16]; 646131623Sdes int state; 647131623Sdes struct rusage ru, *rup; 648131623Sdes long p_tot, s_tot; 64924143Sjoerg 650131623Sdes /* find and remember the next proc structure */ 651131623Sdes hp = (struct handle *)handle; 652131623Sdes pp = *(hp->next_proc++); 653131623Sdes hp->remaining--; 654131620Sdes 655131623Sdes /* get the process's command name */ 656131623Sdes if ((pp->ki_sflag & PS_INMEM) == 0) { 657131623Sdes /* 658131623Sdes * Print swapped processes as <pname> 659131623Sdes */ 660131626Sdes size_t len = strlen(pp->ki_comm); 661131626Sdes if (len > sizeof(pp->ki_comm) - 3) 662131626Sdes len = sizeof(pp->ki_comm) - 3; 663131626Sdes memmove(pp->ki_comm + 1, pp->ki_comm, len); 664131626Sdes pp->ki_comm[0] = '<'; 665131626Sdes pp->ki_comm[len + 1] = '>'; 666131626Sdes pp->ki_comm[len + 2] = '\0'; 667131623Sdes } 668131623Sdes 66924143Sjoerg /* 670131623Sdes * Convert the process's runtime from microseconds to seconds. This 671131623Sdes * time includes the interrupt time although that is not wanted here. 672131623Sdes * ps(1) is similarly sloppy. 67324143Sjoerg */ 674131623Sdes cputime = (pp->ki_runtime + 500000) / 1000000; 67524143Sjoerg 676131623Sdes /* calculate the base for cpu percentages */ 677131623Sdes pct = pctdouble(pp->ki_pctcpu); 67824143Sjoerg 679131623Sdes /* generate "STATE" field */ 680131623Sdes switch (state = pp->ki_stat) { 68124143Sjoerg case SRUN: 682131623Sdes if (smpmode && pp->ki_oncpu != 0xff) 683131623Sdes sprintf(status, "CPU%d", pp->ki_oncpu); 684131623Sdes else 685131623Sdes strcpy(status, "RUN"); 686131623Sdes break; 687104388Sjhb case SLOCK: 688131623Sdes if (pp->ki_kiflag & KI_LOCKBLOCK) { 689131623Sdes sprintf(status, "*%.6s", pp->ki_lockname); 690131623Sdes break; 691131623Sdes } 692131623Sdes /* fall through */ 69324143Sjoerg case SSLEEP: 694131623Sdes if (pp->ki_wmesg != NULL) { 695131623Sdes sprintf(status, "%.6s", pp->ki_wmesg); 696131623Sdes break; 697131623Sdes } 698131623Sdes /* FALLTHROUGH */ 69924143Sjoerg default: 70043720Sfenner 701131623Sdes if (state >= 0 && 702131623Sdes state < sizeof(state_abbrev) / sizeof(*state_abbrev)) 703131626Sdes sprintf(status, "%.6s", state_abbrev[state]); 704131623Sdes else 705131623Sdes sprintf(status, "?%5d", state); 706131623Sdes break; 707131623Sdes } 70824143Sjoerg 709131623Sdes if (displaymode == DISP_IO) { 710131623Sdes oldp = get_old_proc(pp); 711131623Sdes if (oldp != NULL) { 712131623Sdes ru.ru_inblock = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; 713131623Sdes ru.ru_oublock = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; 714131623Sdes ru.ru_majflt = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; 715133817Salfred ru.ru_nvcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; 716133817Salfred ru.ru_nivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; 717131623Sdes rup = &ru; 718131623Sdes } else { 719131623Sdes rup = RU(pp); 720131623Sdes } 721131623Sdes p_tot = rup->ru_inblock + rup->ru_oublock + rup->ru_majflt; 722131623Sdes s_tot = total_inblock + total_oublock + total_majflt; 723131402Salfred 724131623Sdes sprintf(fmt, io_Proc_format, 725131623Sdes pp->ki_pid, 726131623Sdes namelength, namelength, 727131623Sdes (*get_userid)(pp->ki_ruid), 728133817Salfred rup->ru_nvcsw, 729133817Salfred rup->ru_nivcsw, 730131626Sdes rup->ru_inblock, 731131626Sdes rup->ru_oublock, 732131626Sdes rup->ru_majflt, 733131626Sdes p_tot, 734131626Sdes s_tot == 0 ? 0.0 : (p_tot * 100.0 / s_tot), 735131623Sdes screen_width > cmdlengthdelta ? 736131623Sdes screen_width - cmdlengthdelta : 0, 737131623Sdes printable(pp->ki_comm)); 738131623Sdes return (fmt); 739131623Sdes } 740131623Sdes /* format this entry */ 741131623Sdes sprintf(fmt, 74227340Speter smpmode ? smp_Proc_format : up_Proc_format, 74369896Smckusick pp->ki_pid, 74427390Speter namelength, namelength, 74569896Smckusick (*get_userid)(pp->ki_ruid), 74672377Sjake pp->ki_pri.pri_level - PZERO, 74729904Speter 74829904Speter /* 749131620Sdes * normal time -> nice value -20 - +20 75029904Speter * real time 0 - 31 -> nice value -52 - -21 75129904Speter * idle time 0 - 31 -> nice value +21 - +52 75229904Speter */ 753131620Sdes (pp->ki_pri.pri_class == PRI_TIMESHARE ? 754131620Sdes pp->ki_nice - NZERO : 755131620Sdes (PRI_IS_REALTIME(pp->ki_pri.pri_class) ? 75672377Sjake (PRIO_MIN - 1 - (PRI_MAX_REALTIME - pp->ki_pri.pri_level)) : 757131620Sdes (PRIO_MAX + 1 + pp->ki_pri.pri_level - PRI_MIN_IDLE))), 75837100Sdt format_k2(PROCSIZE(pp)), 75969896Smckusick format_k2(pagetok(pp->ki_rssize)), 76024143Sjoerg status, 76169896Smckusick smpmode ? pp->ki_lastcpu : 0, 76224143Sjoerg format_time(cputime), 76341325Sdfr 100.0 * weighted_cpu(pct, pp), 76441325Sdfr 100.0 * pct, 76569375Sjhb screen_width > cmdlengthdelta ? 766131623Sdes screen_width - cmdlengthdelta : 767131623Sdes 0, 76869896Smckusick printable(pp->ki_comm)); 76924143Sjoerg 770131623Sdes /* return the result */ 771131623Sdes return (fmt); 77224143Sjoerg} 77324143Sjoerg 774131310Salfredstatic void 775131622Sdesgetsysctl(char *name, void *ptr, size_t len) 77624143Sjoerg{ 777131623Sdes size_t nlen = len; 778131310Salfred 779131623Sdes if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 780131623Sdes fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name, 781131623Sdes strerror(errno)); 782131623Sdes quit(23); 783131623Sdes } 784131623Sdes if (nlen != len) { 785131623Sdes fprintf(stderr, "top: sysctl(%s...) expected %lu, got %lu\n", name, 786131623Sdes (unsigned long)len, (unsigned long)nlen); 787131623Sdes quit(23); 788131623Sdes } 78924143Sjoerg} 79072951Srwatson 79138278Swosch/* comparison routines for qsort */ 79224143Sjoerg 793131402Salfredint 794131622Sdescompare_pid(const void *p1, const void *p2) 795131402Salfred{ 796131623Sdes const struct kinfo_proc * const *pp1 = p1; 797131623Sdes const struct kinfo_proc * const *pp2 = p2; 798131402Salfred 799131623Sdes if ((*pp2)->ki_pid < 0 || (*pp1)->ki_pid < 0) 800131623Sdes abort(); 801131402Salfred 802131623Sdes return ((*pp1)->ki_pid - (*pp2)->ki_pid); 803131402Salfred} 804131402Salfred 80524143Sjoerg/* 80624143Sjoerg * proc_compare - comparison function for "qsort" 80724143Sjoerg * Compares the resource consumption of two processes using five 808131620Sdes * distinct keys. The keys (in descending order of importance) are: 809131620Sdes * percent cpu, cpu ticks, state, resident set size, total virtual 810131620Sdes * memory usage. The process states are ordered as follows (from least 811131620Sdes * to most important): WAIT, zombie, sleep, stop, start, run. The 812131620Sdes * array declaration below maps a process state index into a number 813131620Sdes * that reflects this ordering. 81424143Sjoerg */ 81524143Sjoerg 816131626Sdesstatic int sorted_state[] = 81724143Sjoerg{ 818131623Sdes 0, /* not used */ 819131623Sdes 3, /* sleep */ 820131623Sdes 1, /* ABANDONED (WAIT) */ 821131623Sdes 6, /* run */ 822131623Sdes 5, /* start */ 823131623Sdes 2, /* zombie */ 824131623Sdes 4 /* stop */ 82524143Sjoerg}; 82638278Swosch 827131620Sdes 828131626Sdes#define ORDERKEY_PCTCPU(a, b) do { \ 829131627Sdes long diff = (long)(b)->ki_pctcpu - (long)(a)->ki_pctcpu; \ 830131626Sdes if (diff != 0) \ 831131626Sdes return (diff > 0 ? 1 : -1); \ 832131626Sdes} while (0) 83338278Swosch 834131626Sdes#define ORDERKEY_CPTICKS(a, b) do { \ 835131628Sdes int64_t diff = (int64_t)(b)->ki_runtime - (int64_t)(a)->ki_runtime; \ 836131626Sdes if (diff != 0) \ 837131626Sdes return (diff > 0 ? 1 : -1); \ 838131626Sdes} while (0) 83938278Swosch 840131626Sdes#define ORDERKEY_STATE(a, b) do { \ 841131626Sdes int diff = sorted_state[(b)->ki_stat] - sorted_state[(a)->ki_stat]; \ 842131626Sdes if (diff != 0) \ 843131626Sdes return (diff > 0 ? 1 : -1); \ 844131626Sdes} while (0) 84538278Swosch 846131626Sdes#define ORDERKEY_PRIO(a, b) do { \ 847131628Sdes int diff = (int)(b)->ki_pri.pri_level - (int)(a)->ki_pri.pri_level; \ 848131626Sdes if (diff != 0) \ 849131626Sdes return (diff > 0 ? 1 : -1); \ 850131626Sdes} while (0) 85138278Swosch 852131626Sdes#define ORDERKEY_RSSIZE(a, b) do { \ 853131628Sdes long diff = (long)(b)->ki_rssize - (long)(a)->ki_rssize; \ 854131626Sdes if (diff != 0) \ 855131626Sdes return (diff > 0 ? 1 : -1); \ 856131626Sdes} while (0) 85738278Swosch 858131626Sdes#define ORDERKEY_MEM(a, b) do { \ 859131628Sdes long diff = (long)PROCSIZE((b)) - (long)PROCSIZE((a)); \ 860131626Sdes if (diff != 0) \ 861131626Sdes return (diff > 0 ? 1 : -1); \ 862131626Sdes} while (0) 86338278Swosch 86438278Swosch/* compare_cpu - the comparison function for sorting by cpu percentage */ 86538278Swosch 86624143Sjoergint 86738278Swosch#ifdef ORDER 868131626Sdescompare_cpu(void *arg1, void *arg2) 86938278Swosch#else 870131626Sdesproc_compare(void *arg1, void *arg2) 87138278Swosch#endif 87224143Sjoerg{ 873131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 874131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 87524143Sjoerg 876131626Sdes ORDERKEY_PCTCPU(p1, p2); 877131626Sdes ORDERKEY_CPTICKS(p1, p2); 878131626Sdes ORDERKEY_STATE(p1, p2); 879131626Sdes ORDERKEY_PRIO(p1, p2); 880131626Sdes ORDERKEY_RSSIZE(p1, p2); 881131626Sdes ORDERKEY_MEM(p1, p2); 88224143Sjoerg 883131626Sdes return (0); 88424143Sjoerg} 88524143Sjoerg 88638278Swosch#ifdef ORDER 88738278Swosch/* compare routines */ 88838278Swoschint compare_size(), compare_res(), compare_time(), compare_prio(); 889133817Salfred/* io compare routines */ 890133817Salfredint compare_iototal(), compare_ioread(), compare_iowrite(), compare_iofault(), compare_vcsw(), compare_ivcsw(); 89124143Sjoerg 892133817Salfredint (*compares[])() = { 893131623Sdes compare_cpu, 894131623Sdes compare_size, 895131623Sdes compare_res, 896131623Sdes compare_time, 897131623Sdes compare_prio, 898133817Salfred compare_iototal, 899133817Salfred compare_ioread, 900133817Salfred compare_iowrite, 901133817Salfred compare_iofault, 902133817Salfred compare_vcsw, 903133817Salfred compare_ivcsw, 904131623Sdes NULL 90538278Swosch}; 90638278Swosch 90738278Swosch/* compare_size - the comparison function for sorting by total memory usage */ 90838278Swosch 90938278Swoschint 910131626Sdescompare_size(void *arg1, void *arg2) 91138278Swosch{ 912131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 913131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 91438278Swosch 915131626Sdes ORDERKEY_MEM(p1, p2); 916131626Sdes ORDERKEY_RSSIZE(p1, p2); 917131626Sdes ORDERKEY_PCTCPU(p1, p2); 918131626Sdes ORDERKEY_CPTICKS(p1, p2); 919131626Sdes ORDERKEY_STATE(p1, p2); 920131626Sdes ORDERKEY_PRIO(p1, p2); 92138278Swosch 922131626Sdes return (0); 92338278Swosch} 92438278Swosch 92538278Swosch/* compare_res - the comparison function for sorting by resident set size */ 92638278Swosch 92738278Swoschint 928131626Sdescompare_res(void *arg1, void *arg2) 92938278Swosch{ 930131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 931131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 93238278Swosch 933131626Sdes ORDERKEY_RSSIZE(p1, p2); 934131626Sdes ORDERKEY_MEM(p1, p2); 935131626Sdes ORDERKEY_PCTCPU(p1, p2); 936131626Sdes ORDERKEY_CPTICKS(p1, p2); 937131626Sdes ORDERKEY_STATE(p1, p2); 938131626Sdes ORDERKEY_PRIO(p1, p2); 93938278Swosch 940131626Sdes return (0); 94138278Swosch} 94238278Swosch 94338278Swosch/* compare_time - the comparison function for sorting by total cpu time */ 94438278Swosch 94538278Swoschint 946131626Sdescompare_time(void *arg1, void *arg2) 947131310Salfred{ 948131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 949131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 95038278Swosch 951131626Sdes ORDERKEY_CPTICKS(p1, p2); 952131626Sdes ORDERKEY_PCTCPU(p1, p2); 953131626Sdes ORDERKEY_STATE(p1, p2); 954131626Sdes ORDERKEY_PRIO(p1, p2); 955131626Sdes ORDERKEY_RSSIZE(p1, p2); 956131626Sdes ORDERKEY_MEM(p1, p2); 95738278Swosch 958131626Sdes return (0); 959131623Sdes} 960131310Salfred 961131626Sdes/* compare_prio - the comparison function for sorting by priority */ 96238278Swosch 96338278Swoschint 964131626Sdescompare_prio(void *arg1, void *arg2) 96538278Swosch{ 966131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 967131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 96838278Swosch 969131626Sdes ORDERKEY_PRIO(p1, p2); 970131626Sdes ORDERKEY_CPTICKS(p1, p2); 971131626Sdes ORDERKEY_PCTCPU(p1, p2); 972131626Sdes ORDERKEY_STATE(p1, p2); 973131626Sdes ORDERKEY_RSSIZE(p1, p2); 974131626Sdes ORDERKEY_MEM(p1, p2); 97538278Swosch 976131626Sdes return (0); 97738278Swosch} 97838278Swosch#endif 97938278Swosch 980131829Skeramida/* compare_io - the comparison function for sorting by total io */ 981131829Skeramida 982131402Salfredint 983131829Skeramida#ifdef ORDER 984131829Skeramidacompare_iototal(void *arg1, void *arg2) 985131829Skeramida#else 986131626Sdesio_compare(void *arg1, void *arg2) 987131829Skeramida#endif 988131402Salfred{ 989131626Sdes struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 990131626Sdes struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 991131402Salfred 992131626Sdes return (get_io_total(p2) - get_io_total(p1)); 993131402Salfred} 994131829Skeramida 995131829Skeramida#ifdef ORDER 996131829Skeramida 997131829Skeramidaint 998131829Skeramidacompare_ioread(void *arg1, void *arg2) 999131829Skeramida{ 1000131829Skeramida struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1001131829Skeramida struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1002131829Skeramida long dummy, inp1, inp2; 1003131829Skeramida 1004133817Salfred (void) get_io_stats(p1, &inp1, &dummy, &dummy, &dummy, &dummy); 1005133817Salfred (void) get_io_stats(p2, &inp2, &dummy, &dummy, &dummy, &dummy); 1006131829Skeramida 1007131829Skeramida return (inp2 - inp1); 1008131829Skeramida} 1009131829Skeramida 1010131829Skeramidaint 1011131829Skeramidacompare_iowrite(void *arg1, void *arg2) 1012131829Skeramida{ 1013131829Skeramida struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1014131829Skeramida struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1015131829Skeramida long dummy, oup1, oup2; 1016131829Skeramida 1017133817Salfred (void) get_io_stats(p1, &dummy, &oup1, &dummy, &dummy, &dummy); 1018133817Salfred (void) get_io_stats(p2, &dummy, &oup2, &dummy, &dummy, &dummy); 1019131829Skeramida 1020131829Skeramida return (oup2 - oup1); 1021131829Skeramida} 1022131829Skeramida 1023131829Skeramidaint 1024131829Skeramidacompare_iofault(void *arg1, void *arg2) 1025131829Skeramida{ 1026131829Skeramida struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1027131829Skeramida struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1028131829Skeramida long dummy, flp1, flp2; 1029131829Skeramida 1030133817Salfred (void) get_io_stats(p1, &dummy, &dummy, &flp1, &dummy, &dummy); 1031133817Salfred (void) get_io_stats(p2, &dummy, &dummy, &flp2, &dummy, &dummy); 1032131829Skeramida 1033131829Skeramida return (flp2 - flp1); 1034131829Skeramida} 1035131829Skeramida 1036133817Salfredint 1037133817Salfredcompare_vcsw(void *arg1, void *arg2) 1038133817Salfred{ 1039133817Salfred struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1040133817Salfred struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1041133817Salfred long dummy, flp1, flp2; 1042133817Salfred 1043133817Salfred (void) get_io_stats(p1, &dummy, &dummy, &dummy, &flp1, &dummy); 1044133817Salfred (void) get_io_stats(p2, &dummy, &dummy, &dummy, &flp2, &dummy); 1045133817Salfred 1046133817Salfred return (flp2 - flp1); 1047133817Salfred} 1048133817Salfred 1049133817Salfredint 1050133817Salfredcompare_ivcsw(void *arg1, void *arg2) 1051133817Salfred{ 1052133817Salfred struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1053133817Salfred struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1054133817Salfred long dummy, flp1, flp2; 1055133817Salfred 1056133817Salfred (void) get_io_stats(p1, &dummy, &dummy, &dummy, &dummy, &flp1); 1057133817Salfred (void) get_io_stats(p2, &dummy, &dummy, &dummy, &dummy, &flp2); 1058133817Salfred 1059133817Salfred return (flp2 - flp1); 1060133817Salfred} 1061133817Salfred 1062131829Skeramida#endif /* ORDER */ 1063131829Skeramida 106424143Sjoerg/* 106524143Sjoerg * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 106624143Sjoerg * the process does not exist. 106724143Sjoerg * It is EXTREMLY IMPORTANT that this function work correctly. 106824143Sjoerg * If top runs setuid root (as in SVR4), then this function 106924143Sjoerg * is the only thing that stands in the way of a serious 107024143Sjoerg * security problem. It validates requests for the "kill" 107124143Sjoerg * and "renice" commands. 107224143Sjoerg */ 107324143Sjoerg 1074131310Salfredint 1075131622Sdesproc_owner(int pid) 107624143Sjoerg{ 1077131623Sdes int cnt; 1078131623Sdes struct kinfo_proc **prefp; 1079131623Sdes struct kinfo_proc *pp; 108024143Sjoerg 1081131623Sdes prefp = pref; 1082131623Sdes cnt = pref_len; 1083131626Sdes while (--cnt >= 0) { 1084131623Sdes pp = *prefp++; 1085131623Sdes if (pp->ki_pid == (pid_t)pid) 1086131623Sdes return ((int)pp->ki_ruid); 108724143Sjoerg } 1088131623Sdes return (-1); 108924143Sjoerg} 109024143Sjoerg 109124143Sjoergint 1092131622Sdesswapmode(int *retavail, int *retfree) 109324143Sjoerg{ 109443053Sdillon int n; 109543053Sdillon int pagesize = getpagesize(); 109643053Sdillon struct kvm_swap swapary[1]; 109724143Sjoerg 109843053Sdillon *retavail = 0; 109943053Sdillon *retfree = 0; 110024143Sjoerg 110143053Sdillon#define CONVERT(v) ((quad_t)(v) * pagesize / 1024) 110224143Sjoerg 110343053Sdillon n = kvm_getswapinfo(kd, swapary, 1, 0); 110443697Sdillon if (n < 0 || swapary[0].ksw_total == 0) 1105131623Sdes return (0); 110624143Sjoerg 110743053Sdillon *retavail = CONVERT(swapary[0].ksw_total); 110843053Sdillon *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); 110924143Sjoerg 1110131626Sdes n = (int)(swapary[0].ksw_used * 100.0 / swapary[0].ksw_total); 1111131623Sdes return (n); 111243053Sdillon} 1113