top.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118
  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. * Sept 2008: Vineet Gupta <vineet.gupta@arc.com>
  21. * Added Support for reporting SMP Information
  22. * - CPU where Process was last seen running
  23. * (to see effect of sched_setaffinity() etc)
  24. * - CPU Time Split (idle/IO/wait etc) PER CPU
  25. *
  26. * Copyright (c) 1992 Branko Lankester
  27. * Copyright (c) 1992 Roger Binns
  28. * Copyright (C) 1994-1996 Charles L. Blake.
  29. * Copyright (C) 1992-1998 Michael K. Johnson
  30. *
  31. * Licensed under GPLv2, see file LICENSE in this tarball for details.
  32. */
  33. #include "libbb.h"
  34. typedef 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. #if ENABLE_FEATURE_TOP_SMP_PROCESS
  45. int last_seen_on_cpu;
  46. #endif
  47. } top_status_t;
  48. typedef struct jiffy_counts_t {
  49. /* Linux 2.4.x has only first four */
  50. unsigned long long usr, nic, sys, idle;
  51. unsigned long long iowait, irq, softirq, steal;
  52. unsigned long long total;
  53. unsigned long long busy;
  54. } jiffy_counts_t;
  55. /* This structure stores some critical information from one frame to
  56. the next. Used for finding deltas. */
  57. typedef struct save_hist {
  58. unsigned long ticks;
  59. pid_t pid;
  60. } save_hist;
  61. typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q);
  62. enum { SORT_DEPTH = 3 };
  63. struct globals {
  64. top_status_t *top;
  65. int ntop;
  66. #if ENABLE_FEATURE_TOPMEM
  67. smallint sort_field;
  68. smallint inverted;
  69. #endif
  70. #if ENABLE_FEATURE_TOP_SMP_CPU
  71. smallint smp_cpu_info; /* one/many cpu info lines? */
  72. #endif
  73. #if ENABLE_FEATURE_USE_TERMIOS
  74. struct termios initial_settings;
  75. #endif
  76. #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  77. cmp_funcp sort_function[1];
  78. #else
  79. cmp_funcp sort_function[SORT_DEPTH];
  80. struct save_hist *prev_hist;
  81. int prev_hist_count;
  82. jiffy_counts_t cur_jif, prev_jif;
  83. /* int hist_iterations; */
  84. unsigned total_pcpu;
  85. /* unsigned long total_vsz; */
  86. #endif
  87. #if ENABLE_FEATURE_TOP_SMP_CPU
  88. /* Per CPU samples: current and last */
  89. jiffy_counts_t *cpu_jif, *cpu_prev_jif;
  90. int num_cpus;
  91. #endif
  92. char line_buf[80];
  93. };
  94. enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) };
  95. #define G (*(struct globals*)&bb_common_bufsiz1)
  96. #define INIT_G() do { \
  97. struct G_sizecheck { \
  98. char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
  99. }; \
  100. } while (0)
  101. #define top (G.top )
  102. #define ntop (G.ntop )
  103. #define sort_field (G.sort_field )
  104. #define inverted (G.inverted )
  105. #define smp_cpu_info (G.smp_cpu_info )
  106. #define initial_settings (G.initial_settings )
  107. #define sort_function (G.sort_function )
  108. #define prev_hist (G.prev_hist )
  109. #define prev_hist_count (G.prev_hist_count )
  110. #define cur_jif (G.cur_jif )
  111. #define prev_jif (G.prev_jif )
  112. #define cpu_jif (G.cpu_jif )
  113. #define cpu_prev_jif (G.cpu_prev_jif )
  114. #define num_cpus (G.num_cpus )
  115. #define total_pcpu (G.total_pcpu )
  116. #define line_buf (G.line_buf )
  117. enum {
  118. OPT_d = (1 << 0),
  119. OPT_n = (1 << 1),
  120. OPT_b = (1 << 2),
  121. OPT_EOF = (1 << 3), /* pseudo: "we saw EOF in stdin" */
  122. };
  123. #define OPT_BATCH_MODE (option_mask32 & OPT_b)
  124. #if ENABLE_FEATURE_USE_TERMIOS
  125. static int pid_sort(top_status_t *P, top_status_t *Q)
  126. {
  127. /* Buggy wrt pids with high bit set */
  128. /* (linux pids are in [1..2^15-1]) */
  129. return (Q->pid - P->pid);
  130. }
  131. #endif
  132. static int mem_sort(top_status_t *P, top_status_t *Q)
  133. {
  134. /* We want to avoid unsigned->signed and truncation errors */
  135. if (Q->vsz < P->vsz) return -1;
  136. return Q->vsz != P->vsz; /* 0 if ==, 1 if > */
  137. }
  138. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  139. static int pcpu_sort(top_status_t *P, top_status_t *Q)
  140. {
  141. /* Buggy wrt ticks with high bit set */
  142. /* Affects only processes for which ticks overflow */
  143. return (int)Q->pcpu - (int)P->pcpu;
  144. }
  145. static int time_sort(top_status_t *P, top_status_t *Q)
  146. {
  147. /* We want to avoid unsigned->signed and truncation errors */
  148. if (Q->ticks < P->ticks) return -1;
  149. return Q->ticks != P->ticks; /* 0 if ==, 1 if > */
  150. }
  151. static int mult_lvl_cmp(void* a, void* b)
  152. {
  153. int i, cmp_val;
  154. for (i = 0; i < SORT_DEPTH; i++) {
  155. cmp_val = (*sort_function[i])(a, b);
  156. if (cmp_val != 0)
  157. return cmp_val;
  158. }
  159. return 0;
  160. }
  161. static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif)
  162. {
  163. #if !ENABLE_FEATURE_TOP_SMP_CPU
  164. static const char fmt[] = "cpu %llu %llu %llu %llu %llu %llu %llu %llu";
  165. #else
  166. static const char fmt[] = "cp%*s %llu %llu %llu %llu %llu %llu %llu %llu";
  167. #endif
  168. int ret;
  169. if (!fgets(line_buf, LINE_BUF_SIZE, fp) || line_buf[0] != 'c' /* not "cpu" */)
  170. return 0;
  171. ret = sscanf(line_buf, fmt,
  172. &p_jif->usr, &p_jif->nic, &p_jif->sys, &p_jif->idle,
  173. &p_jif->iowait, &p_jif->irq, &p_jif->softirq,
  174. &p_jif->steal);
  175. if (ret >= 4) {
  176. p_jif->total = p_jif->usr + p_jif->nic + p_jif->sys + p_jif->idle
  177. + p_jif->iowait + p_jif->irq + p_jif->softirq + p_jif->steal;
  178. /* procps 2.x does not count iowait as busy time */
  179. p_jif->busy = p_jif->total - p_jif->idle - p_jif->iowait;
  180. }
  181. return ret;
  182. }
  183. static void get_jiffy_counts(void)
  184. {
  185. FILE* fp = xfopen_for_read("stat");
  186. /* We need to parse cumulative counts even if SMP CPU display is on,
  187. * they are used to calculate per process CPU% */
  188. prev_jif = cur_jif;
  189. if (read_cpu_jiffy(fp, &cur_jif) < 4)
  190. bb_error_msg_and_die("can't read /proc/stat");
  191. #if !ENABLE_FEATURE_TOP_SMP_CPU
  192. fclose(fp);
  193. return;
  194. #else
  195. if (!smp_cpu_info) {
  196. fclose(fp);
  197. return;
  198. }
  199. if (!num_cpus) {
  200. /* First time here. How many CPUs?
  201. * There will be at least 1 /proc/stat line with cpu%d
  202. */
  203. while (1) {
  204. cpu_jif = xrealloc_vector(cpu_jif, 1, num_cpus);
  205. if (read_cpu_jiffy(fp, &cpu_jif[num_cpus]) <= 4)
  206. break;
  207. num_cpus++;
  208. }
  209. if (num_cpus == 0) /* /proc/stat with only "cpu ..." line?! */
  210. smp_cpu_info = 0;
  211. cpu_prev_jif = xzalloc(sizeof(cpu_prev_jif[0]) * num_cpus);
  212. /* Otherwise the first per cpu display shows all 100% idles */
  213. usleep(50000);
  214. } else { /* Non first time invocation */
  215. jiffy_counts_t *tmp;
  216. int i;
  217. /* First switch the sample pointers: no need to copy */
  218. tmp = cpu_prev_jif;
  219. cpu_prev_jif = cpu_jif;
  220. cpu_jif = tmp;
  221. /* Get the new samples */
  222. for (i = 0; i < num_cpus; i++)
  223. read_cpu_jiffy(fp, &cpu_jif[i]);
  224. }
  225. #endif
  226. fclose(fp);
  227. }
  228. static void do_stats(void)
  229. {
  230. top_status_t *cur;
  231. pid_t pid;
  232. int i, last_i, n;
  233. struct save_hist *new_hist;
  234. get_jiffy_counts();
  235. total_pcpu = 0;
  236. /* total_vsz = 0; */
  237. new_hist = xmalloc(sizeof(new_hist[0]) * ntop);
  238. /*
  239. * Make a pass through the data to get stats.
  240. */
  241. /* hist_iterations = 0; */
  242. i = 0;
  243. for (n = 0; n < ntop; n++) {
  244. cur = top + n;
  245. /*
  246. * Calculate time in cur process. Time is sum of user time
  247. * and system time
  248. */
  249. pid = cur->pid;
  250. new_hist[n].ticks = cur->ticks;
  251. new_hist[n].pid = pid;
  252. /* find matching entry from previous pass */
  253. cur->pcpu = 0;
  254. /* do not start at index 0, continue at last used one
  255. * (brought hist_iterations from ~14000 down to 172) */
  256. last_i = i;
  257. if (prev_hist_count) do {
  258. if (prev_hist[i].pid == pid) {
  259. cur->pcpu = cur->ticks - prev_hist[i].ticks;
  260. total_pcpu += cur->pcpu;
  261. break;
  262. }
  263. i = (i+1) % prev_hist_count;
  264. /* hist_iterations++; */
  265. } while (i != last_i);
  266. /* total_vsz += cur->vsz; */
  267. }
  268. /*
  269. * Save cur frame's information.
  270. */
  271. free(prev_hist);
  272. prev_hist = new_hist;
  273. prev_hist_count = ntop;
  274. }
  275. #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
  276. #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && ENABLE_FEATURE_TOP_DECIMALS
  277. /* formats 7 char string (8 with terminating NUL) */
  278. static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total)
  279. {
  280. unsigned t;
  281. if (value >= total) { /* 100% ? */
  282. strcpy(pbuf, " 100% ");
  283. return pbuf;
  284. }
  285. /* else generate " [N/space]N.N% " string */
  286. value = 1000 * value / total;
  287. t = value / 100;
  288. value = value % 100;
  289. pbuf[0] = ' ';
  290. pbuf[1] = t ? t + '0' : ' ';
  291. pbuf[2] = '0' + (value / 10);
  292. pbuf[3] = '.';
  293. pbuf[4] = '0' + (value % 10);
  294. pbuf[5] = '%';
  295. pbuf[6] = ' ';
  296. pbuf[7] = '\0';
  297. return pbuf;
  298. }
  299. #endif
  300. #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS
  301. static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p)
  302. {
  303. /*
  304. * xxx% = (cur_jif.xxx - prev_jif.xxx) / (cur_jif.total - prev_jif.total) * 100%
  305. */
  306. unsigned total_diff;
  307. jiffy_counts_t *p_jif, *p_prev_jif;
  308. int i;
  309. #if ENABLE_FEATURE_TOP_SMP_CPU
  310. int n_cpu_lines;
  311. #endif
  312. /* using (unsigned) casts to make operations cheaper */
  313. #define CALC_TOT_DIFF ((unsigned)(p_jif->total - p_prev_jif->total) ? : 1)
  314. #if ENABLE_FEATURE_TOP_DECIMALS
  315. #define CALC_STAT(xxx) char xxx[8]
  316. #define SHOW_STAT(xxx) fmt_100percent_8(xxx, (unsigned)(p_jif->xxx - p_prev_jif->xxx), total_diff)
  317. #define FMT "%s"
  318. #else
  319. #define CALC_STAT(xxx) unsigned xxx = 100 * (unsigned)(p_jif->xxx - p_prev_jif->xxx) / total_diff
  320. #define SHOW_STAT(xxx) xxx
  321. #define FMT "%4u%% "
  322. #endif
  323. #if !ENABLE_FEATURE_TOP_SMP_CPU
  324. {
  325. i = 1;
  326. p_jif = &cur_jif;
  327. p_prev_jif = &prev_jif;
  328. #else
  329. /* Loop thru CPU(s) */
  330. n_cpu_lines = smp_cpu_info ? num_cpus : 1;
  331. if (n_cpu_lines > *lines_rem_p)
  332. n_cpu_lines = *lines_rem_p;
  333. for (i = 0; i < n_cpu_lines; i++) {
  334. p_jif = &cpu_jif[i];
  335. p_prev_jif = &cpu_prev_jif[i];
  336. #endif
  337. total_diff = CALC_TOT_DIFF;
  338. { /* Need a block: CALC_STAT are declarations */
  339. CALC_STAT(usr);
  340. CALC_STAT(sys);
  341. CALC_STAT(nic);
  342. CALC_STAT(idle);
  343. CALC_STAT(iowait);
  344. CALC_STAT(irq);
  345. CALC_STAT(softirq);
  346. /*CALC_STAT(steal);*/
  347. snprintf(scrbuf, scr_width,
  348. /* Barely fits in 79 chars when in "decimals" mode. */
  349. #if ENABLE_FEATURE_TOP_SMP_CPU
  350. "CPU%s:"FMT"usr"FMT"sys"FMT"nic"FMT"idle"FMT"io"FMT"irq"FMT"sirq",
  351. (smp_cpu_info ? utoa(i) : ""),
  352. #else
  353. "CPU:"FMT"usr"FMT"sys"FMT"nic"FMT"idle"FMT"io"FMT"irq"FMT"sirq",
  354. #endif
  355. SHOW_STAT(usr), SHOW_STAT(sys), SHOW_STAT(nic), SHOW_STAT(idle),
  356. SHOW_STAT(iowait), SHOW_STAT(irq), SHOW_STAT(softirq)
  357. /*, SHOW_STAT(steal) - what is this 'steal' thing? */
  358. /* I doubt anyone wants to know it */
  359. );
  360. puts(scrbuf);
  361. }
  362. }
  363. #undef SHOW_STAT
  364. #undef CALC_STAT
  365. #undef FMT
  366. *lines_rem_p -= i;
  367. }
  368. #else /* !ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS */
  369. #define display_cpus(scr_width, scrbuf, lines_rem) ((void)0)
  370. #endif
  371. static unsigned long display_header(int scr_width, int *lines_rem_p)
  372. {
  373. FILE *fp;
  374. char buf[80];
  375. char scrbuf[80];
  376. unsigned long total, used, mfree, shared, buffers, cached;
  377. /* read memory info */
  378. fp = xfopen_for_read("meminfo");
  379. /*
  380. * Old kernels (such as 2.4.x) had a nice summary of memory info that
  381. * we could parse, however this is gone entirely in 2.6. Try parsing
  382. * the old way first, and if that fails, parse each field manually.
  383. *
  384. * First, we read in the first line. Old kernels will have bogus
  385. * strings we don't care about, whereas new kernels will start right
  386. * out with MemTotal:
  387. * -- PFM.
  388. */
  389. if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) {
  390. fgets(buf, sizeof(buf), fp); /* skip first line */
  391. fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
  392. &total, &used, &mfree, &shared, &buffers, &cached);
  393. /* convert to kilobytes */
  394. used /= 1024;
  395. mfree /= 1024;
  396. shared /= 1024;
  397. buffers /= 1024;
  398. cached /= 1024;
  399. total /= 1024;
  400. } else {
  401. /*
  402. * Revert to manual parsing, which incidentally already has the
  403. * sizes in kilobytes. This should be safe for both 2.4 and
  404. * 2.6.
  405. */
  406. fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
  407. /*
  408. * MemShared: is no longer present in 2.6. Report this as 0,
  409. * to maintain consistent behavior with normal procps.
  410. */
  411. if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
  412. shared = 0;
  413. fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
  414. fscanf(fp, "Cached: %lu %s\n", &cached, buf);
  415. used = total - mfree;
  416. }
  417. fclose(fp);
  418. /* output memory info */
  419. if (scr_width > (int)sizeof(scrbuf))
  420. scr_width = sizeof(scrbuf);
  421. snprintf(scrbuf, scr_width,
  422. "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
  423. used, mfree, shared, buffers, cached);
  424. /* clear screen & go to top */
  425. printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf);
  426. (*lines_rem_p)--;
  427. /* Display CPU time split as percentage of total time
  428. * This displays either a cumulative line or one line per CPU
  429. */
  430. display_cpus(scr_width, scrbuf, lines_rem_p);
  431. /* read load average as a string */
  432. buf[0] = '\0';
  433. open_read_close("loadavg", buf, sizeof(buf) - 1);
  434. buf[sizeof(buf) - 1] = '\n';
  435. *strchr(buf, '\n') = '\0';
  436. snprintf(scrbuf, scr_width, "Load average: %s", buf);
  437. puts(scrbuf);
  438. (*lines_rem_p)--;
  439. return total;
  440. }
  441. static NOINLINE void display_process_list(int lines_rem, int scr_width)
  442. {
  443. enum {
  444. BITS_PER_INT = sizeof(int) * 8
  445. };
  446. top_status_t *s;
  447. char vsz_str_buf[8];
  448. unsigned long total_memory = display_header(scr_width, &lines_rem); /* or use total_vsz? */
  449. /* xxx_shift and xxx_scale variables allow us to replace
  450. * expensive divides with multiply and shift */
  451. unsigned pmem_shift, pmem_scale, pmem_half;
  452. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  453. unsigned pcpu_shift, pcpu_scale, pcpu_half;
  454. unsigned busy_jifs;
  455. #endif
  456. /* what info of the processes is shown */
  457. printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
  458. " PID PPID USER STAT VSZ %MEM"
  459. #if ENABLE_FEATURE_TOP_SMP_PROCESS
  460. " CPU"
  461. #endif
  462. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  463. " %CPU"
  464. #endif
  465. " COMMAND");
  466. lines_rem--;
  467. #if ENABLE_FEATURE_TOP_DECIMALS
  468. #define UPSCALE 1000
  469. #define CALC_STAT(name, val) div_t name = div((val), 10)
  470. #define SHOW_STAT(name) name.quot, '0'+name.rem
  471. #define FMT "%3u.%c"
  472. #else
  473. #define UPSCALE 100
  474. #define CALC_STAT(name, val) unsigned name = (val)
  475. #define SHOW_STAT(name) name
  476. #define FMT "%4u%%"
  477. #endif
  478. /*
  479. * MEM% = s->vsz/MemTotal
  480. */
  481. pmem_shift = BITS_PER_INT-11;
  482. pmem_scale = UPSCALE*(1U<<(BITS_PER_INT-11)) / total_memory;
  483. /* s->vsz is in kb. we want (s->vsz * pmem_scale) to never overflow */
  484. while (pmem_scale >= 512) {
  485. pmem_scale /= 4;
  486. pmem_shift -= 2;
  487. }
  488. pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2);
  489. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  490. busy_jifs = cur_jif.busy - prev_jif.busy;
  491. /* This happens if there were lots of short-lived processes
  492. * between two top updates (e.g. compilation) */
  493. if (total_pcpu < busy_jifs) total_pcpu = busy_jifs;
  494. /*
  495. * CPU% = s->pcpu/sum(s->pcpu) * busy_cpu_ticks/total_cpu_ticks
  496. * (pcpu is delta of sys+user time between samples)
  497. */
  498. /* (cur_jif.xxx - prev_jif.xxx) and s->pcpu are
  499. * in 0..~64000 range (HZ*update_interval).
  500. * we assume that unsigned is at least 32-bit.
  501. */
  502. pcpu_shift = 6;
  503. pcpu_scale = (UPSCALE*64 * (uint16_t)busy_jifs ? : 1);
  504. while (pcpu_scale < (1U << (BITS_PER_INT-2))) {
  505. pcpu_scale *= 4;
  506. pcpu_shift += 2;
  507. }
  508. pcpu_scale /= ( (uint16_t)(cur_jif.total - prev_jif.total) * total_pcpu ? : 1);
  509. /* we want (s->pcpu * pcpu_scale) to never overflow */
  510. while (pcpu_scale >= 1024) {
  511. pcpu_scale /= 4;
  512. pcpu_shift -= 2;
  513. }
  514. pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2);
  515. /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */
  516. #endif
  517. /* Ok, all preliminary data is ready, go through the list */
  518. scr_width += 2; /* account for leading '\n' and trailing NUL */
  519. if (lines_rem > ntop)
  520. lines_rem = ntop;
  521. s = top;
  522. while (--lines_rem >= 0) {
  523. unsigned col;
  524. CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift);
  525. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  526. CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift);
  527. #endif
  528. if (s->vsz >= 100000)
  529. sprintf(vsz_str_buf, "%6ldm", s->vsz/1024);
  530. else
  531. sprintf(vsz_str_buf, "%7ld", s->vsz);
  532. /* PID PPID USER STAT VSZ %MEM [%CPU] COMMAND */
  533. col = snprintf(line_buf, scr_width,
  534. "\n" "%5u%6u %-8.8s %s%s" FMT
  535. #if ENABLE_FEATURE_TOP_SMP_PROCESS
  536. " %3d"
  537. #endif
  538. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  539. FMT
  540. #endif
  541. " ",
  542. s->pid, s->ppid, get_cached_username(s->uid),
  543. s->state, vsz_str_buf,
  544. SHOW_STAT(pmem)
  545. #if ENABLE_FEATURE_TOP_SMP_PROCESS
  546. , s->last_seen_on_cpu
  547. #endif
  548. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  549. , SHOW_STAT(pcpu)
  550. #endif
  551. );
  552. if ((int)(col + 1) < scr_width)
  553. read_cmdline(line_buf + col, scr_width - col - 1, s->pid, s->comm);
  554. fputs(line_buf, stdout);
  555. /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
  556. cur_jif.busy - prev_jif.busy, cur_jif.total - prev_jif.total); */
  557. s++;
  558. }
  559. /* printf(" %d", hist_iterations); */
  560. bb_putchar(OPT_BATCH_MODE ? '\n' : '\r');
  561. fflush(stdout);
  562. }
  563. #undef UPSCALE
  564. #undef SHOW_STAT
  565. #undef CALC_STAT
  566. #undef FMT
  567. static void clearmems(void)
  568. {
  569. clear_username_cache();
  570. free(top);
  571. top = NULL;
  572. ntop = 0;
  573. }
  574. #if ENABLE_FEATURE_USE_TERMIOS
  575. static void reset_term(void)
  576. {
  577. tcsetattr_stdin_TCSANOW(&initial_settings);
  578. if (ENABLE_FEATURE_CLEAN_UP) {
  579. clearmems();
  580. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  581. free(prev_hist);
  582. #endif
  583. }
  584. }
  585. static void sig_catcher(int sig UNUSED_PARAM)
  586. {
  587. reset_term();
  588. exit(EXIT_FAILURE);
  589. }
  590. #endif /* FEATURE_USE_TERMIOS */
  591. /*
  592. * TOPMEM support
  593. */
  594. typedef unsigned long mem_t;
  595. typedef struct topmem_status_t {
  596. unsigned pid;
  597. char comm[COMM_LEN];
  598. /* vsz doesn't count /dev/xxx mappings except /dev/zero */
  599. mem_t vsz ;
  600. mem_t vszrw ;
  601. mem_t rss ;
  602. mem_t rss_sh ;
  603. mem_t dirty ;
  604. mem_t dirty_sh;
  605. mem_t stack ;
  606. } topmem_status_t;
  607. enum { NUM_SORT_FIELD = 7 };
  608. #define topmem ((topmem_status_t*)top)
  609. #if ENABLE_FEATURE_TOPMEM
  610. static int topmem_sort(char *a, char *b)
  611. {
  612. int n;
  613. mem_t l, r;
  614. n = offsetof(topmem_status_t, vsz) + (sort_field * sizeof(mem_t));
  615. l = *(mem_t*)(a + n);
  616. r = *(mem_t*)(b + n);
  617. // if (l == r) {
  618. // l = a->mapped_rw;
  619. // r = b->mapped_rw;
  620. // }
  621. /* We want to avoid unsigned->signed and truncation errors */
  622. /* l>r: -1, l=r: 0, l<r: 1 */
  623. n = (l > r) ? -1 : (l != r);
  624. return inverted ? -n : n;
  625. }
  626. /* Cut "NNNN " out of " NNNN kb" */
  627. static char *grab_number(char *str, const char *match, unsigned sz)
  628. {
  629. if (strncmp(str, match, sz) == 0) {
  630. str = skip_whitespace(str + sz);
  631. (skip_non_whitespace(str))[1] = '\0';
  632. return xstrdup(str);
  633. }
  634. return NULL;
  635. }
  636. /* display header info (meminfo / loadavg) */
  637. static void display_topmem_header(int scr_width, int *lines_rem_p)
  638. {
  639. char linebuf[128];
  640. unsigned i;
  641. FILE *fp;
  642. union {
  643. struct {
  644. /* 1 */ char *total;
  645. /* 2 */ char *mfree;
  646. /* 3 */ char *buf;
  647. /* 4 */ char *cache;
  648. /* 5 */ char *swaptotal;
  649. /* 6 */ char *swapfree;
  650. /* 7 */ char *dirty;
  651. /* 8 */ char *mwrite;
  652. /* 9 */ char *anon;
  653. /* 10 */ char *map;
  654. /* 11 */ char *slab;
  655. } u;
  656. char *str[11];
  657. } Z;
  658. #define total Z.u.total
  659. #define mfree Z.u.mfree
  660. #define buf Z.u.buf
  661. #define cache Z.u.cache
  662. #define swaptotal Z.u.swaptotal
  663. #define swapfree Z.u.swapfree
  664. #define dirty Z.u.dirty
  665. #define mwrite Z.u.mwrite
  666. #define anon Z.u.anon
  667. #define map Z.u.map
  668. #define slab Z.u.slab
  669. #define str Z.str
  670. memset(&Z, 0, sizeof(Z));
  671. /* read memory info */
  672. fp = xfopen_for_read("meminfo");
  673. while (fgets(linebuf, sizeof(linebuf), fp)) {
  674. char *p;
  675. #define SCAN(match, name) \
  676. p = grab_number(linebuf, match, sizeof(match)-1); \
  677. if (p) { name = p; continue; }
  678. SCAN("MemTotal:", total);
  679. SCAN("MemFree:", mfree);
  680. SCAN("Buffers:", buf);
  681. SCAN("Cached:", cache);
  682. SCAN("SwapTotal:", swaptotal);
  683. SCAN("SwapFree:", swapfree);
  684. SCAN("Dirty:", dirty);
  685. SCAN("Writeback:", mwrite);
  686. SCAN("AnonPages:", anon);
  687. SCAN("Mapped:", map);
  688. SCAN("Slab:", slab);
  689. #undef SCAN
  690. }
  691. fclose(fp);
  692. #define S(s) (s ? s : "0 ")
  693. snprintf(linebuf, sizeof(linebuf),
  694. "Mem %stotal %sanon %smap %sfree",
  695. S(total), S(anon), S(map), S(mfree));
  696. printf(OPT_BATCH_MODE ? "%.*s\n" : "\e[H\e[J%.*s\n", scr_width, linebuf);
  697. snprintf(linebuf, sizeof(linebuf),
  698. " %sslab %sbuf %scache %sdirty %swrite",
  699. S(slab), S(buf), S(cache), S(dirty), S(mwrite));
  700. printf("%.*s\n", scr_width, linebuf);
  701. snprintf(linebuf, sizeof(linebuf),
  702. "Swap %stotal %sfree", // TODO: % used?
  703. S(swaptotal), S(swapfree));
  704. printf("%.*s\n", scr_width, linebuf);
  705. (*lines_rem_p) -= 3;
  706. #undef S
  707. for (i = 0; i < ARRAY_SIZE(str); i++)
  708. free(str[i]);
  709. #undef total
  710. #undef free
  711. #undef buf
  712. #undef cache
  713. #undef swaptotal
  714. #undef swapfree
  715. #undef dirty
  716. #undef write
  717. #undef anon
  718. #undef map
  719. #undef slab
  720. #undef str
  721. }
  722. static void ulltoa6_and_space(unsigned long long ul, char buf[6])
  723. {
  724. /* see http://en.wikipedia.org/wiki/Tera */
  725. smart_ulltoa5(ul, buf, " mgtpezy");
  726. buf[5] = ' ';
  727. }
  728. static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width)
  729. {
  730. #define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK"
  731. #define MIN_WIDTH sizeof(HDR_STR)
  732. const topmem_status_t *s = topmem;
  733. display_topmem_header(scr_width, &lines_rem);
  734. strcpy(line_buf, HDR_STR " COMMAND");
  735. line_buf[5 + sort_field * 6] = '*';
  736. printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf);
  737. lines_rem--;
  738. if (lines_rem > ntop)
  739. lines_rem = ntop;
  740. while (--lines_rem >= 0) {
  741. /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */
  742. ulltoa6_and_space(s->pid , &line_buf[0*6]);
  743. ulltoa6_and_space(s->vsz , &line_buf[1*6]);
  744. ulltoa6_and_space(s->vszrw , &line_buf[2*6]);
  745. ulltoa6_and_space(s->rss , &line_buf[3*6]);
  746. ulltoa6_and_space(s->rss_sh , &line_buf[4*6]);
  747. ulltoa6_and_space(s->dirty , &line_buf[5*6]);
  748. ulltoa6_and_space(s->dirty_sh, &line_buf[6*6]);
  749. ulltoa6_and_space(s->stack , &line_buf[7*6]);
  750. line_buf[8*6] = '\0';
  751. if (scr_width > (int)MIN_WIDTH) {
  752. read_cmdline(&line_buf[8*6], scr_width - MIN_WIDTH, s->pid, s->comm);
  753. }
  754. printf("\n""%.*s", scr_width, line_buf);
  755. s++;
  756. }
  757. bb_putchar(OPT_BATCH_MODE ? '\n' : '\r');
  758. fflush(stdout);
  759. #undef HDR_STR
  760. #undef MIN_WIDTH
  761. }
  762. #else
  763. void display_topmem_process_list(int lines_rem, int scr_width);
  764. int topmem_sort(char *a, char *b);
  765. #endif /* TOPMEM */
  766. /*
  767. * end TOPMEM support
  768. */
  769. enum {
  770. TOP_MASK = 0
  771. | PSSCAN_PID
  772. | PSSCAN_PPID
  773. | PSSCAN_VSZ
  774. | PSSCAN_STIME
  775. | PSSCAN_UTIME
  776. | PSSCAN_STATE
  777. | PSSCAN_COMM
  778. | PSSCAN_CPU
  779. | PSSCAN_UIDGID,
  780. TOPMEM_MASK = 0
  781. | PSSCAN_PID
  782. | PSSCAN_SMAPS
  783. | PSSCAN_COMM,
  784. };
  785. int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  786. int top_main(int argc UNUSED_PARAM, char **argv)
  787. {
  788. int iterations;
  789. unsigned lines, col;
  790. int lines_rem;
  791. unsigned interval;
  792. char *str_interval, *str_iterations;
  793. IF_NOT_FEATURE_TOPMEM(const) unsigned scan_mask = TOP_MASK;
  794. #if ENABLE_FEATURE_USE_TERMIOS
  795. struct termios new_settings;
  796. struct pollfd pfd[1];
  797. unsigned char c;
  798. pfd[0].fd = 0;
  799. pfd[0].events = POLLIN;
  800. #endif /* FEATURE_USE_TERMIOS */
  801. INIT_G();
  802. interval = 5; /* default update interval is 5 seconds */
  803. iterations = 0; /* infinite */
  804. #if ENABLE_FEATURE_TOP_SMP_CPU
  805. /*num_cpus = 0;*/
  806. /*smp_cpu_info = 0;*/ /* to start with show aggregate */
  807. cpu_jif = &cur_jif;
  808. cpu_prev_jif = &prev_jif;
  809. #endif
  810. /* all args are options; -n NUM */
  811. opt_complementary = "-";
  812. col = getopt32(argv, "d:n:b", &str_interval, &str_iterations);
  813. if (col & OPT_d) {
  814. /* work around for "-d 1" -> "-d -1" done by getopt32 */
  815. if (str_interval[0] == '-')
  816. str_interval++;
  817. /* Need to limit it to not overflow poll timeout */
  818. interval = xatou16(str_interval);
  819. }
  820. if (col & OPT_n) {
  821. if (str_iterations[0] == '-')
  822. str_iterations++;
  823. iterations = xatou(str_iterations);
  824. }
  825. /* change to /proc */
  826. xchdir("/proc");
  827. #if ENABLE_FEATURE_USE_TERMIOS
  828. tcgetattr(0, (void *) &initial_settings);
  829. memcpy(&new_settings, &initial_settings, sizeof(new_settings));
  830. /* unbuffered input, turn off echo */
  831. new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL);
  832. bb_signals(BB_FATAL_SIGS, sig_catcher);
  833. tcsetattr_stdin_TCSANOW(&new_settings);
  834. #endif /* FEATURE_USE_TERMIOS */
  835. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  836. sort_function[0] = pcpu_sort;
  837. sort_function[1] = mem_sort;
  838. sort_function[2] = time_sort;
  839. #else
  840. sort_function[0] = mem_sort;
  841. #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
  842. while (1) {
  843. procps_status_t *p = NULL;
  844. lines = 24; /* default */
  845. col = 79;
  846. #if ENABLE_FEATURE_USE_TERMIOS
  847. /* We output to stdout, we need size of stdout (not stdin)! */
  848. get_terminal_width_height(STDOUT_FILENO, &col, &lines);
  849. if (lines < 5 || col < 10) {
  850. sleep(interval);
  851. continue;
  852. }
  853. #endif /* FEATURE_USE_TERMIOS */
  854. if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */
  855. col = LINE_BUF_SIZE-2;
  856. /* read process IDs & status for all the processes */
  857. while ((p = procps_scan(p, scan_mask)) != NULL) {
  858. int n;
  859. if (scan_mask == TOP_MASK) {
  860. n = ntop;
  861. top = xrealloc_vector(top, 6, ntop++);
  862. top[n].pid = p->pid;
  863. top[n].ppid = p->ppid;
  864. top[n].vsz = p->vsz;
  865. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  866. top[n].ticks = p->stime + p->utime;
  867. #endif
  868. top[n].uid = p->uid;
  869. strcpy(top[n].state, p->state);
  870. strcpy(top[n].comm, p->comm);
  871. #if ENABLE_FEATURE_TOP_SMP_PROCESS
  872. top[n].last_seen_on_cpu = p->last_seen_on_cpu;
  873. #endif
  874. } else { /* TOPMEM */
  875. #if ENABLE_FEATURE_TOPMEM
  876. if (!(p->mapped_ro | p->mapped_rw))
  877. continue; /* kernel threads are ignored */
  878. n = ntop;
  879. /* No bug here - top and topmem are the same */
  880. top = xrealloc_vector(topmem, 6, ntop++);
  881. strcpy(topmem[n].comm, p->comm);
  882. topmem[n].pid = p->pid;
  883. topmem[n].vsz = p->mapped_rw + p->mapped_ro;
  884. topmem[n].vszrw = p->mapped_rw;
  885. topmem[n].rss_sh = p->shared_clean + p->shared_dirty;
  886. topmem[n].rss = p->private_clean + p->private_dirty + topmem[n].rss_sh;
  887. topmem[n].dirty = p->private_dirty + p->shared_dirty;
  888. topmem[n].dirty_sh = p->shared_dirty;
  889. topmem[n].stack = p->stack;
  890. #endif
  891. }
  892. } /* end of "while we read /proc" */
  893. if (ntop == 0) {
  894. bb_error_msg("no process info in /proc");
  895. break;
  896. }
  897. if (scan_mask == TOP_MASK) {
  898. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  899. if (!prev_hist_count) {
  900. do_stats();
  901. usleep(100000);
  902. clearmems();
  903. continue;
  904. }
  905. do_stats();
  906. /* TODO: we don't need to sort all 10000 processes, we need to find top 24! */
  907. qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
  908. #else
  909. qsort(top, ntop, sizeof(top_status_t), (void*)(sort_function[0]));
  910. #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
  911. }
  912. #if ENABLE_FEATURE_TOPMEM
  913. else { /* TOPMEM */
  914. qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort);
  915. }
  916. #endif
  917. lines_rem = lines;
  918. if (OPT_BATCH_MODE) {
  919. lines_rem = INT_MAX;
  920. }
  921. if (scan_mask == TOP_MASK)
  922. display_process_list(lines_rem, col);
  923. #if ENABLE_FEATURE_TOPMEM
  924. else
  925. display_topmem_process_list(lines_rem, col);
  926. #endif
  927. clearmems();
  928. if (iterations >= 0 && !--iterations)
  929. break;
  930. #if !ENABLE_FEATURE_USE_TERMIOS
  931. sleep(interval);
  932. #else
  933. if (option_mask32 & (OPT_b|OPT_EOF))
  934. /* batch mode, or EOF on stdin ("top </dev/null") */
  935. sleep(interval);
  936. else if (safe_poll(pfd, 1, interval * 1000) > 0) {
  937. if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */
  938. option_mask32 |= OPT_EOF;
  939. continue;
  940. }
  941. if (c == initial_settings.c_cc[VINTR])
  942. break;
  943. c |= 0x20; /* lowercase */
  944. if (c == 'q')
  945. break;
  946. if (c == 'n') {
  947. IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
  948. sort_function[0] = pid_sort;
  949. }
  950. if (c == 'm') {
  951. IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
  952. sort_function[0] = mem_sort;
  953. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  954. sort_function[1] = pcpu_sort;
  955. sort_function[2] = time_sort;
  956. #endif
  957. }
  958. #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
  959. if (c == 'p') {
  960. IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
  961. sort_function[0] = pcpu_sort;
  962. sort_function[1] = mem_sort;
  963. sort_function[2] = time_sort;
  964. }
  965. if (c == 't') {
  966. IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
  967. sort_function[0] = time_sort;
  968. sort_function[1] = mem_sort;
  969. sort_function[2] = pcpu_sort;
  970. }
  971. #if ENABLE_FEATURE_TOPMEM
  972. if (c == 's') {
  973. scan_mask = TOPMEM_MASK;
  974. free(prev_hist);
  975. prev_hist = NULL;
  976. prev_hist_count = 0;
  977. sort_field = (sort_field + 1) % NUM_SORT_FIELD;
  978. }
  979. if (c == 'r')
  980. inverted ^= 1;
  981. #endif
  982. #if ENABLE_FEATURE_TOP_SMP_CPU
  983. /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */
  984. if (c == 'c' || c == '1') {
  985. /* User wants to toggle per cpu <> aggregate */
  986. if (smp_cpu_info) {
  987. free(cpu_prev_jif);
  988. free(cpu_jif);
  989. cpu_jif = &cur_jif;
  990. cpu_prev_jif = &prev_jif;
  991. } else {
  992. /* Prepare for xrealloc() */
  993. cpu_jif = cpu_prev_jif = NULL;
  994. }
  995. num_cpus = 0;
  996. smp_cpu_info = !smp_cpu_info;
  997. get_jiffy_counts();
  998. }
  999. #endif
  1000. #endif
  1001. }
  1002. #endif /* FEATURE_USE_TERMIOS */
  1003. } /* end of "while (1)" */
  1004. bb_putchar('\n');
  1005. #if ENABLE_FEATURE_USE_TERMIOS
  1006. reset_term();
  1007. #endif
  1008. return EXIT_SUCCESS;
  1009. }