blob: 8d732d4b28dc29c42ef1eaf337bb87a95ccfb29b [file] [log] [blame]
Bernhard Reutner-Fischerd9cf7ac2006-04-12 18:39:58 +00001/* vi: set sw=4 ts=4: */
Eric Andersen420b2082002-09-17 22:14:58 +00002/*
3 * A tiny 'top' utility.
4 *
Eric Andersen08a72202002-09-30 20:52:10 +00005 * 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.
Eric Andersenc7bda1c2004-03-15 08:29:22 +000011 *
Eric Andersen420b2082002-09-17 22:14:58 +000012 * NOTES:
13 * - At startup this changes to /proc, all the reads are then
14 * relative to that.
Eric Andersenc7bda1c2004-03-15 08:29:22 +000015 *
Eric Andersen420b2082002-09-17 22:14:58 +000016 * (C) Eero Tamminen <oak at welho dot com>
Eric Andersen08a72202002-09-30 20:52:10 +000017 *
Eric Andersenaff114c2004-04-14 17:51:38 +000018 * Rewritten by Vladimir Oleynik (C) 2002 <dzo@simtreas.ru>
Eric Andersen420b2082002-09-17 22:14:58 +000019 */
Eric Andersen08a72202002-09-30 20:52:10 +000020
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
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000031#include "busybox.h"
Eric Andersen420b2082002-09-17 22:14:58 +000032
Eric Andersen08a72202002-09-30 20:52:10 +000033
Denis Vlasenko459e4d62006-11-05 00:43:51 +000034typedef 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;
Eric Andersen08a72202002-09-30 20:52:10 +000046static int ntop;
Denis Vlasenko459e4d62006-11-05 00:43:51 +000047/* 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
Denis Vlasenkoc12f5302006-10-06 09:49:47 +000060#define OPT_BATCH_MODE (option_mask32 & 0x4)
Eric Andersen08a72202002-09-30 20:52:10 +000061
Denis Vlasenkofa076802006-11-05 00:38:51 +000062#if ENABLE_FEATURE_USE_TERMIOS
Denis Vlasenko459e4d62006-11-05 00:43:51 +000063static int pid_sort(top_status_t *P, top_status_t *Q)
Eric Andersen08a72202002-09-30 20:52:10 +000064{
Denis Vlasenko459e4d62006-11-05 00:43:51 +000065 /* Buggy wrt pids with high bit set */
66 /* (linux pids are in [1..2^15-1]) */
Rob Landleyb2804552006-02-13 22:04:27 +000067 return (Q->pid - P->pid);
Eric Andersen08a72202002-09-30 20:52:10 +000068}
Mike Frysinger223b8872005-07-30 09:42:05 +000069#endif
Eric Andersen08a72202002-09-30 20:52:10 +000070
Denis Vlasenko459e4d62006-11-05 00:43:51 +000071static int mem_sort(top_status_t *P, top_status_t *Q)
Eric Andersen08a72202002-09-30 20:52:10 +000072{
Denis Vlasenko459e4d62006-11-05 00:43:51 +000073 /* 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 > */
Eric Andersen08a72202002-09-30 20:52:10 +000076}
77
Denis Vlasenko459e4d62006-11-05 00:43:51 +000078
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
Eric Andersen08a72202002-09-30 20:52:10 +000086
Denis Vlasenkofa076802006-11-05 00:38:51 +000087enum { SORT_DEPTH = 3 };
Eric Andersen08a72202002-09-30 20:52:10 +000088
Denis Vlasenko459e4d62006-11-05 00:43:51 +000089static cmp_funcp sort_function[SORT_DEPTH];
90
91static int pcpu_sort(top_status_t *P, top_status_t *Q)
Eric Andersen08a72202002-09-30 20:52:10 +000092{
Denis Vlasenko459e4d62006-11-05 00:43:51 +000093 /* Buggy wrt ticks with high bit set */
94 /* Affects only processes for which ticks overflow */
95 return (int)Q->pcpu - (int)P->pcpu;
Eric Andersen08a72202002-09-30 20:52:10 +000096}
97
Denis Vlasenko459e4d62006-11-05 00:43:51 +000098static int time_sort(top_status_t *P, top_status_t *Q)
Eric Andersen08a72202002-09-30 20:52:10 +000099{
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000100 /* 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 > */
Eric Andersen08a72202002-09-30 20:52:10 +0000103}
104
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000105static int mult_lvl_cmp(void* a, void* b) {
Rob Landleyb2804552006-02-13 22:04:27 +0000106 int i, cmp_val;
Eric Andersen08a72202002-09-30 20:52:10 +0000107
Denis Vlasenkofa076802006-11-05 00:38:51 +0000108 for (i = 0; i < SORT_DEPTH; i++) {
Rob Landleyb2804552006-02-13 22:04:27 +0000109 cmp_val = (*sort_function[i])(a, b);
110 if (cmp_val != 0)
111 return cmp_val;
112 }
113 return 0;
Eric Andersen08a72202002-09-30 20:52:10 +0000114}
115
Eric Andersen08a72202002-09-30 20:52:10 +0000116
Denis Vlasenkofa076802006-11-05 00:38:51 +0000117typedef struct {
Rob Landley997650b2006-04-24 23:13:46 +0000118 unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal;
119 unsigned long long total;
120 unsigned long long busy;
Denis Vlasenkofa076802006-11-05 00:38:51 +0000121} jiffy_counts_t;
122static jiffy_counts_t jif, prev_jif;
Rob Landley997650b2006-04-24 23:13:46 +0000123static void get_jiffy_counts(void)
Rob Landleyb2804552006-02-13 22:04:27 +0000124{
Rob Landleyd921b2e2006-08-03 15:41:12 +0000125 FILE* fp = xfopen("stat", "r");
Rob Landley997650b2006-04-24 23:13:46 +0000126 prev_jif = jif;
127 if (fscanf(fp, "cpu %lld %lld %lld %lld %lld %lld %lld %lld",
128 &jif.usr,&jif.nic,&jif.sys,&jif.idle,
129 &jif.iowait,&jif.irq,&jif.softirq,&jif.steal) < 4) {
Denis Vlasenko42dfcd22006-09-09 12:55:02 +0000130 bb_error_msg_and_die("failed to read /proc/stat");
Rob Landleyb2804552006-02-13 22:04:27 +0000131 }
Rob Landley997650b2006-04-24 23:13:46 +0000132 fclose(fp);
133 jif.total = jif.usr + jif.nic + jif.sys + jif.idle
134 + jif.iowait + jif.irq + jif.softirq + jif.steal;
135 /* procps 2.x does not count iowait as busy time */
136 jif.busy = jif.total - jif.idle - jif.iowait;
Eric Andersen08a72202002-09-30 20:52:10 +0000137}
138
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000139
Eric Andersen08a72202002-09-30 20:52:10 +0000140static void do_stats(void)
141{
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000142 top_status_t *cur;
Denis Vlasenko35fb5122006-11-01 09:16:49 +0000143 pid_t pid;
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000144 int i, last_i, n;
Rob Landley997650b2006-04-24 23:13:46 +0000145 struct save_hist *new_hist;
Eric Andersen08a72202002-09-30 20:52:10 +0000146
Rob Landley997650b2006-04-24 23:13:46 +0000147 get_jiffy_counts();
148 total_pcpu = 0;
149 /* total_rss = 0; */
150 new_hist = xmalloc(sizeof(struct save_hist)*ntop);
Rob Landleyb2804552006-02-13 22:04:27 +0000151 /*
152 * Make a pass through the data to get stats.
153 */
Rob Landley997650b2006-04-24 23:13:46 +0000154 /* hist_iterations = 0; */
155 i = 0;
156 for (n = 0; n < ntop; n++) {
Rob Landleyb2804552006-02-13 22:04:27 +0000157 cur = top + n;
158
159 /*
160 * Calculate time in cur process. Time is sum of user time
Rob Landley997650b2006-04-24 23:13:46 +0000161 * and system time
Rob Landleyb2804552006-02-13 22:04:27 +0000162 */
Rob Landleyb2804552006-02-13 22:04:27 +0000163 pid = cur->pid;
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000164 new_hist[n].ticks = cur->ticks;
Rob Landley997650b2006-04-24 23:13:46 +0000165 new_hist[n].pid = pid;
Rob Landleyb2804552006-02-13 22:04:27 +0000166
167 /* find matching entry from previous pass */
Rob Landley997650b2006-04-24 23:13:46 +0000168 cur->pcpu = 0;
169 /* do not start at index 0, continue at last used one
170 * (brought hist_iterations from ~14000 down to 172) */
171 last_i = i;
172 if (prev_hist_count) do {
173 if (prev_hist[i].pid == pid) {
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000174 cur->pcpu = cur->ticks - prev_hist[i].ticks;
175 total_pcpu += cur->pcpu;
Rob Landleyb2804552006-02-13 22:04:27 +0000176 break;
177 }
Rob Landley997650b2006-04-24 23:13:46 +0000178 i = (i+1) % prev_hist_count;
179 /* hist_iterations++; */
180 } while (i != last_i);
Rob Landley997650b2006-04-24 23:13:46 +0000181 /* total_rss += cur->rss; */
Eric Andersen08a72202002-09-30 20:52:10 +0000182 }
183
184 /*
Rob Landleyb2804552006-02-13 22:04:27 +0000185 * Save cur frame's information.
Eric Andersen08a72202002-09-30 20:52:10 +0000186 */
Rob Landley997650b2006-04-24 23:13:46 +0000187 free(prev_hist);
188 prev_hist = new_hist;
189 prev_hist_count = ntop;
Eric Andersen08a72202002-09-30 20:52:10 +0000190}
Denis Vlasenkofa076802006-11-05 00:38:51 +0000191#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
Eric Andersen08a72202002-09-30 20:52:10 +0000192
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000193
Eric Andersen420b2082002-09-17 22:14:58 +0000194/* display generic info (meminfo / loadavg) */
Rob Landley997650b2006-04-24 23:13:46 +0000195static unsigned long display_generic(int scr_width)
Eric Andersen420b2082002-09-17 22:14:58 +0000196{
197 FILE *fp;
198 char buf[80];
Rob Landley997650b2006-04-24 23:13:46 +0000199 char scrbuf[80];
200 char *end;
Eric Andersen420b2082002-09-17 22:14:58 +0000201 unsigned long total, used, mfree, shared, buffers, cached;
Eric Andersen7857c032003-10-11 18:47:20 +0000202 unsigned int needs_conversion = 1;
Eric Andersen420b2082002-09-17 22:14:58 +0000203
204 /* read memory info */
Rob Landleyd921b2e2006-08-03 15:41:12 +0000205 fp = xfopen("meminfo", "r");
Eric Andersen420b2082002-09-17 22:14:58 +0000206
Eric Andersen7857c032003-10-11 18:47:20 +0000207 /*
208 * Old kernels (such as 2.4.x) had a nice summary of memory info that
209 * we could parse, however this is gone entirely in 2.6. Try parsing
210 * the old way first, and if that fails, parse each field manually.
211 *
212 * First, we read in the first line. Old kernels will have bogus
213 * strings we don't care about, whereas new kernels will start right
214 * out with MemTotal:
"Vladimir N. Oleynik"70678bc2005-11-29 12:32:33 +0000215 * -- PFM.
Eric Andersen7857c032003-10-11 18:47:20 +0000216 */
217 if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) {
"Vladimir N. Oleynik"70678bc2005-11-29 12:32:33 +0000218 fgets(buf, sizeof(buf), fp); /* skip first line */
Eric Andersen7857c032003-10-11 18:47:20 +0000219
220 fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
221 &total, &used, &mfree, &shared, &buffers, &cached);
222 } else {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000223 /*
Eric Andersen7857c032003-10-11 18:47:20 +0000224 * Revert to manual parsing, which incidentally already has the
225 * sizes in kilobytes. This should be safe for both 2.4 and
226 * 2.6.
227 */
228 needs_conversion = 0;
229
230 fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
231
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000232 /*
Eric Andersen7857c032003-10-11 18:47:20 +0000233 * MemShared: is no longer present in 2.6. Report this as 0,
234 * to maintain consistent behavior with normal procps.
235 */
236 if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
237 shared = 0;
238
239 fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
240 fscanf(fp, "Cached: %lu %s\n", &cached, buf);
241
242 used = total - mfree;
Eric Andersen420b2082002-09-17 22:14:58 +0000243 }
244 fclose(fp);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000245
Rob Landley997650b2006-04-24 23:13:46 +0000246 /* read load average as a string */
Rob Landley997650b2006-04-24 23:13:46 +0000247 buf[0] = '\0';
Denis Vlasenko25d80622006-10-27 09:34:22 +0000248 open_read_close("loadavg", buf, sizeof(buf));
Rob Landley997650b2006-04-24 23:13:46 +0000249 end = strchr(buf, ' ');
250 if (end) end = strchr(end+1, ' ');
251 if (end) end = strchr(end+1, ' ');
252 if (end) *end = '\0';
Eric Andersen420b2082002-09-17 22:14:58 +0000253
Eric Andersen7857c032003-10-11 18:47:20 +0000254 if (needs_conversion) {
255 /* convert to kilobytes */
256 used /= 1024;
257 mfree /= 1024;
258 shared /= 1024;
259 buffers /= 1024;
260 cached /= 1024;
261 total /= 1024;
262 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000263
Eric Andersen420b2082002-09-17 22:14:58 +0000264 /* output memory info and load average */
Eric Andersen08a72202002-09-30 20:52:10 +0000265 /* clear screen & go to top */
Rob Landley997650b2006-04-24 23:13:46 +0000266 if (scr_width > sizeof(scrbuf))
267 scr_width = sizeof(scrbuf);
268 snprintf(scrbuf, scr_width,
269 "Mem: %ldK used, %ldK free, %ldK shrd, %ldK buff, %ldK cached",
Rob Landleyb2804552006-02-13 22:04:27 +0000270 used, mfree, shared, buffers, cached);
Denis Vlasenko266bc172006-09-29 17:16:39 +0000271
272 printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf);
273
Denis Vlasenko25d80622006-10-27 09:34:22 +0000274 snprintf(scrbuf, scr_width, "Load average: %s", buf);
Rob Landley997650b2006-04-24 23:13:46 +0000275 printf("%s\n", scrbuf);
276
Eric Andersen7857c032003-10-11 18:47:20 +0000277 return total;
Eric Andersen420b2082002-09-17 22:14:58 +0000278}
279
280
281/* display process statuses */
Rob Landley997650b2006-04-24 23:13:46 +0000282static void display_status(int count, int scr_width)
Eric Andersen420b2082002-09-17 22:14:58 +0000283{
Rob Landley997650b2006-04-24 23:13:46 +0000284 enum {
285 bits_per_int = sizeof(int)*8
286 };
287
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000288 top_status_t *s = top;
Eric Andersen08a72202002-09-30 20:52:10 +0000289 char rss_str_buf[8];
Rob Landley997650b2006-04-24 23:13:46 +0000290 unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */
291 unsigned pmem_shift, pmem_scale;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000292
Denis Vlasenkofa076802006-11-05 00:38:51 +0000293#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
Rob Landley997650b2006-04-24 23:13:46 +0000294 unsigned pcpu_shift, pcpu_scale;
Denis Vlasenkofa076802006-11-05 00:38:51 +0000295 unsigned busy_jifs;
Rob Landley997650b2006-04-24 23:13:46 +0000296
Eric Andersen420b2082002-09-17 22:14:58 +0000297 /* what info of the processes is shown */
Denis Vlasenko266bc172006-09-29 17:16:39 +0000298 printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
Rob Landley997650b2006-04-24 23:13:46 +0000299 " PID USER STATUS RSS PPID %CPU %MEM COMMAND");
300#define MIN_WIDTH \
301 sizeof( " PID USER STATUS RSS PPID %CPU %MEM C")
Eric Andersen08a72202002-09-30 20:52:10 +0000302#else
Denis Vlasenko266bc172006-09-29 17:16:39 +0000303 printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
Rob Landley997650b2006-04-24 23:13:46 +0000304 " PID USER STATUS RSS PPID %MEM COMMAND");
305#define MIN_WIDTH \
306 sizeof( " PID USER STATUS RSS PPID %MEM C")
307#endif
308
309 /*
310 * MEM% = s->rss/MemTotal
311 */
312 pmem_shift = bits_per_int-11;
313 pmem_scale = 1000*(1U<<(bits_per_int-11)) / total_memory;
314 /* s->rss is in kb. we want (s->rss * pmem_scale) to never overflow */
315 while (pmem_scale >= 512) {
316 pmem_scale /= 4;
317 pmem_shift -= 2;
318 }
Denis Vlasenkofa076802006-11-05 00:38:51 +0000319#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
320 busy_jifs = jif.busy - prev_jif.busy;
321 /* This happens if there were lots of short-lived processes
322 * between two top updates (e.g. compilation) */
323 if (total_pcpu < busy_jifs) total_pcpu = busy_jifs;
324
Rob Landley997650b2006-04-24 23:13:46 +0000325 /*
326 * CPU% = s->pcpu/sum(s->pcpu) * busy_cpu_ticks/total_cpu_ticks
327 * (pcpu is delta of sys+user time between samples)
328 */
329 /* (jif.xxx - prev_jif.xxx) and s->pcpu are
330 * in 0..~64000 range (HZ*update_interval).
331 * we assume that unsigned is at least 32-bit.
332 */
333 pcpu_shift = 6;
Denis Vlasenkofa076802006-11-05 00:38:51 +0000334 pcpu_scale = (1000*64*(uint16_t)busy_jifs ? : 1);
Rob Landley997650b2006-04-24 23:13:46 +0000335 while (pcpu_scale < (1U<<(bits_per_int-2))) {
336 pcpu_scale *= 4;
337 pcpu_shift += 2;
338 }
339 pcpu_scale /= ( (uint16_t)(jif.total-prev_jif.total)*total_pcpu ? : 1);
340 /* we want (s->pcpu * pcpu_scale) to never overflow */
341 while (pcpu_scale >= 1024) {
342 pcpu_scale /= 4;
343 pcpu_shift -= 2;
344 }
345 /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */
Eric Andersen08a72202002-09-30 20:52:10 +0000346#endif
Denis Vlasenko266bc172006-09-29 17:16:39 +0000347 while (count-- > 0) {
348 div_t pmem = div((s->rss*pmem_scale) >> pmem_shift, 10);
Rob Landley997650b2006-04-24 23:13:46 +0000349 int col = scr_width+1;
Bernhard Reutner-Fischere2922e42006-05-19 12:48:56 +0000350 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(div_t pcpu;)
Eric Andersen420b2082002-09-17 22:14:58 +0000351
Rob Landley997650b2006-04-24 23:13:46 +0000352 if (s->rss >= 100*1024)
Eric Andersen08a72202002-09-30 20:52:10 +0000353 sprintf(rss_str_buf, "%6ldM", s->rss/1024);
Manuel Novoa III d4993302002-09-18 19:27:10 +0000354 else
Eric Andersen08a72202002-09-30 20:52:10 +0000355 sprintf(rss_str_buf, "%7ld", s->rss);
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000356 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(
357 pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10);
358 )
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,
Rob Landley0c430462006-05-04 19:51:22 +0000365 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,)
366 pmem.quot, '0'+pmem.rem);
Denis Vlasenko25d80622006-10-27 09:34:22 +0000367 if (col > 0)
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000368 printf("%.*s", col, s->comm);
Bernhard Reutner-Fischere2922e42006-05-19 12:48:56 +0000369 /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
Rob Landley997650b2006-04-24 23:13:46 +0000370 jif.busy - prev_jif.busy, jif.total - prev_jif.total); */
Eric Andersen420b2082002-09-17 22:14:58 +0000371 s++;
Eric Andersen08a72202002-09-30 20:52:10 +0000372 }
Rob Landley997650b2006-04-24 23:13:46 +0000373 /* printf(" %d", hist_iterations); */
Denis Vlasenko266bc172006-09-29 17:16:39 +0000374 putchar(OPT_BATCH_MODE ? '\n' : '\r');
Rob Landley997650b2006-04-24 23:13:46 +0000375 fflush(stdout);
Eric Andersen44608e92002-10-22 12:21:15 +0000376}
377
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000378
Eric Andersen44608e92002-10-22 12:21:15 +0000379static void clearmems(void)
380{
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000381 clear_username_cache();
Eric Andersen08a72202002-09-30 20:52:10 +0000382 free(top);
Eric Andersen08a72202002-09-30 20:52:10 +0000383 top = 0;
Eric Andersen08a72202002-09-30 20:52:10 +0000384 ntop = 0;
385}
386
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000387
Denis Vlasenkofa076802006-11-05 00:38:51 +0000388#if ENABLE_FEATURE_USE_TERMIOS
Eric Andersen08a72202002-09-30 20:52:10 +0000389#include <termios.h>
Eric Andersen08a72202002-09-30 20:52:10 +0000390#include <signal.h>
391
Eric Andersen08a72202002-09-30 20:52:10 +0000392static struct termios initial_settings;
393
394static void reset_term(void)
395{
396 tcsetattr(0, TCSANOW, (void *) &initial_settings);
Denis Vlasenkofa076802006-11-05 00:38:51 +0000397#if ENABLE_FEATURE_CLEAN_UP
Eric Andersen08a72202002-09-30 20:52:10 +0000398 clearmems();
Denis Vlasenkofa076802006-11-05 00:38:51 +0000399#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
Rob Landley997650b2006-04-24 23:13:46 +0000400 free(prev_hist);
Eric Andersen08a72202002-09-30 20:52:10 +0000401#endif
Denis Vlasenkofa076802006-11-05 00:38:51 +0000402#endif /* FEATURE_CLEAN_UP */
Eric Andersen08a72202002-09-30 20:52:10 +0000403}
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000404
Rob Landleyb2804552006-02-13 22:04:27 +0000405static void sig_catcher(int sig ATTRIBUTE_UNUSED)
Eric Andersen08a72202002-09-30 20:52:10 +0000406{
407 reset_term();
Rob Landleydb1ab1a2006-06-28 14:11:25 +0000408 exit(1);
Eric Andersen08a72202002-09-30 20:52:10 +0000409}
Denis Vlasenkofa076802006-11-05 00:38:51 +0000410#endif /* FEATURE_USE_TERMIOS */
Eric Andersen08a72202002-09-30 20:52:10 +0000411
412
Eric Andersen420b2082002-09-17 22:14:58 +0000413int top_main(int argc, char **argv)
414{
Denis Vlasenko266bc172006-09-29 17:16:39 +0000415 int count, lines, col;
Denis Vlasenko13858992006-10-08 12:49:22 +0000416 unsigned interval = 5; /* default update rate is 5 seconds */
417 unsigned iterations = UINT_MAX; /* 2^32 iterations by default :) */
Denis Vlasenko266bc172006-09-29 17:16:39 +0000418 char *sinterval, *siterations;
Denis Vlasenkofa076802006-11-05 00:38:51 +0000419#if ENABLE_FEATURE_USE_TERMIOS
Eric Andersen08a72202002-09-30 20:52:10 +0000420 struct termios new_settings;
421 struct timeval tv;
422 fd_set readfds;
423 unsigned char c;
Denis Vlasenkofa076802006-11-05 00:38:51 +0000424#endif /* FEATURE_USE_TERMIOS */
Eric Andersen08a72202002-09-30 20:52:10 +0000425
Eric Andersen420b2082002-09-17 22:14:58 +0000426 /* do normal option parsing */
Denis Vlasenko42dfcd22006-09-09 12:55:02 +0000427 interval = 5;
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000428 opt_complementary = "-";
Denis Vlasenkofa076802006-11-05 00:38:51 +0000429 getopt32(argc, argv, "d:n:b", &sinterval, &siterations);
Denis Vlasenko13858992006-10-08 12:49:22 +0000430 if (option_mask32 & 0x1) interval = xatou(sinterval); // -d
431 if (option_mask32 & 0x2) iterations = xatou(siterations); // -n
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000432 //if (option_mask32 & 0x4) // -b
Eric Andersen420b2082002-09-17 22:14:58 +0000433
Eric Andersen44608e92002-10-22 12:21:15 +0000434 /* change to /proc */
Rob Landleyd921b2e2006-08-03 15:41:12 +0000435 xchdir("/proc");
Denis Vlasenkofa076802006-11-05 00:38:51 +0000436#if ENABLE_FEATURE_USE_TERMIOS
Eric Andersen08a72202002-09-30 20:52:10 +0000437 tcgetattr(0, (void *) &initial_settings);
438 memcpy(&new_settings, &initial_settings, sizeof(struct termios));
Denis Vlasenko42dfcd22006-09-09 12:55:02 +0000439 /* unbuffered input, turn off echo */
440 new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL);
Eric Andersen08a72202002-09-30 20:52:10 +0000441
Rob Landley997650b2006-04-24 23:13:46 +0000442 signal(SIGTERM, sig_catcher);
Rob Landleydb1ab1a2006-06-28 14:11:25 +0000443 signal(SIGINT, sig_catcher);
Eric Andersen08a72202002-09-30 20:52:10 +0000444 tcsetattr(0, TCSANOW, (void *) &new_settings);
445 atexit(reset_term);
Denis Vlasenkofa076802006-11-05 00:38:51 +0000446#endif /* FEATURE_USE_TERMIOS */
Mike Frysinger223b8872005-07-30 09:42:05 +0000447
Denis Vlasenkofa076802006-11-05 00:38:51 +0000448#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
Eric Andersen08a72202002-09-30 20:52:10 +0000449 sort_function[0] = pcpu_sort;
450 sort_function[1] = mem_sort;
451 sort_function[2] = time_sort;
452#else
453 sort_function = mem_sort;
Denis Vlasenkofa076802006-11-05 00:38:51 +0000454#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
Mike Frysinger223b8872005-07-30 09:42:05 +0000455
Eric Andersen08a72202002-09-30 20:52:10 +0000456 while (1) {
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000457 procps_status_t *p = NULL;
Eric Andersen44608e92002-10-22 12:21:15 +0000458
Rob Landley997650b2006-04-24 23:13:46 +0000459 /* Default to 25 lines - 5 lines for status */
460 lines = 24 - 3;
461 col = 79;
Denis Vlasenkofa076802006-11-05 00:38:51 +0000462#if ENABLE_FEATURE_USE_TERMIOS
Rob Landley997650b2006-04-24 23:13:46 +0000463 get_terminal_width_height(0, &col, &lines);
464 if (lines < 5 || col < MIN_WIDTH) {
465 sleep(interval);
466 continue;
467 }
468 lines -= 3;
Denis Vlasenkofa076802006-11-05 00:38:51 +0000469#endif /* FEATURE_USE_TERMIOS */
Rob Landley997650b2006-04-24 23:13:46 +0000470
471 /* read process IDs & status for all the processes */
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000472 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 ))) {
Eric Andersen44608e92002-10-22 12:21:15 +0000483 int n = ntop;
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000484 top = xrealloc(top, (++ntop)*sizeof(top_status_t));
485 top[n].pid = p->pid;
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);
Eric Andersen44608e92002-10-22 12:21:15 +0000492 }
493 if (ntop == 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +0000494 bb_error_msg_and_die("can't find process info in /proc");
Rob Landleyb2804552006-02-13 22:04:27 +0000495 }
Denis Vlasenkofa076802006-11-05 00:38:51 +0000496#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
Rob Landley997650b2006-04-24 23:13:46 +0000497 if (!prev_hist_count) {
Eric Andersen08a72202002-09-30 20:52:10 +0000498 do_stats();
499 sleep(1);
500 clearmems();
501 continue;
Rob Landleyb2804552006-02-13 22:04:27 +0000502 }
Eric Andersen08a72202002-09-30 20:52:10 +0000503 do_stats();
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000504 qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
Eric Andersen08a72202002-09-30 20:52:10 +0000505#else
Denis Vlasenko459e4d62006-11-05 00:43:51 +0000506 qsort(top, ntop, sizeof(top_status_t), (void*)sort_function);
Denis Vlasenkofa076802006-11-05 00:38:51 +0000507#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
Denis Vlasenko266bc172006-09-29 17:16:39 +0000508 count = lines;
Denis Vlasenko25d80622006-10-27 09:34:22 +0000509 if (OPT_BATCH_MODE || count > ntop) {
Denis Vlasenko266bc172006-09-29 17:16:39 +0000510 count = ntop;
Eric Andersen08a72202002-09-30 20:52:10 +0000511 }
512 /* show status for each of the processes */
Denis Vlasenko266bc172006-09-29 17:16:39 +0000513 display_status(count, col);
Denis Vlasenkofa076802006-11-05 00:38:51 +0000514#if ENABLE_FEATURE_USE_TERMIOS
Eric Andersen08a72202002-09-30 20:52:10 +0000515 tv.tv_sec = interval;
516 tv.tv_usec = 0;
Rob Landley997650b2006-04-24 23:13:46 +0000517 FD_ZERO(&readfds);
518 FD_SET(0, &readfds);
519 select(1, &readfds, NULL, NULL, &tv);
520 if (FD_ISSET(0, &readfds)) {
521 if (read(0, &c, 1) <= 0) { /* signal */
Mike Frysinger223b8872005-07-30 09:42:05 +0000522 return EXIT_FAILURE;
523 }
Rob Landley997650b2006-04-24 23:13:46 +0000524 if (c == 'q' || c == initial_settings.c_cc[VINTR])
"Vladimir N. Oleynik"c218a292006-02-15 17:15:56 +0000525 break;
Rob Landley997650b2006-04-24 23:13:46 +0000526 if (c == 'M') {
Denis Vlasenkofa076802006-11-05 00:38:51 +0000527#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
Eric Andersen08a72202002-09-30 20:52:10 +0000528 sort_function[0] = mem_sort;
529 sort_function[1] = pcpu_sort;
530 sort_function[2] = time_sort;
531#else
532 sort_function = mem_sort;
533#endif
534 }
Denis Vlasenkofa076802006-11-05 00:38:51 +0000535#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
Rob Landley997650b2006-04-24 23:13:46 +0000536 if (c == 'P') {
Eric Andersen08a72202002-09-30 20:52:10 +0000537 sort_function[0] = pcpu_sort;
538 sort_function[1] = mem_sort;
539 sort_function[2] = time_sort;
540 }
Rob Landley997650b2006-04-24 23:13:46 +0000541 if (c == 'T') {
Eric Andersen08a72202002-09-30 20:52:10 +0000542 sort_function[0] = time_sort;
543 sort_function[1] = mem_sort;
544 sort_function[2] = pcpu_sort;
545 }
546#endif
Rob Landley997650b2006-04-24 23:13:46 +0000547 if (c == 'N') {
Denis Vlasenkofa076802006-11-05 00:38:51 +0000548#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
Eric Andersen08a72202002-09-30 20:52:10 +0000549 sort_function[0] = pid_sort;
550#else
551 sort_function = pid_sort;
552#endif
553 }
554 }
Denis Vlasenko266bc172006-09-29 17:16:39 +0000555 if (!--iterations)
556 break;
Eric Andersen08a72202002-09-30 20:52:10 +0000557#else
Eric Andersen420b2082002-09-17 22:14:58 +0000558 sleep(interval);
Denis Vlasenkofa076802006-11-05 00:38:51 +0000559#endif /* FEATURE_USE_TERMIOS */
Eric Andersen08a72202002-09-30 20:52:10 +0000560 clearmems();
Eric Andersen420b2082002-09-17 22:14:58 +0000561 }
Rob Landley997650b2006-04-24 23:13:46 +0000562 if (ENABLE_FEATURE_CLEAN_UP)
"Vladimir N. Oleynik"c218a292006-02-15 17:15:56 +0000563 clearmems();
564 putchar('\n');
Eric Andersen420b2082002-09-17 22:14:58 +0000565 return EXIT_SUCCESS;
566}