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