1/* vi: set sw=4 ts=4: */ 2/* 3 * A tiny 'top' utility. 4 * 5 * This is written specifically for the linux /proc/<PID>/stat(m) 6 * files format. 7 8 * This reads the PIDs of all processes and their status and shows 9 * the status of processes (first ones that fit to screen) at given 10 * intervals. 11 * 12 * NOTES: 13 * - At startup this changes to /proc, all the reads are then 14 * relative to that. 15 * 16 * (C) Eero Tamminen <oak at welho dot com> 17 * 18 * Rewritten by Vladimir Oleynik (C) 2002 <dzo@simtreas.ru> 19 */ 20 21/* Original code Copyrights */ 22/* 23 * Copyright (c) 1992 Branko Lankester 24 * Copyright (c) 1992 Roger Binns 25 * Copyright (C) 1994-1996 Charles L. Blake. 26 * Copyright (C) 1992-1998 Michael K. Johnson 27 * May be distributed under the conditions of the 28 * GNU Library General Public License 29 */ 30 31#include "libbb.h" 32 33 34typedef struct top_status_t { 35 unsigned long vsz; 36#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 37 unsigned long ticks; 38 unsigned pcpu; /* delta of ticks */ 39#endif 40 unsigned pid, ppid; 41 unsigned uid; 42 char state[4]; 43 char comm[COMM_LEN]; 44} top_status_t; 45 46typedef struct jiffy_counts_t { 47 unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal; 48 unsigned long long total; 49 unsigned long long busy; 50} jiffy_counts_t; 51 52/* This structure stores some critical information from one frame to 53 the next. Used for finding deltas. */ 54typedef struct save_hist { 55 unsigned long ticks; 56 unsigned pid; 57} save_hist; 58 59typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q); 60 61enum { SORT_DEPTH = 3 }; 62 63struct globals { 64 top_status_t *top; 65 int ntop; 66#if ENABLE_FEATURE_USE_TERMIOS 67 struct termios initial_settings; 68#endif 69#if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 70 cmp_funcp sort_function; 71#else 72 cmp_funcp sort_function[SORT_DEPTH]; 73 struct save_hist *prev_hist; 74 int prev_hist_count; 75 jiffy_counts_t jif, prev_jif; 76 /* int hist_iterations; */ 77 unsigned total_pcpu; 78 /* unsigned long total_vsz; */ 79#endif 80}; 81#define G (*(struct globals*)&bb_common_bufsiz1) 82#define top (G.top ) 83#define ntop (G.ntop ) 84#if ENABLE_FEATURE_USE_TERMIOS 85#define initial_settings (G. initial_settings ) 86#endif 87#define sort_function (G.sort_function ) 88#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 89#define prev_hist (G.prev_hist ) 90#define prev_hist_count (G.prev_hist_count ) 91#define jif (G.jif ) 92#define prev_jif (G.prev_jif ) 93#define total_pcpu (G.total_pcpu ) 94#endif 95 96#define OPT_BATCH_MODE (option_mask32 & 0x4) 97 98 99#if ENABLE_FEATURE_USE_TERMIOS 100static int pid_sort(top_status_t *P, top_status_t *Q) 101{ 102 /* Buggy wrt pids with high bit set */ 103 /* (linux pids are in [1..2^15-1]) */ 104 return (Q->pid - P->pid); 105} 106#endif 107 108static int mem_sort(top_status_t *P, top_status_t *Q) 109{ 110 /* We want to avoid unsigned->signed and truncation errors */ 111 if (Q->vsz < P->vsz) return -1; 112 return Q->vsz != P->vsz; /* 0 if ==, 1 if > */ 113} 114 115 116#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 117 118static int pcpu_sort(top_status_t *P, top_status_t *Q) 119{ 120 /* Buggy wrt ticks with high bit set */ 121 /* Affects only processes for which ticks overflow */ 122 return (int)Q->pcpu - (int)P->pcpu; 123} 124 125static int time_sort(top_status_t *P, top_status_t *Q) 126{ 127 /* We want to avoid unsigned->signed and truncation errors */ 128 if (Q->ticks < P->ticks) return -1; 129 return Q->ticks != P->ticks; /* 0 if ==, 1 if > */ 130} 131 132static int mult_lvl_cmp(void* a, void* b) 133{ 134 int i, cmp_val; 135 136 for (i = 0; i < SORT_DEPTH; i++) { 137 cmp_val = (*sort_function[i])(a, b); 138 if (cmp_val != 0) 139 return cmp_val; 140 } 141 return 0; 142} 143 144 145static void get_jiffy_counts(void) 146{ 147 FILE* fp = xfopen("stat", "r"); 148 prev_jif = jif; 149 if (fscanf(fp, "cpu %lld %lld %lld %lld %lld %lld %lld %lld", 150 &jif.usr,&jif.nic,&jif.sys,&jif.idle, 151 &jif.iowait,&jif.irq,&jif.softirq,&jif.steal) < 4) { 152 bb_error_msg_and_die("failed to read /proc/stat"); 153 } 154 fclose(fp); 155 jif.total = jif.usr + jif.nic + jif.sys + jif.idle 156 + jif.iowait + jif.irq + jif.softirq + jif.steal; 157 /* procps 2.x does not count iowait as busy time */ 158 jif.busy = jif.total - jif.idle - jif.iowait; 159} 160 161 162static void do_stats(void) 163{ 164 top_status_t *cur; 165 pid_t pid; 166 int i, last_i, n; 167 struct save_hist *new_hist; 168 169 get_jiffy_counts(); 170 total_pcpu = 0; 171 /* total_vsz = 0; */ 172 new_hist = xmalloc(sizeof(struct save_hist)*ntop); 173 /* 174 * Make a pass through the data to get stats. 175 */ 176 /* hist_iterations = 0; */ 177 i = 0; 178 for (n = 0; n < ntop; n++) { 179 cur = top + n; 180 181 /* 182 * Calculate time in cur process. Time is sum of user time 183 * and system time 184 */ 185 pid = cur->pid; 186 new_hist[n].ticks = cur->ticks; 187 new_hist[n].pid = pid; 188 189 /* find matching entry from previous pass */ 190 cur->pcpu = 0; 191 /* do not start at index 0, continue at last used one 192 * (brought hist_iterations from ~14000 down to 172) */ 193 last_i = i; 194 if (prev_hist_count) do { 195 if (prev_hist[i].pid == pid) { 196 cur->pcpu = cur->ticks - prev_hist[i].ticks; 197 total_pcpu += cur->pcpu; 198 break; 199 } 200 i = (i+1) % prev_hist_count; 201 /* hist_iterations++; */ 202 } while (i != last_i); 203 /* total_vsz += cur->vsz; */ 204 } 205 206 /* 207 * Save cur frame's information. 208 */ 209 free(prev_hist); 210 prev_hist = new_hist; 211 prev_hist_count = ntop; 212} 213#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ 214 215#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && ENABLE_FEATURE_TOP_DECIMALS 216/* formats 7 char string (8 with terminating NUL) */ 217static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total) 218{ 219 unsigned t; 220 if (value >= total) { /* 100% ? */ 221 strcpy(pbuf, " 100% "); 222 return pbuf; 223 } 224 /* else generate " [N/space]N.N% " string */ 225 value = 1000 * value / total; 226 t = value / 100; 227 value = value % 100; 228 pbuf[0] = ' '; 229 pbuf[1] = t ? t + '0' : ' '; 230 pbuf[2] = '0' + (value / 10); 231 pbuf[3] = '.'; 232 pbuf[4] = '0' + (value % 10); 233 pbuf[5] = '%'; 234 pbuf[6] = ' '; 235 pbuf[7] = '\0'; 236 return pbuf; 237} 238#endif 239 240/* display generic info (meminfo / loadavg) */ 241static unsigned long display_generic(int scr_width) 242{ 243 FILE *fp; 244 char buf[80]; 245 char scrbuf[80]; 246 unsigned long total, used, mfree, shared, buffers, cached; 247#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS 248 unsigned total_diff; 249#endif 250 251 /* read memory info */ 252 fp = xfopen("meminfo", "r"); 253 254 /* 255 * Old kernels (such as 2.4.x) had a nice summary of memory info that 256 * we could parse, however this is gone entirely in 2.6. Try parsing 257 * the old way first, and if that fails, parse each field manually. 258 * 259 * First, we read in the first line. Old kernels will have bogus 260 * strings we don't care about, whereas new kernels will start right 261 * out with MemTotal: 262 * -- PFM. 263 */ 264 if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) { 265 fgets(buf, sizeof(buf), fp); /* skip first line */ 266 267 fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu", 268 &total, &used, &mfree, &shared, &buffers, &cached); 269 /* convert to kilobytes */ 270 used /= 1024; 271 mfree /= 1024; 272 shared /= 1024; 273 buffers /= 1024; 274 cached /= 1024; 275 total /= 1024; 276 } else { 277 /* 278 * Revert to manual parsing, which incidentally already has the 279 * sizes in kilobytes. This should be safe for both 2.4 and 280 * 2.6. 281 */ 282 283 fscanf(fp, "MemFree: %lu %s\n", &mfree, buf); 284 285 /* 286 * MemShared: is no longer present in 2.6. Report this as 0, 287 * to maintain consistent behavior with normal procps. 288 */ 289 if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2) 290 shared = 0; 291 292 fscanf(fp, "Buffers: %lu %s\n", &buffers, buf); 293 fscanf(fp, "Cached: %lu %s\n", &cached, buf); 294 295 used = total - mfree; 296 } 297 fclose(fp); 298 299 /* output memory info */ 300 if (scr_width > sizeof(scrbuf)) 301 scr_width = sizeof(scrbuf); 302 snprintf(scrbuf, scr_width, 303 "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached", 304 used, mfree, shared, buffers, cached); 305 /* clear screen & go to top */ 306 printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf); 307 308#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS 309 /* using (unsigned) casts to make operations cheaper */ 310 total_diff = ((unsigned)(jif.total - prev_jif.total) ? : 1); 311#if ENABLE_FEATURE_TOP_DECIMALS 312/* Generated code is approx +0.3k */ 313#define CALC_STAT(xxx) char xxx[8] 314#define SHOW_STAT(xxx) fmt_100percent_8(xxx, (unsigned)(jif.xxx - prev_jif.xxx), total_diff) 315#define FMT "%s" 316#else 317#define CALC_STAT(xxx) unsigned xxx = 100 * (unsigned)(jif.xxx - prev_jif.xxx) / total_diff 318#define SHOW_STAT(xxx) xxx 319#define FMT "%4u%% " 320#endif 321 { /* need block: CALC_STAT are declarations */ 322 CALC_STAT(usr); 323 CALC_STAT(sys); 324 CALC_STAT(nic); 325 CALC_STAT(idle); 326 CALC_STAT(iowait); 327 CALC_STAT(irq); 328 CALC_STAT(softirq); 329 //CALC_STAT(steal); 330 331 snprintf(scrbuf, scr_width, 332 /* Barely fits in 79 chars when in "decimals" mode. */ 333 "CPU:"FMT"usr"FMT"sys"FMT"nice"FMT"idle"FMT"io"FMT"irq"FMT"softirq", 334 SHOW_STAT(usr), SHOW_STAT(sys), SHOW_STAT(nic), SHOW_STAT(idle), 335 SHOW_STAT(iowait), SHOW_STAT(irq), SHOW_STAT(softirq) 336 //, SHOW_STAT(steal) - what is this 'steal' thing? 337 // I doubt anyone wants to know it 338 ); 339 } 340 puts(scrbuf); 341#undef SHOW_STAT 342#undef CALC_STAT 343#undef FMT 344#endif 345 346 /* read load average as a string */ 347 buf[0] = '\0'; 348 open_read_close("loadavg", buf, sizeof("N.NN N.NN N.NN")-1); 349 buf[sizeof("N.NN N.NN N.NN")-1] = '\0'; 350 snprintf(scrbuf, scr_width, "Load average: %s", buf); 351 puts(scrbuf); 352 353 return total; 354} 355 356/* display process statuses */ 357static void display_status(int count, int scr_width) 358{ 359 enum { 360 BITS_PER_INT = sizeof(int)*8 361 }; 362 363 top_status_t *s = top; 364 char vsz_str_buf[8]; 365 unsigned long total_memory = display_generic(scr_width); /* or use total_vsz? */ 366 /* xxx_shift and xxx_scale variables allow us to replace 367 * expensive divides with multiply and shift */ 368 unsigned pmem_shift, pmem_scale, pmem_half; 369#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 370 unsigned pcpu_shift, pcpu_scale, pcpu_half; 371 unsigned busy_jifs; 372 373 /* what info of the processes is shown */ 374 printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, 375 " PID PPID USER STAT VSZ %MEM %CPU COMMAND"); 376#define MIN_WIDTH \ 377 sizeof( " PID PPID USER STAT VSZ %MEM %CPU C") 378#else 379 380 /* !CPU_USAGE_PERCENTAGE */ 381 printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, 382 " PID PPID USER STAT VSZ %MEM COMMAND"); 383#define MIN_WIDTH \ 384 sizeof( " PID PPID USER STAT VSZ %MEM C") 385#endif 386 387#if ENABLE_FEATURE_TOP_DECIMALS 388#define UPSCALE 1000 389#define CALC_STAT(name, val) div_t name = div((val), 10) 390#define SHOW_STAT(name) name.quot, '0'+name.rem 391#define FMT "%3u.%c" 392#else 393#define UPSCALE 100 394#define CALC_STAT(name, val) unsigned name = (val) 395#define SHOW_STAT(name) name 396#define FMT "%4u%%" 397#endif 398 /* 399 * MEM% = s->vsz/MemTotal 400 */ 401 pmem_shift = BITS_PER_INT-11; 402 pmem_scale = UPSCALE*(1U<<(BITS_PER_INT-11)) / total_memory; 403 /* s->vsz is in kb. we want (s->vsz * pmem_scale) to never overflow */ 404 while (pmem_scale >= 512) { 405 pmem_scale /= 4; 406 pmem_shift -= 2; 407 } 408 pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2); 409#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 410 busy_jifs = jif.busy - prev_jif.busy; 411 /* This happens if there were lots of short-lived processes 412 * between two top updates (e.g. compilation) */ 413 if (total_pcpu < busy_jifs) total_pcpu = busy_jifs; 414 415 /* 416 * CPU% = s->pcpu/sum(s->pcpu) * busy_cpu_ticks/total_cpu_ticks 417 * (pcpu is delta of sys+user time between samples) 418 */ 419 pcpu_shift = 6; 420 pcpu_scale = (UPSCALE*64*(uint16_t)busy_jifs ? : 1); 421 while (pcpu_scale < (1U<<(BITS_PER_INT-2))) { 422 pcpu_scale *= 4; 423 pcpu_shift += 2; 424 } 425 pcpu_scale /= ( (uint16_t)(jif.total-prev_jif.total)*total_pcpu ? : 1); 426 /* we want (s->pcpu * pcpu_scale) to never overflow */ 427 while (pcpu_scale >= 1024) { 428 pcpu_scale /= 4; 429 pcpu_shift -= 2; 430 } 431 pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2); 432 /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */ 433#endif 434 435 /* Ok, all prelim data is ready, go thru the list */ 436 while (count-- > 0) { 437 int col = scr_width; 438 CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); 439#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 440 CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift); 441#endif 442 443 if (s->vsz >= 100*1024) 444 sprintf(vsz_str_buf, "%6ldM", s->vsz/1024); 445 else 446 sprintf(vsz_str_buf, "%7ld", s->vsz); 447 // PID PPID USER STAT VSZ %MEM [%CPU] COMMAND 448 col -= printf("\n" "%5u%6u %-8.8s %s%s" FMT 449#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 450 FMT 451#endif 452 " ", 453 s->pid, s->ppid, get_cached_username(s->uid), 454 s->state, vsz_str_buf, 455 SHOW_STAT(pmem) 456#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 457 , SHOW_STAT(pcpu) 458#endif 459 ); 460 if (col > 0) { 461 char buf[col + 1]; 462 read_cmdline(buf, col, s->pid, s->comm); 463 fputs(buf, stdout); 464 } 465 /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, 466 jif.busy - prev_jif.busy, jif.total - prev_jif.total); */ 467 s++; 468 } 469 /* printf(" %d", hist_iterations); */ 470 putchar(OPT_BATCH_MODE ? '\n' : '\r'); 471 fflush(stdout); 472} 473#undef UPSCALE 474#undef SHOW_STAT 475#undef CALC_STAT 476#undef FMT 477 478 479static void clearmems(void) 480{ 481 clear_username_cache(); 482 free(top); 483 top = 0; 484 ntop = 0; 485} 486 487 488#if ENABLE_FEATURE_USE_TERMIOS 489#include <termios.h> 490#include <signal.h> 491 492static void reset_term(void) 493{ 494 tcsetattr(0, TCSANOW, (void *) &initial_settings); 495#if ENABLE_FEATURE_CLEAN_UP 496 clearmems(); 497#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 498 free(prev_hist); 499#endif 500#endif /* FEATURE_CLEAN_UP */ 501} 502 503static void sig_catcher(int sig ATTRIBUTE_UNUSED) 504{ 505 reset_term(); 506 exit(1); 507} 508#endif /* FEATURE_USE_TERMIOS */ 509 510 511int top_main(int argc, char **argv); 512int top_main(int argc, char **argv) 513{ 514 int count, lines, col; 515 unsigned interval = 5; /* default update rate is 5 seconds */ 516 unsigned iterations = UINT_MAX; /* 2^32 iterations by default :) */ 517 char *sinterval, *siterations; 518#if ENABLE_FEATURE_USE_TERMIOS 519 struct termios new_settings; 520 struct timeval tv; 521 fd_set readfds; 522 unsigned char c; 523#endif /* FEATURE_USE_TERMIOS */ 524 525 interval = 5; 526 527 /* do normal option parsing */ 528 opt_complementary = "-"; 529 getopt32(argv, "d:n:b", &sinterval, &siterations); 530 if (option_mask32 & 0x1) interval = xatou(sinterval); // -d 531 if (option_mask32 & 0x2) iterations = xatou(siterations); // -n 532 //if (option_mask32 & 0x4) // -b 533 534 /* change to /proc */ 535 xchdir("/proc"); 536#if ENABLE_FEATURE_USE_TERMIOS 537 tcgetattr(0, (void *) &initial_settings); 538 memcpy(&new_settings, &initial_settings, sizeof(struct termios)); 539 /* unbuffered input, turn off echo */ 540 new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); 541 542 signal(SIGTERM, sig_catcher); 543 signal(SIGINT, sig_catcher); 544 tcsetattr(0, TCSANOW, (void *) &new_settings); 545 atexit(reset_term); 546#endif /* FEATURE_USE_TERMIOS */ 547 548#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 549 sort_function[0] = pcpu_sort; 550 sort_function[1] = mem_sort; 551 sort_function[2] = time_sort; 552#else 553 sort_function = mem_sort; 554#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ 555 556 while (1) { 557 procps_status_t *p = NULL; 558 559 /* Default to 25 lines - 5 lines for status */ 560 lines = 24 - 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( - 1); 561 col = 79; 562#if ENABLE_FEATURE_USE_TERMIOS 563 get_terminal_width_height(0, &col, &lines); 564 if (lines < 5 || col < MIN_WIDTH) { 565 sleep(interval); 566 continue; 567 } 568 lines -= 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( + 1); 569#endif /* FEATURE_USE_TERMIOS */ 570 571 /* read process IDs & status for all the processes */ 572 while ((p = procps_scan(p, 0 573 | PSSCAN_PID 574 | PSSCAN_PPID 575 | PSSCAN_VSZ 576 | PSSCAN_STIME 577 | PSSCAN_UTIME 578 | PSSCAN_STATE 579 | PSSCAN_COMM 580 | PSSCAN_SID 581 | PSSCAN_UIDGID 582 ))) { 583 int n = ntop; 584 top = xrealloc(top, (++ntop) * sizeof(*top)); 585 top[n].pid = p->pid; 586 top[n].ppid = p->ppid; 587 top[n].vsz = p->vsz; 588#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 589 top[n].ticks = p->stime + p->utime; 590#endif 591 top[n].uid = p->uid; 592 strcpy(top[n].state, p->state); 593 strcpy(top[n].comm, p->comm); 594 } 595 if (ntop == 0) { 596 bb_error_msg_and_die("no process info in /proc"); 597 } 598#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 599 if (!prev_hist_count) { 600 do_stats(); 601 sleep(1); 602 clearmems(); 603 continue; 604 } 605 do_stats(); 606/* TODO: we don't need to sort all 10000 processes, we need to find top 24! */ 607 qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp); 608#else 609 qsort(top, ntop, sizeof(top_status_t), (void*)sort_function); 610#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ 611 count = lines; 612 if (OPT_BATCH_MODE || count > ntop) { 613 count = ntop; 614 } 615 /* show status for each of the processes */ 616 display_status(count, col); 617#if ENABLE_FEATURE_USE_TERMIOS 618 tv.tv_sec = interval; 619 tv.tv_usec = 0; 620 FD_ZERO(&readfds); 621 FD_SET(0, &readfds); 622 select(1, &readfds, NULL, NULL, &tv); 623 if (FD_ISSET(0, &readfds)) { 624 if (read(0, &c, 1) <= 0) { /* signal */ 625 return EXIT_FAILURE; 626 } 627 if (c == 'q' || c == initial_settings.c_cc[VINTR]) 628 break; 629 if (c == 'M') { 630#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 631 sort_function[0] = mem_sort; 632 sort_function[1] = pcpu_sort; 633 sort_function[2] = time_sort; 634#else 635 sort_function = mem_sort; 636#endif 637 } 638#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 639 if (c == 'P') { 640 sort_function[0] = pcpu_sort; 641 sort_function[1] = mem_sort; 642 sort_function[2] = time_sort; 643 } 644 if (c == 'T') { 645 sort_function[0] = time_sort; 646 sort_function[1] = mem_sort; 647 sort_function[2] = pcpu_sort; 648 } 649#endif 650 if (c == 'N') { 651#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 652 sort_function[0] = pid_sort; 653#else 654 sort_function = pid_sort; 655#endif 656 } 657 } 658 if (!--iterations) 659 break; 660#else 661 sleep(interval); 662#endif /* FEATURE_USE_TERMIOS */ 663 clearmems(); 664 } 665 if (ENABLE_FEATURE_CLEAN_UP) 666 clearmems(); 667 putchar('\n'); 668 return EXIT_SUCCESS; 669} 670