machine.c revision 133817
1/* 2 * top - a top users display for Unix 3 * 4 * SYNOPSIS: For FreeBSD-2.x and later 5 * 6 * DESCRIPTION: 7 * Originally written for BSD4.4 system by Christos Zoulas. 8 * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider 9 * Order support hacked in from top-3.5beta6/machine/m_aix41.c 10 * by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/) 11 * 12 * This is the machine-dependent module for FreeBSD 2.2 13 * Works for: 14 * FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x 15 * 16 * LIBS: -lkvm 17 * 18 * AUTHOR: Christos Zoulas <christos@ee.cornell.edu> 19 * Steven Wallace <swallace@freebsd.org> 20 * Wolfram Schneider <wosch@FreeBSD.org> 21 * Thomas Moestl <tmoestl@gmx.net> 22 * 23 * $FreeBSD: head/usr.bin/top/machine.c 133817 2004-08-16 07:51:22Z alfred $ 24 */ 25 26#include <sys/param.h> 27#include <sys/errno.h> 28#include <sys/file.h> 29#include <sys/proc.h> 30#include <sys/resource.h> 31#include <sys/rtprio.h> 32#include <sys/signal.h> 33#include <sys/sysctl.h> 34#include <sys/time.h> 35#include <sys/user.h> 36#include <sys/vmmeter.h> 37 38#include <kvm.h> 39#include <math.h> 40#include <nlist.h> 41#include <paths.h> 42#include <pwd.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <unistd.h> 46 47#include "top.h" 48#include "machine.h" 49#include "screen.h" 50#include "utils.h" 51 52static void getsysctl(char *, void *, size_t); 53 54#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) 55 56extern char* printable(char *); 57int swapmode(int *retavail, int *retfree); 58static int smpmode; 59enum displaymodes displaymode; 60static int namelength; 61static int cmdlengthdelta; 62 63/* Prototypes for top internals */ 64void quit(int); 65int compare_pid(const void *a, const void *b); 66 67/* get_process_info passes back a handle. This is what it looks like: */ 68 69struct handle 70{ 71 struct kinfo_proc **next_proc; /* points to next valid proc pointer */ 72 int remaining; /* number of pointers remaining */ 73}; 74 75/* declarations for load_avg */ 76#include "loadavg.h" 77 78/* define what weighted cpu is. */ 79#define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \ 80 ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu)))) 81 82/* what we consider to be process size: */ 83#define PROCSIZE(pp) ((pp)->ki_size / 1024) 84 85#define RU(pp) (&(pp)->ki_rusage) 86#define RUTOT(pp) \ 87 (RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt) 88 89 90/* definitions for indices in the nlist array */ 91 92/* 93 * These definitions control the format of the per-process area 94 */ 95 96static char io_header[] = 97 " PID %-*.*s VCSW IVCSW READ WRITE FAULT TOTAL PERCENT COMMAND"; 98 99#define io_Proc_format \ 100 "%5d %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s" 101 102static char smp_header[] = 103 " PID %-*.*s PRI NICE SIZE RES STATE C TIME WCPU CPU COMMAND"; 104 105#define smp_Proc_format \ 106 "%5d %-*.*s %3d %4d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %.*s" 107 108static char up_header[] = 109 " PID %-*.*s PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 110 111#define up_Proc_format \ 112 "%5d %-*.*s %3d %4d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s" 113 114 115 116/* process state names for the "STATE" column of the display */ 117/* the extra nulls in the string "run" are for adding a slash and 118 the processor number when needed */ 119 120char *state_abbrev[] = 121{ 122 "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK" 123}; 124 125 126static kvm_t *kd; 127 128/* values that we stash away in _init and use in later routines */ 129 130static double logcpu; 131 132/* these are retrieved from the kernel in _init */ 133 134static load_avg ccpu; 135 136/* these are used in the get_ functions */ 137 138static int lastpid; 139 140/* these are for calculating cpu state percentages */ 141 142static long cp_time[CPUSTATES]; 143static long cp_old[CPUSTATES]; 144static long cp_diff[CPUSTATES]; 145 146/* these are for detailing the process states */ 147 148int process_states[8]; 149char *procstatenames[] = { 150 "", " starting, ", " running, ", " sleeping, ", " stopped, ", 151 " zombie, ", " waiting, ", " lock, ", 152 NULL 153}; 154 155/* these are for detailing the cpu states */ 156 157int cpu_states[CPUSTATES]; 158char *cpustatenames[] = { 159 "user", "nice", "system", "interrupt", "idle", NULL 160}; 161 162/* these are for detailing the memory statistics */ 163 164int memory_stats[7]; 165char *memorynames[] = { 166 /* 0 1 2 3 4 5 */ 167 "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free", 168 NULL 169}; 170 171int swap_stats[7]; 172char *swapnames[] = { 173 /* 0 1 2 3 4 5 */ 174 "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", 175 NULL 176}; 177 178 179/* these are for keeping track of the proc array */ 180 181static int nproc; 182static int onproc = -1; 183static int pref_len; 184static struct kinfo_proc *pbase; 185static struct kinfo_proc **pref; 186static struct kinfo_proc *previous_procs; 187static struct kinfo_proc **previous_pref; 188static int previous_proc_count = 0; 189static int previous_proc_count_max = 0; 190 191/* total number of io operations */ 192static long total_inblock; 193static long total_oublock; 194static long total_majflt; 195 196/* these are for getting the memory statistics */ 197 198static int pageshift; /* log base 2 of the pagesize */ 199 200/* define pagetok in terms of pageshift */ 201 202#define pagetok(size) ((size) << pageshift) 203 204/* useful externals */ 205long percentages(); 206 207#ifdef ORDER 208/* 209 * Sorting orders. One vector per display mode. 210 * The first element is the default for each mode. 211 */ 212char *ordernames[] = { 213 "cpu", "size", "res", "time", "pri", 214 "total", "read", "write", "fault", "vcsw", "ivcsw", NULL 215}; 216#endif 217 218int 219machine_init(struct statics *statics) 220{ 221 int pagesize; 222 size_t modelen; 223 struct passwd *pw; 224 225 modelen = sizeof(smpmode); 226 if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 && 227 sysctlbyname("kern.smp.active", &smpmode, &modelen, NULL, 0) < 0) || 228 modelen != sizeof(smpmode)) 229 smpmode = 0; 230 231 while ((pw = getpwent()) != NULL) { 232 if (strlen(pw->pw_name) > namelength) 233 namelength = strlen(pw->pw_name); 234 } 235 if (namelength < 8) 236 namelength = 8; 237 if (smpmode && namelength > 13) 238 namelength = 13; 239 else if (namelength > 15) 240 namelength = 15; 241 242 kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); 243 if (kd == NULL) 244 return (-1); 245 246 GETSYSCTL("kern.ccpu", ccpu); 247 248 /* this is used in calculating WCPU -- calculate it ahead of time */ 249 logcpu = log(loaddouble(ccpu)); 250 251 pbase = NULL; 252 pref = NULL; 253 nproc = 0; 254 onproc = -1; 255 /* get the page size with "getpagesize" and calculate pageshift from it */ 256 pagesize = getpagesize(); 257 pageshift = 0; 258 while (pagesize > 1) { 259 pageshift++; 260 pagesize >>= 1; 261 } 262 263 /* we only need the amount of log(2)1024 for our conversion */ 264 pageshift -= LOG1024; 265 266 /* fill in the statics information */ 267 statics->procstate_names = procstatenames; 268 statics->cpustate_names = cpustatenames; 269 statics->memory_names = memorynames; 270 statics->swap_names = swapnames; 271#ifdef ORDER 272 statics->order_names = ordernames; 273#endif 274 275 /* all done! */ 276 return (0); 277} 278 279char * 280format_header(char *uname_field) 281{ 282 static char Header[128]; 283 const char *prehead; 284 285 switch (displaymode) { 286 case DISP_CPU: 287 prehead = smpmode ? smp_header : up_header; 288 break; 289 case DISP_IO: 290 prehead = io_header; 291 break; 292 } 293 294 snprintf(Header, sizeof(Header), prehead, 295 namelength, namelength, uname_field); 296 297 cmdlengthdelta = strlen(Header) - 7; 298 299 return (Header); 300} 301 302static int swappgsin = -1; 303static int swappgsout = -1; 304extern struct timeval timeout; 305 306void 307get_system_info(struct system_info *si) 308{ 309 long total; 310 struct loadavg sysload; 311 int mib[2]; 312 struct timeval boottime; 313 size_t bt_size; 314 int i; 315 316 /* get the cp_time array */ 317 GETSYSCTL("kern.cp_time", cp_time); 318 GETSYSCTL("vm.loadavg", sysload); 319 GETSYSCTL("kern.lastpid", lastpid); 320 321 /* convert load averages to doubles */ 322 for (i = 0; i < 3; i++) 323 si->load_avg[i] = (double)sysload.ldavg[i] / sysload.fscale; 324 325 /* convert cp_time counts to percentages */ 326 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 327 328 /* sum memory & swap statistics */ 329 { 330 static unsigned int swap_delay = 0; 331 static int swapavail = 0; 332 static int swapfree = 0; 333 static int bufspace = 0; 334 static int nspgsin, nspgsout; 335 336 GETSYSCTL("vfs.bufspace", bufspace); 337 GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]); 338 GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]); 339 GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]); 340 GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]); 341 GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]); 342 GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin); 343 GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout); 344 /* convert memory stats to Kbytes */ 345 memory_stats[0] = pagetok(memory_stats[0]); 346 memory_stats[1] = pagetok(memory_stats[1]); 347 memory_stats[2] = pagetok(memory_stats[2]); 348 memory_stats[3] = pagetok(memory_stats[3]); 349 memory_stats[4] = bufspace / 1024; 350 memory_stats[5] = pagetok(memory_stats[5]); 351 memory_stats[6] = -1; 352 353 /* first interval */ 354 if (swappgsin < 0) { 355 swap_stats[4] = 0; 356 swap_stats[5] = 0; 357 } 358 359 /* compute differences between old and new swap statistic */ 360 else { 361 swap_stats[4] = pagetok(((nspgsin - swappgsin))); 362 swap_stats[5] = pagetok(((nspgsout - swappgsout))); 363 } 364 365 swappgsin = nspgsin; 366 swappgsout = nspgsout; 367 368 /* call CPU heavy swapmode() only for changes */ 369 if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) { 370 swap_stats[3] = swapmode(&swapavail, &swapfree); 371 swap_stats[0] = swapavail; 372 swap_stats[1] = swapavail - swapfree; 373 swap_stats[2] = swapfree; 374 } 375 swap_delay = 1; 376 swap_stats[6] = -1; 377 } 378 379 /* set arrays and strings */ 380 si->cpustates = cpu_states; 381 si->memory = memory_stats; 382 si->swap = swap_stats; 383 384 385 if (lastpid > 0) { 386 si->last_pid = lastpid; 387 } else { 388 si->last_pid = -1; 389 } 390 391 /* 392 * Print how long system has been up. 393 * (Found by looking getting "boottime" from the kernel) 394 */ 395 mib[0] = CTL_KERN; 396 mib[1] = KERN_BOOTTIME; 397 bt_size = sizeof(boottime); 398 if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 && 399 boottime.tv_sec != 0) { 400 si->boottime = boottime; 401 } else { 402 si->boottime.tv_sec = -1; 403 } 404} 405 406#define NOPROC ((void *)-1) 407 408/* 409 * We need to compare data from the old process entry with the new 410 * process entry. 411 * To facilitate doing this quickly we stash a pointer in the kinfo_proc 412 * structure to cache the mapping. We also use a negative cache pointer 413 * of NOPROC to avoid duplicate lookups. 414 * XXX: this could be done when the actual processes are fetched, we do 415 * it here out of laziness. 416 */ 417const struct kinfo_proc * 418get_old_proc(struct kinfo_proc *pp) 419{ 420 struct kinfo_proc **oldpp, *oldp; 421 422 /* 423 * If this is the first fetch of the kinfo_procs then we don't have 424 * any previous entries. 425 */ 426 if (previous_proc_count == 0) 427 return (NULL); 428 /* negative cache? */ 429 if (pp->ki_udata == NOPROC) 430 return (NULL); 431 /* cached? */ 432 if (pp->ki_udata != NULL) 433 return (pp->ki_udata); 434 /* 435 * Not cached, 436 * 1) look up based on pid. 437 * 2) compare process start. 438 * If we fail here, then setup a negative cache entry, otherwise 439 * cache it. 440 */ 441 oldpp = bsearch(&pp, previous_pref, previous_proc_count, 442 sizeof(*previous_pref), compare_pid); 443 if (oldpp == NULL) { 444 pp->ki_udata = NOPROC; 445 return (NULL); 446 } 447 oldp = *oldpp; 448 if (bcmp(&oldp->ki_start, &pp->ki_start, sizeof(pp->ki_start)) != 0) { 449 pp->ki_udata = NOPROC; 450 return (NULL); 451 } 452 pp->ki_udata = oldp; 453 return (oldp); 454} 455 456/* 457 * Return the total amount of IO done in blocks in/out and faults. 458 * store the values individually in the pointers passed in. 459 */ 460long 461get_io_stats(struct kinfo_proc *pp, long *inp, long *oup, long *flp, long *vcsw, long *ivcsw) 462{ 463 const struct kinfo_proc *oldp; 464 static struct kinfo_proc dummy; 465 long ret; 466 467 oldp = get_old_proc(pp); 468 if (oldp == NULL) { 469 bzero(&dummy, sizeof(dummy)); 470 oldp = &dummy; 471 } 472 473 *inp = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; 474 *oup = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; 475 *flp = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; 476 *vcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; 477 *ivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; 478 ret = 479 (RU(pp)->ru_inblock - RU(oldp)->ru_inblock) + 480 (RU(pp)->ru_oublock - RU(oldp)->ru_oublock) + 481 (RU(pp)->ru_majflt - RU(oldp)->ru_majflt); 482 return (ret); 483} 484 485/* 486 * Return the total number of block in/out and faults by a process. 487 */ 488long 489get_io_total(struct kinfo_proc *pp) 490{ 491 long dummy; 492 493 return (get_io_stats(pp, &dummy, &dummy, &dummy, &dummy, &dummy)); 494} 495 496static struct handle handle; 497 498caddr_t 499get_process_info(struct system_info *si, struct process_select *sel, 500 int (*compare)(const void *, const void *)) 501{ 502 int i; 503 int total_procs; 504 long p_io; 505 long p_inblock, p_oublock, p_majflt, p_vcsw, p_ivcsw; 506 int active_procs; 507 struct kinfo_proc **prefp; 508 struct kinfo_proc *pp; 509 struct kinfo_proc *prev_pp = NULL; 510 511 /* these are copied out of sel for speed */ 512 int show_idle; 513 int show_self; 514 int show_system; 515 int show_uid; 516 int show_command; 517 518 /* 519 * Save the previous process info. 520 */ 521 if (previous_proc_count_max < nproc) { 522 free(previous_procs); 523 previous_procs = malloc(nproc * sizeof(*previous_procs)); 524 free(previous_pref); 525 previous_pref = malloc(nproc * sizeof(*previous_pref)); 526 if (previous_procs == NULL || previous_pref == NULL) { 527 (void) fprintf(stderr, "top: Out of memory.\n"); 528 quit(23); 529 } 530 previous_proc_count_max = nproc; 531 } 532 if (nproc) { 533 for (i = 0; i < nproc; i++) 534 previous_pref[i] = &previous_procs[i]; 535 bcopy(pbase, previous_procs, nproc * sizeof(*previous_procs)); 536 qsort(previous_pref, nproc, sizeof(*previous_pref), compare_pid); 537 } 538 previous_proc_count = nproc; 539 540 pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc); 541 if (nproc > onproc) 542 pref = realloc(pref, sizeof(*pref) * (onproc = nproc)); 543 if (pref == NULL || pbase == NULL) { 544 (void) fprintf(stderr, "top: Out of memory.\n"); 545 quit(23); 546 } 547 /* get a pointer to the states summary array */ 548 si->procstates = process_states; 549 550 /* set up flags which define what we are going to select */ 551 show_idle = sel->idle; 552 show_self = sel->self == -1; 553 show_system = sel->system; 554 show_uid = sel->uid != -1; 555 show_command = sel->command != NULL; 556 557 /* count up process states and get pointers to interesting procs */ 558 total_procs = 0; 559 active_procs = 0; 560 total_inblock = 0; 561 total_oublock = 0; 562 total_majflt = 0; 563 memset((char *)process_states, 0, sizeof(process_states)); 564 prefp = pref; 565 for (pp = pbase, i = 0; i < nproc; pp++, i++) { 566 567 if (pp->ki_stat == 0) 568 /* not in use */ 569 continue; 570 571 if (!show_self && pp->ki_pid == sel->self) 572 /* skip self */ 573 continue; 574 575 if (!show_system && (pp->ki_flag & P_SYSTEM)) 576 /* skip system process */ 577 continue; 578 579 p_io = get_io_stats(pp, &p_inblock, &p_oublock, &p_majflt, &p_vcsw, &p_ivcsw); 580 total_inblock += p_inblock; 581 total_oublock += p_oublock; 582 total_majflt += p_majflt; 583 total_procs++; 584 process_states[pp->ki_stat]++; 585 586 if (pp->ki_stat == SZOMB) 587 /* skip zombies */ 588 continue; 589 590 if (displaymode == DISP_CPU && !show_idle && 591 (pp->ki_pctcpu == 0 || pp->ki_stat != SRUN)) 592 /* skip idle or non-running processes */ 593 continue; 594 595 if (displaymode == DISP_IO && !show_idle && p_io == 0) 596 /* skip processes that aren't doing I/O */ 597 continue; 598 599 if (show_uid && pp->ki_ruid != (uid_t)sel->uid) 600 /* skip processes which don't belong to the selected UID */ 601 continue; 602 603 /* 604 * When not showing threads, take the first thread 605 * for output and add the fields that we can from 606 * the rest of the process's threads rather than 607 * using the system's mostly-broken KERN_PROC_PROC. 608 */ 609 if (sel->thread || prev_pp == NULL || 610 prev_pp->ki_pid != pp->ki_pid) { 611 *prefp++ = pp; 612 active_procs++; 613 prev_pp = pp; 614 } else { 615 prev_pp->ki_pctcpu += pp->ki_pctcpu; 616 } 617 } 618 619 /* if requested, sort the "interesting" processes */ 620 if (compare != NULL) 621 qsort(pref, active_procs, sizeof(*pref), compare); 622 623 /* remember active and total counts */ 624 si->p_total = total_procs; 625 si->p_active = pref_len = active_procs; 626 627 /* pass back a handle */ 628 handle.next_proc = pref; 629 handle.remaining = active_procs; 630 return ((caddr_t)&handle); 631} 632 633static char fmt[128]; /* static area where result is built */ 634 635char * 636format_next_process(caddr_t handle, char *(*get_userid)(int)) 637{ 638 struct kinfo_proc *pp; 639 const struct kinfo_proc *oldp; 640 long cputime; 641 double pct; 642 struct handle *hp; 643 char status[16]; 644 int state; 645 struct rusage ru, *rup; 646 long p_tot, s_tot; 647 648 /* find and remember the next proc structure */ 649 hp = (struct handle *)handle; 650 pp = *(hp->next_proc++); 651 hp->remaining--; 652 653 /* get the process's command name */ 654 if ((pp->ki_sflag & PS_INMEM) == 0) { 655 /* 656 * Print swapped processes as <pname> 657 */ 658 size_t len = strlen(pp->ki_comm); 659 if (len > sizeof(pp->ki_comm) - 3) 660 len = sizeof(pp->ki_comm) - 3; 661 memmove(pp->ki_comm + 1, pp->ki_comm, len); 662 pp->ki_comm[0] = '<'; 663 pp->ki_comm[len + 1] = '>'; 664 pp->ki_comm[len + 2] = '\0'; 665 } 666 667 /* 668 * Convert the process's runtime from microseconds to seconds. This 669 * time includes the interrupt time although that is not wanted here. 670 * ps(1) is similarly sloppy. 671 */ 672 cputime = (pp->ki_runtime + 500000) / 1000000; 673 674 /* calculate the base for cpu percentages */ 675 pct = pctdouble(pp->ki_pctcpu); 676 677 /* generate "STATE" field */ 678 switch (state = pp->ki_stat) { 679 case SRUN: 680 if (smpmode && pp->ki_oncpu != 0xff) 681 sprintf(status, "CPU%d", pp->ki_oncpu); 682 else 683 strcpy(status, "RUN"); 684 break; 685 case SLOCK: 686 if (pp->ki_kiflag & KI_LOCKBLOCK) { 687 sprintf(status, "*%.6s", pp->ki_lockname); 688 break; 689 } 690 /* fall through */ 691 case SSLEEP: 692 if (pp->ki_wmesg != NULL) { 693 sprintf(status, "%.6s", pp->ki_wmesg); 694 break; 695 } 696 /* FALLTHROUGH */ 697 default: 698 699 if (state >= 0 && 700 state < sizeof(state_abbrev) / sizeof(*state_abbrev)) 701 sprintf(status, "%.6s", state_abbrev[state]); 702 else 703 sprintf(status, "?%5d", state); 704 break; 705 } 706 707 if (displaymode == DISP_IO) { 708 oldp = get_old_proc(pp); 709 if (oldp != NULL) { 710 ru.ru_inblock = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; 711 ru.ru_oublock = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; 712 ru.ru_majflt = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; 713 ru.ru_nvcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; 714 ru.ru_nivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; 715 rup = &ru; 716 } else { 717 rup = RU(pp); 718 } 719 p_tot = rup->ru_inblock + rup->ru_oublock + rup->ru_majflt; 720 s_tot = total_inblock + total_oublock + total_majflt; 721 722 sprintf(fmt, io_Proc_format, 723 pp->ki_pid, 724 namelength, namelength, 725 (*get_userid)(pp->ki_ruid), 726 rup->ru_nvcsw, 727 rup->ru_nivcsw, 728 rup->ru_inblock, 729 rup->ru_oublock, 730 rup->ru_majflt, 731 p_tot, 732 s_tot == 0 ? 0.0 : (p_tot * 100.0 / s_tot), 733 screen_width > cmdlengthdelta ? 734 screen_width - cmdlengthdelta : 0, 735 printable(pp->ki_comm)); 736 return (fmt); 737 } 738 /* format this entry */ 739 sprintf(fmt, 740 smpmode ? smp_Proc_format : up_Proc_format, 741 pp->ki_pid, 742 namelength, namelength, 743 (*get_userid)(pp->ki_ruid), 744 pp->ki_pri.pri_level - PZERO, 745 746 /* 747 * normal time -> nice value -20 - +20 748 * real time 0 - 31 -> nice value -52 - -21 749 * idle time 0 - 31 -> nice value +21 - +52 750 */ 751 (pp->ki_pri.pri_class == PRI_TIMESHARE ? 752 pp->ki_nice - NZERO : 753 (PRI_IS_REALTIME(pp->ki_pri.pri_class) ? 754 (PRIO_MIN - 1 - (PRI_MAX_REALTIME - pp->ki_pri.pri_level)) : 755 (PRIO_MAX + 1 + pp->ki_pri.pri_level - PRI_MIN_IDLE))), 756 format_k2(PROCSIZE(pp)), 757 format_k2(pagetok(pp->ki_rssize)), 758 status, 759 smpmode ? pp->ki_lastcpu : 0, 760 format_time(cputime), 761 100.0 * weighted_cpu(pct, pp), 762 100.0 * pct, 763 screen_width > cmdlengthdelta ? 764 screen_width - cmdlengthdelta : 765 0, 766 printable(pp->ki_comm)); 767 768 /* return the result */ 769 return (fmt); 770} 771 772static void 773getsysctl(char *name, void *ptr, size_t len) 774{ 775 size_t nlen = len; 776 777 if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 778 fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name, 779 strerror(errno)); 780 quit(23); 781 } 782 if (nlen != len) { 783 fprintf(stderr, "top: sysctl(%s...) expected %lu, got %lu\n", name, 784 (unsigned long)len, (unsigned long)nlen); 785 quit(23); 786 } 787} 788 789/* comparison routines for qsort */ 790 791int 792compare_pid(const void *p1, const void *p2) 793{ 794 const struct kinfo_proc * const *pp1 = p1; 795 const struct kinfo_proc * const *pp2 = p2; 796 797 if ((*pp2)->ki_pid < 0 || (*pp1)->ki_pid < 0) 798 abort(); 799 800 return ((*pp1)->ki_pid - (*pp2)->ki_pid); 801} 802 803/* 804 * proc_compare - comparison function for "qsort" 805 * Compares the resource consumption of two processes using five 806 * distinct keys. The keys (in descending order of importance) are: 807 * percent cpu, cpu ticks, state, resident set size, total virtual 808 * memory usage. The process states are ordered as follows (from least 809 * to most important): WAIT, zombie, sleep, stop, start, run. The 810 * array declaration below maps a process state index into a number 811 * that reflects this ordering. 812 */ 813 814static int sorted_state[] = 815{ 816 0, /* not used */ 817 3, /* sleep */ 818 1, /* ABANDONED (WAIT) */ 819 6, /* run */ 820 5, /* start */ 821 2, /* zombie */ 822 4 /* stop */ 823}; 824 825 826#define ORDERKEY_PCTCPU(a, b) do { \ 827 long diff = (long)(b)->ki_pctcpu - (long)(a)->ki_pctcpu; \ 828 if (diff != 0) \ 829 return (diff > 0 ? 1 : -1); \ 830} while (0) 831 832#define ORDERKEY_CPTICKS(a, b) do { \ 833 int64_t diff = (int64_t)(b)->ki_runtime - (int64_t)(a)->ki_runtime; \ 834 if (diff != 0) \ 835 return (diff > 0 ? 1 : -1); \ 836} while (0) 837 838#define ORDERKEY_STATE(a, b) do { \ 839 int diff = sorted_state[(b)->ki_stat] - sorted_state[(a)->ki_stat]; \ 840 if (diff != 0) \ 841 return (diff > 0 ? 1 : -1); \ 842} while (0) 843 844#define ORDERKEY_PRIO(a, b) do { \ 845 int diff = (int)(b)->ki_pri.pri_level - (int)(a)->ki_pri.pri_level; \ 846 if (diff != 0) \ 847 return (diff > 0 ? 1 : -1); \ 848} while (0) 849 850#define ORDERKEY_RSSIZE(a, b) do { \ 851 long diff = (long)(b)->ki_rssize - (long)(a)->ki_rssize; \ 852 if (diff != 0) \ 853 return (diff > 0 ? 1 : -1); \ 854} while (0) 855 856#define ORDERKEY_MEM(a, b) do { \ 857 long diff = (long)PROCSIZE((b)) - (long)PROCSIZE((a)); \ 858 if (diff != 0) \ 859 return (diff > 0 ? 1 : -1); \ 860} while (0) 861 862/* compare_cpu - the comparison function for sorting by cpu percentage */ 863 864int 865#ifdef ORDER 866compare_cpu(void *arg1, void *arg2) 867#else 868proc_compare(void *arg1, void *arg2) 869#endif 870{ 871 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 872 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 873 874 ORDERKEY_PCTCPU(p1, p2); 875 ORDERKEY_CPTICKS(p1, p2); 876 ORDERKEY_STATE(p1, p2); 877 ORDERKEY_PRIO(p1, p2); 878 ORDERKEY_RSSIZE(p1, p2); 879 ORDERKEY_MEM(p1, p2); 880 881 return (0); 882} 883 884#ifdef ORDER 885/* compare routines */ 886int compare_size(), compare_res(), compare_time(), compare_prio(); 887/* io compare routines */ 888int compare_iototal(), compare_ioread(), compare_iowrite(), compare_iofault(), compare_vcsw(), compare_ivcsw(); 889 890int (*compares[])() = { 891 compare_cpu, 892 compare_size, 893 compare_res, 894 compare_time, 895 compare_prio, 896 compare_iototal, 897 compare_ioread, 898 compare_iowrite, 899 compare_iofault, 900 compare_vcsw, 901 compare_ivcsw, 902 NULL 903}; 904 905/* compare_size - the comparison function for sorting by total memory usage */ 906 907int 908compare_size(void *arg1, void *arg2) 909{ 910 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 911 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 912 913 ORDERKEY_MEM(p1, p2); 914 ORDERKEY_RSSIZE(p1, p2); 915 ORDERKEY_PCTCPU(p1, p2); 916 ORDERKEY_CPTICKS(p1, p2); 917 ORDERKEY_STATE(p1, p2); 918 ORDERKEY_PRIO(p1, p2); 919 920 return (0); 921} 922 923/* compare_res - the comparison function for sorting by resident set size */ 924 925int 926compare_res(void *arg1, void *arg2) 927{ 928 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 929 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 930 931 ORDERKEY_RSSIZE(p1, p2); 932 ORDERKEY_MEM(p1, p2); 933 ORDERKEY_PCTCPU(p1, p2); 934 ORDERKEY_CPTICKS(p1, p2); 935 ORDERKEY_STATE(p1, p2); 936 ORDERKEY_PRIO(p1, p2); 937 938 return (0); 939} 940 941/* compare_time - the comparison function for sorting by total cpu time */ 942 943int 944compare_time(void *arg1, void *arg2) 945{ 946 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 947 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 948 949 ORDERKEY_CPTICKS(p1, p2); 950 ORDERKEY_PCTCPU(p1, p2); 951 ORDERKEY_STATE(p1, p2); 952 ORDERKEY_PRIO(p1, p2); 953 ORDERKEY_RSSIZE(p1, p2); 954 ORDERKEY_MEM(p1, p2); 955 956 return (0); 957} 958 959/* compare_prio - the comparison function for sorting by priority */ 960 961int 962compare_prio(void *arg1, void *arg2) 963{ 964 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 965 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 966 967 ORDERKEY_PRIO(p1, p2); 968 ORDERKEY_CPTICKS(p1, p2); 969 ORDERKEY_PCTCPU(p1, p2); 970 ORDERKEY_STATE(p1, p2); 971 ORDERKEY_RSSIZE(p1, p2); 972 ORDERKEY_MEM(p1, p2); 973 974 return (0); 975} 976#endif 977 978/* compare_io - the comparison function for sorting by total io */ 979 980int 981#ifdef ORDER 982compare_iototal(void *arg1, void *arg2) 983#else 984io_compare(void *arg1, void *arg2) 985#endif 986{ 987 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 988 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 989 990 return (get_io_total(p2) - get_io_total(p1)); 991} 992 993#ifdef ORDER 994 995int 996compare_ioread(void *arg1, void *arg2) 997{ 998 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 999 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1000 long dummy, inp1, inp2; 1001 1002 (void) get_io_stats(p1, &inp1, &dummy, &dummy, &dummy, &dummy); 1003 (void) get_io_stats(p2, &inp2, &dummy, &dummy, &dummy, &dummy); 1004 1005 return (inp2 - inp1); 1006} 1007 1008int 1009compare_iowrite(void *arg1, void *arg2) 1010{ 1011 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1012 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1013 long dummy, oup1, oup2; 1014 1015 (void) get_io_stats(p1, &dummy, &oup1, &dummy, &dummy, &dummy); 1016 (void) get_io_stats(p2, &dummy, &oup2, &dummy, &dummy, &dummy); 1017 1018 return (oup2 - oup1); 1019} 1020 1021int 1022compare_iofault(void *arg1, void *arg2) 1023{ 1024 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1025 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1026 long dummy, flp1, flp2; 1027 1028 (void) get_io_stats(p1, &dummy, &dummy, &flp1, &dummy, &dummy); 1029 (void) get_io_stats(p2, &dummy, &dummy, &flp2, &dummy, &dummy); 1030 1031 return (flp2 - flp1); 1032} 1033 1034int 1035compare_vcsw(void *arg1, void *arg2) 1036{ 1037 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1038 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1039 long dummy, flp1, flp2; 1040 1041 (void) get_io_stats(p1, &dummy, &dummy, &dummy, &flp1, &dummy); 1042 (void) get_io_stats(p2, &dummy, &dummy, &dummy, &flp2, &dummy); 1043 1044 return (flp2 - flp1); 1045} 1046 1047int 1048compare_ivcsw(void *arg1, void *arg2) 1049{ 1050 struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; 1051 struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; 1052 long dummy, flp1, flp2; 1053 1054 (void) get_io_stats(p1, &dummy, &dummy, &dummy, &dummy, &flp1); 1055 (void) get_io_stats(p2, &dummy, &dummy, &dummy, &dummy, &flp2); 1056 1057 return (flp2 - flp1); 1058} 1059 1060#endif /* ORDER */ 1061 1062/* 1063 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 1064 * the process does not exist. 1065 * It is EXTREMLY IMPORTANT that this function work correctly. 1066 * If top runs setuid root (as in SVR4), then this function 1067 * is the only thing that stands in the way of a serious 1068 * security problem. It validates requests for the "kill" 1069 * and "renice" commands. 1070 */ 1071 1072int 1073proc_owner(int pid) 1074{ 1075 int cnt; 1076 struct kinfo_proc **prefp; 1077 struct kinfo_proc *pp; 1078 1079 prefp = pref; 1080 cnt = pref_len; 1081 while (--cnt >= 0) { 1082 pp = *prefp++; 1083 if (pp->ki_pid == (pid_t)pid) 1084 return ((int)pp->ki_ruid); 1085 } 1086 return (-1); 1087} 1088 1089int 1090swapmode(int *retavail, int *retfree) 1091{ 1092 int n; 1093 int pagesize = getpagesize(); 1094 struct kvm_swap swapary[1]; 1095 1096 *retavail = 0; 1097 *retfree = 0; 1098 1099#define CONVERT(v) ((quad_t)(v) * pagesize / 1024) 1100 1101 n = kvm_getswapinfo(kd, swapary, 1, 0); 1102 if (n < 0 || swapary[0].ksw_total == 0) 1103 return (0); 1104 1105 *retavail = CONVERT(swapary[0].ksw_total); 1106 *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); 1107 1108 n = (int)(swapary[0].ksw_used * 100.0 / swapary[0].ksw_total); 1109 return (n); 1110} 1111