aboutsummaryrefslogtreecommitdiff
path: root/procps/top.c
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-11-05 00:43:51 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-11-05 00:43:51 +0000
commit48b1ebd12ec4ef182b4ea423f2309705ae141e8e (patch)
tree5deb7d2b82c280440761cceb4281738867d5631a /procps/top.c
parentd2c185589694b83e492144a6a5d0f79e16dd9b74 (diff)
downloadbusybox-w32-48b1ebd12ec4ef182b4ea423f2309705ae141e8e.tar.gz
busybox-w32-48b1ebd12ec4ef182b4ea423f2309705ae141e8e.tar.bz2
busybox-w32-48b1ebd12ec4ef182b4ea423f2309705ae141e8e.zip
replace /proc scanning code by more versatile one.
Use it where appropriate. Stop scanning /etc/passwd *for every process*!!! (uid->username) top: reduce memory usage - we won't save unneeded fields from /proc info anymore. Downside: ~+250 bytes of code git-svn-id: svn://busybox.net/trunk/busybox@16509 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'procps/top.c')
-rw-r--r--procps/top.c144
1 files changed, 93 insertions, 51 deletions
diff --git a/procps/top.c b/procps/top.c
index c76fdc312..8d732d4b2 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -30,37 +30,76 @@
30 30
31#include "busybox.h" 31#include "busybox.h"
32 32
33typedef int (*cmp_t)(procps_status_t *P, procps_status_t *Q);
34 33
35static procps_status_t *top; /* Hehe */ 34typedef struct {
35 unsigned long rss;
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;
45static top_status_t *top;
36static int ntop; 46static int ntop;
47/* This structure stores some critical information from one frame to
48 the next. Used for finding deltas. */
49struct save_hist {
50 unsigned long ticks;
51 unsigned pid;
52};
53static struct save_hist *prev_hist;
54static int prev_hist_count;
55/* static int hist_iterations; */
56static unsigned total_pcpu;
57/* static unsigned long total_rss; */
58
59
37#define OPT_BATCH_MODE (option_mask32 & 0x4) 60#define OPT_BATCH_MODE (option_mask32 & 0x4)
38 61
39#if ENABLE_FEATURE_USE_TERMIOS 62#if ENABLE_FEATURE_USE_TERMIOS
40static int pid_sort(procps_status_t *P, procps_status_t *Q) 63static int pid_sort(top_status_t *P, top_status_t *Q)
41{ 64{
65 /* Buggy wrt pids with high bit set */
66 /* (linux pids are in [1..2^15-1]) */
42 return (Q->pid - P->pid); 67 return (Q->pid - P->pid);
43} 68}
44#endif 69#endif
45 70
46static int mem_sort(procps_status_t *P, procps_status_t *Q) 71static int mem_sort(top_status_t *P, top_status_t *Q)
47{ 72{
48 return (int)(Q->rss - P->rss); 73 /* We want to avoid unsigned->signed and truncation errors */
74 if (Q->rss < P->rss) return -1;
75 return Q->rss != P->rss; /* 0 if ==, 1 if > */
49} 76}
50 77
51#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 78
79typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q);
80
81#if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
82
83static cmp_funcp sort_function;
84
85#else
52 86
53enum { SORT_DEPTH = 3 }; 87enum { SORT_DEPTH = 3 };
54static cmp_t sort_function[SORT_DEPTH];
55 88
56static int pcpu_sort(procps_status_t *P, procps_status_t *Q) 89static cmp_funcp sort_function[SORT_DEPTH];
90
91static int pcpu_sort(top_status_t *P, top_status_t *Q)
57{ 92{
58 return (Q->pcpu - P->pcpu); 93 /* Buggy wrt ticks with high bit set */
94 /* Affects only processes for which ticks overflow */
95 return (int)Q->pcpu - (int)P->pcpu;
59} 96}
60 97
61static int time_sort(procps_status_t *P, procps_status_t *Q) 98static int time_sort(top_status_t *P, top_status_t *Q)
62{ 99{
63 return (int)((Q->stime + Q->utime) - (P->stime + P->utime)); 100 /* We want to avoid unsigned->signed and truncation errors */
101 if (Q->ticks < P->ticks) return -1;
102 return Q->ticks != P->ticks; /* 0 if ==, 1 if > */
64} 103}
65 104
66static int mult_lvl_cmp(void* a, void* b) { 105static int mult_lvl_cmp(void* a, void* b) {
@@ -74,24 +113,6 @@ static int mult_lvl_cmp(void* a, void* b) {
74 return 0; 113 return 0;
75} 114}
76 115
77/* This structure stores some critical information from one frame to
78 the next. Mostly used for sorting. */
79struct save_hist {
80 int ticks;
81 pid_t pid;
82};
83
84/*
85 * Calculates percent cpu usage for each task.
86 */
87
88static struct save_hist *prev_hist;
89static int prev_hist_count;
90/* static int hist_iterations; */
91
92
93static unsigned total_pcpu;
94/* static unsigned long total_rss; */
95 116
96typedef struct { 117typedef struct {
97 unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal; 118 unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal;
@@ -115,11 +136,12 @@ static void get_jiffy_counts(void)
115 jif.busy = jif.total - jif.idle - jif.iowait; 136 jif.busy = jif.total - jif.idle - jif.iowait;
116} 137}
117 138
139
118static void do_stats(void) 140static void do_stats(void)
119{ 141{
120 procps_status_t *cur; 142 top_status_t *cur;
121 pid_t pid; 143 pid_t pid;
122 int total_time, i, last_i, n; 144 int i, last_i, n;
123 struct save_hist *new_hist; 145 struct save_hist *new_hist;
124 146
125 get_jiffy_counts(); 147 get_jiffy_counts();
@@ -139,8 +161,7 @@ static void do_stats(void)
139 * and system time 161 * and system time
140 */ 162 */
141 pid = cur->pid; 163 pid = cur->pid;
142 total_time = cur->stime + cur->utime; 164 new_hist[n].ticks = cur->ticks;
143 new_hist[n].ticks = total_time;
144 new_hist[n].pid = pid; 165 new_hist[n].pid = pid;
145 166
146 /* find matching entry from previous pass */ 167 /* find matching entry from previous pass */
@@ -150,13 +171,13 @@ static void do_stats(void)
150 last_i = i; 171 last_i = i;
151 if (prev_hist_count) do { 172 if (prev_hist_count) do {
152 if (prev_hist[i].pid == pid) { 173 if (prev_hist[i].pid == pid) {
153 cur->pcpu = total_time - prev_hist[i].ticks; 174 cur->pcpu = cur->ticks - prev_hist[i].ticks;
175 total_pcpu += cur->pcpu;
154 break; 176 break;
155 } 177 }
156 i = (i+1) % prev_hist_count; 178 i = (i+1) % prev_hist_count;
157 /* hist_iterations++; */ 179 /* hist_iterations++; */
158 } while (i != last_i); 180 } while (i != last_i);
159 total_pcpu += cur->pcpu;
160 /* total_rss += cur->rss; */ 181 /* total_rss += cur->rss; */
161 } 182 }
162 183
@@ -167,10 +188,9 @@ static void do_stats(void)
167 prev_hist = new_hist; 188 prev_hist = new_hist;
168 prev_hist_count = ntop; 189 prev_hist_count = ntop;
169} 190}
170#else
171static cmp_t sort_function;
172#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ 191#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
173 192
193
174/* display generic info (meminfo / loadavg) */ 194/* display generic info (meminfo / loadavg) */
175static unsigned long display_generic(int scr_width) 195static unsigned long display_generic(int scr_width)
176{ 196{
@@ -265,7 +285,7 @@ static void display_status(int count, int scr_width)
265 bits_per_int = sizeof(int)*8 285 bits_per_int = sizeof(int)*8
266 }; 286 };
267 287
268 procps_status_t *s = top; 288 top_status_t *s = top;
269 char rss_str_buf[8]; 289 char rss_str_buf[8];
270 unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */ 290 unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */
271 unsigned pmem_shift, pmem_scale; 291 unsigned pmem_shift, pmem_scale;
@@ -333,14 +353,19 @@ static void display_status(int count, int scr_width)
333 sprintf(rss_str_buf, "%6ldM", s->rss/1024); 353 sprintf(rss_str_buf, "%6ldM", s->rss/1024);
334 else 354 else
335 sprintf(rss_str_buf, "%7ld", s->rss); 355 sprintf(rss_str_buf, "%7ld", s->rss);
336 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10);) 356 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(
337 col -= printf("\n%5u %-8s %s %s%6u%3u.%c" \ 357 pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10);
338 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c") " ", 358 )
339 (unsigned)s->pid, s->user, s->state, rss_str_buf, (unsigned)s->ppid, 359 col -= printf("\n%5u %-8s %s "
360 "%s%6u"
361 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c")
362 "%3u.%c ",
363 s->pid, get_cached_username(s->uid), s->state,
364 rss_str_buf, s->ppid,
340 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,) 365 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,)
341 pmem.quot, '0'+pmem.rem); 366 pmem.quot, '0'+pmem.rem);
342 if (col > 0) 367 if (col > 0)
343 printf("%.*s", col, s->short_cmd); 368 printf("%.*s", col, s->comm);
344 /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, 369 /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
345 jif.busy - prev_jif.busy, jif.total - prev_jif.total); */ 370 jif.busy - prev_jif.busy, jif.total - prev_jif.total); */
346 s++; 371 s++;
@@ -350,18 +375,20 @@ static void display_status(int count, int scr_width)
350 fflush(stdout); 375 fflush(stdout);
351} 376}
352 377
378
353static void clearmems(void) 379static void clearmems(void)
354{ 380{
381 clear_username_cache();
355 free(top); 382 free(top);
356 top = 0; 383 top = 0;
357 ntop = 0; 384 ntop = 0;
358} 385}
359 386
387
360#if ENABLE_FEATURE_USE_TERMIOS 388#if ENABLE_FEATURE_USE_TERMIOS
361#include <termios.h> 389#include <termios.h>
362#include <signal.h> 390#include <signal.h>
363 391
364
365static struct termios initial_settings; 392static struct termios initial_settings;
366 393
367static void reset_term(void) 394static void reset_term(void)
@@ -427,7 +454,7 @@ int top_main(int argc, char **argv)
427#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ 454#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
428 455
429 while (1) { 456 while (1) {
430 procps_status_t *p; 457 procps_status_t *p = NULL;
431 458
432 /* Default to 25 lines - 5 lines for status */ 459 /* Default to 25 lines - 5 lines for status */
433 lines = 24 - 3; 460 lines = 24 - 3;
@@ -442,11 +469,26 @@ int top_main(int argc, char **argv)
442#endif /* FEATURE_USE_TERMIOS */ 469#endif /* FEATURE_USE_TERMIOS */
443 470
444 /* read process IDs & status for all the processes */ 471 /* read process IDs & status for all the processes */
445 while ((p = procps_scan(0)) != 0) { 472 while ((p = procps_scan(p, 0
473 | PSSCAN_PID
474 | PSSCAN_PPID
475 | PSSCAN_RSS
476 | PSSCAN_STIME
477 | PSSCAN_UTIME
478 | PSSCAN_STATE
479 | PSSCAN_COMM
480 | PSSCAN_SID
481 | PSSCAN_UIDGID
482 ))) {
446 int n = ntop; 483 int n = ntop;
447 484 top = xrealloc(top, (++ntop)*sizeof(top_status_t));
448 top = xrealloc(top, (++ntop)*sizeof(procps_status_t)); 485 top[n].pid = p->pid;
449 memcpy(top + n, p, sizeof(procps_status_t)); 486 top[n].ppid = p->ppid;
487 top[n].rss = p->rss;
488 top[n].ticks = p->stime + p->utime;
489 top[n].uid = p->uid;
490 strcpy(top[n].state, p->state);
491 strcpy(top[n].comm, p->comm);
450 } 492 }
451 if (ntop == 0) { 493 if (ntop == 0) {
452 bb_error_msg_and_die("can't find process info in /proc"); 494 bb_error_msg_and_die("can't find process info in /proc");
@@ -459,9 +501,9 @@ int top_main(int argc, char **argv)
459 continue; 501 continue;
460 } 502 }
461 do_stats(); 503 do_stats();
462 qsort(top, ntop, sizeof(procps_status_t), (void*)mult_lvl_cmp); 504 qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
463#else 505#else
464 qsort(top, ntop, sizeof(procps_status_t), (void*)sort_function); 506 qsort(top, ntop, sizeof(top_status_t), (void*)sort_function);
465#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ 507#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
466 count = lines; 508 count = lines;
467 if (OPT_BATCH_MODE || count > ntop) { 509 if (OPT_BATCH_MODE || count > ntop) {