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