*
* This is written specifically for the linux /proc/<PID>/stat(m)
* files format.
-
+ *
* This reads the PIDs of all processes and their status and shows
* the status of processes (first ones that fit to screen) at given
* intervals.
* - CPU where Process was last seen running
* (to see effect of sched_setaffinity() etc)
* - CPU Time Split (idle/IO/wait etc) PER CPU
- */
-
-/* Original code Copyrights */
-/*
+ *
* Copyright (c) 1992 Branko Lankester
* Copyright (c) 1992 Roger Binns
* Copyright (C) 1994-1996 Charles L. Blake.
* Copyright (C) 1992-1998 Michael K. Johnson
- * May be distributed under the conditions of the
- * GNU Library General Public License
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
#include "libbb.h"
} top_status_t;
typedef struct jiffy_counts_t {
- unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal;
+ /* Linux 2.4.x has only first four */
+ unsigned long long usr, nic, sys, idle;
+ unsigned long long iowait, irq, softirq, steal;
unsigned long long total;
unsigned long long busy;
} jiffy_counts_t;
cmp_funcp sort_function[SORT_DEPTH];
struct save_hist *prev_hist;
int prev_hist_count;
- jiffy_counts_t jif, prev_jif;
+ jiffy_counts_t cur_jif, prev_jif;
/* int hist_iterations; */
unsigned total_pcpu;
/* unsigned long total_vsz; */
#define sort_function (G.sort_function )
#define prev_hist (G.prev_hist )
#define prev_hist_count (G.prev_hist_count )
-#define jif (G.jif )
+#define cur_jif (G.cur_jif )
#define prev_jif (G.prev_jif )
#define cpu_jif (G.cpu_jif )
#define cpu_prev_jif (G.cpu_prev_jif )
return 0;
}
-/* NOINLINE so that complier doesn't unfold the call
- * causing multiple copies of the arithmatic instrns
- */
static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif)
{
#if !ENABLE_FEATURE_TOP_SMP_CPU
- static const char fmt[] = "cpu %lld %lld %lld %lld %lld %lld %lld %lld";
+ static const char fmt[] = "cpu %llu %llu %llu %llu %llu %llu %llu %llu";
#else
- static const char fmt[] = "cp%*s %lld %lld %lld %lld %lld %lld %lld %lld";
+ static const char fmt[] = "cp%*s %llu %llu %llu %llu %llu %llu %llu %llu";
#endif
int ret;
&p_jif->usr, &p_jif->nic, &p_jif->sys, &p_jif->idle,
&p_jif->iowait, &p_jif->irq, &p_jif->softirq,
&p_jif->steal);
- if (ret > 4) {
+ if (ret >= 4) {
p_jif->total = p_jif->usr + p_jif->nic + p_jif->sys + p_jif->idle
+ p_jif->iowait + p_jif->irq + p_jif->softirq + p_jif->steal;
/* procps 2.x does not count iowait as busy time */
{
FILE* fp = xfopen_for_read("stat");
-#if !ENABLE_FEATURE_TOP_SMP_CPU
- prev_jif = jif;
- if (read_cpu_jiffy(fp, &jif) < 4)
+ /* We need to parse cumulative counts even if SMP CPU display is on,
+ * they are used to calculate per process CPU% */
+ prev_jif = cur_jif;
+ if (read_cpu_jiffy(fp, &cur_jif) < 4)
bb_error_msg_and_die("can't read /proc/stat");
+
+#if !ENABLE_FEATURE_TOP_SMP_CPU
fclose(fp);
return;
#else
- if (!smp_cpu_info) { /* user wants to see cumulative cpu info */
- prev_jif = jif;
- if (read_cpu_jiffy(fp, &jif) < 4)
- bb_error_msg_and_die("can't read /proc/stat");
+ if (!smp_cpu_info) {
fclose(fp);
return;
}
- /* Discard first "cpu ..." line */
- fgets(line_buf, LINE_BUF_SIZE, fp);
-
if (!num_cpus) {
/* First time here. How many CPUs?
* There will be at least 1 /proc/stat line with cpu%d
if (num_cpus == 0) /* /proc/stat with only "cpu ..." line?! */
smp_cpu_info = 0;
- /* TODO: need to cap num_cpus to a reasonable num
- * on massively paralle machines so that we dont
- * swamp the terminal with cpu "only" info
- */
cpu_prev_jif = xzalloc(sizeof(cpu_prev_jif[0]) * num_cpus);
/* Otherwise the first per cpu display shows all 100% idles */
static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p)
{
/*
- * xxx% = (jif.xxx - prev_jif.xxx) / (jif.total - prev_jif.total) * 100%
+ * xxx% = (cur_jif.xxx - prev_jif.xxx) / (cur_jif.total - prev_jif.total) * 100%
*/
unsigned total_diff;
jiffy_counts_t *p_jif, *p_prev_jif;
#if !ENABLE_FEATURE_TOP_SMP_CPU
{
i = 1;
- p_jif = &jif;
+ p_jif = &cur_jif;
p_prev_jif = &prev_jif;
#else
/* Loop thru CPU(s) */
n_cpu_lines = *lines_rem_p;
for (i = 0; i < n_cpu_lines; i++) {
- /* set the real loop end */
p_jif = &cpu_jif[i];
p_prev_jif = &cpu_prev_jif[i];
#endif
total_diff = CALC_TOT_DIFF;
- { /* Need block: CALC_STAT are declarations */
+ { /* Need a block: CALC_STAT are declarations */
CALC_STAT(usr);
CALC_STAT(sys);
CALC_STAT(nic);
/* read load average as a string */
buf[0] = '\0';
- open_read_close("loadavg", buf, sizeof("N.NN N.NN N.NN")-1);
- buf[sizeof("N.NN N.NN N.NN")-1] = '\0';
+ open_read_close("loadavg", buf, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\n';
+ *strchr(buf, '\n') = '\0';
snprintf(scrbuf, scr_width, "Load average: %s", buf);
puts(scrbuf);
(*lines_rem_p)--;
}
pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2);
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
- busy_jifs = jif.busy - prev_jif.busy;
+ busy_jifs = cur_jif.busy - prev_jif.busy;
/* This happens if there were lots of short-lived processes
* between two top updates (e.g. compilation) */
if (total_pcpu < busy_jifs) total_pcpu = busy_jifs;
* CPU% = s->pcpu/sum(s->pcpu) * busy_cpu_ticks/total_cpu_ticks
* (pcpu is delta of sys+user time between samples)
*/
- /* (jif.xxx - prev_jif.xxx) and s->pcpu are
+ /* (cur_jif.xxx - prev_jif.xxx) and s->pcpu are
* in 0..~64000 range (HZ*update_interval).
* we assume that unsigned is at least 32-bit.
*/
pcpu_shift = 6;
- pcpu_scale = (UPSCALE*64*(uint16_t)busy_jifs ? : 1);
- while (pcpu_scale < (1U<<(BITS_PER_INT-2))) {
+ pcpu_scale = (UPSCALE*64 * (uint16_t)busy_jifs ? : 1);
+ while (pcpu_scale < (1U << (BITS_PER_INT-2))) {
pcpu_scale *= 4;
pcpu_shift += 2;
}
- pcpu_scale /= ( (uint16_t)(jif.total-prev_jif.total)*total_pcpu ? : 1);
+ pcpu_scale /= ( (uint16_t)(cur_jif.total - prev_jif.total) * total_pcpu ? : 1);
/* we want (s->pcpu * pcpu_scale) to never overflow */
while (pcpu_scale >= 1024) {
pcpu_scale /= 4;
read_cmdline(line_buf + col, scr_width - col - 1, s->pid, s->comm);
fputs(line_buf, stdout);
/* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
- jif.busy - prev_jif.busy, jif.total - prev_jif.total); */
+ cur_jif.busy - prev_jif.busy, cur_jif.total - prev_jif.total); */
s++;
}
/* printf(" %d", hist_iterations); */
}
#if ENABLE_FEATURE_USE_TERMIOS
-#include <termios.h>
-#include <signal.h>
static void reset_term(void)
{
- tcsetattr(0, TCSANOW, &initial_settings);
+ tcsetattr_stdin_TCSANOW(&initial_settings);
if (ENABLE_FEATURE_CLEAN_UP) {
clearmems();
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
#define topmem ((topmem_status_t*)top)
#if ENABLE_FEATURE_TOPMEM
+
static int topmem_sort(char *a, char *b)
{
int n;
#undef HDR_STR
#undef MIN_WIDTH
}
+
#else
void display_topmem_process_list(int lines_rem, int scr_width);
int topmem_sort(char *a, char *b);
| PSSCAN_UTIME
| PSSCAN_STATE
| PSSCAN_COMM
-#if ENABLE_FEATURE_TOP_SMP_PROCESS
| PSSCAN_CPU
-#endif
| PSSCAN_UIDGID,
TOPMEM_MASK = 0
| PSSCAN_PID
unsigned lines, col;
int lines_rem;
unsigned interval;
- char *sinterval;
- SKIP_FEATURE_TOPMEM(const) unsigned scan_mask = TOP_MASK;
+ char *str_interval, *str_iterations;
+ IF_NOT_FEATURE_TOPMEM(const) unsigned scan_mask = TOP_MASK;
#if ENABLE_FEATURE_USE_TERMIOS
struct termios new_settings;
struct pollfd pfd[1];
#if ENABLE_FEATURE_TOP_SMP_CPU
/*num_cpus = 0;*/
/*smp_cpu_info = 0;*/ /* to start with show aggregate */
- cpu_jif = &jif;
+ cpu_jif = &cur_jif;
cpu_prev_jif = &prev_jif;
#endif
/* all args are options; -n NUM */
- opt_complementary = "-:n+";
- if (getopt32(argv, "d:n:b", &sinterval, &iterations) & OPT_d) {
+ opt_complementary = "-";
+ col = getopt32(argv, "d:n:b", &str_interval, &str_iterations);
+ if (col & OPT_d) {
+ /* work around for "-d 1" -> "-d -1" done by getopt32 */
+ if (str_interval[0] == '-')
+ str_interval++;
/* Need to limit it to not overflow poll timeout */
- interval = xatou16(sinterval); /* -d */
+ interval = xatou16(str_interval);
+ }
+ if (col & OPT_n) {
+ if (str_iterations[0] == '-')
+ str_iterations++;
+ iterations = xatou(str_iterations);
}
/* change to /proc */
new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL);
bb_signals(BB_FATAL_SIGS, sig_catcher);
- tcsetattr(0, TCSANOW, (void *) &new_settings);
+ tcsetattr_stdin_TCSANOW(&new_settings);
#endif /* FEATURE_USE_TERMIOS */
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
if (c == 'q')
break;
if (c == 'n') {
- USE_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
+ IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
sort_function[0] = pid_sort;
}
if (c == 'm') {
- USE_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
+ IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
sort_function[0] = mem_sort;
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
sort_function[1] = pcpu_sort;
}
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
if (c == 'p') {
- USE_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
+ IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
sort_function[0] = pcpu_sort;
sort_function[1] = mem_sort;
sort_function[2] = time_sort;
}
if (c == 't') {
- USE_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
+ IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
sort_function[0] = time_sort;
sort_function[1] = mem_sort;
sort_function[2] = pcpu_sort;
inverted ^= 1;
#endif
#if ENABLE_FEATURE_TOP_SMP_CPU
- if (c == 'c') { /* procps-2.0.18 uses 'C' */
+ /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */
+ if (c == 'c' || c == '1') {
/* User wants to toggle per cpu <> aggregate */
if (smp_cpu_info) {
free(cpu_prev_jif);
free(cpu_jif);
- cpu_jif = &jif;
+ cpu_jif = &cur_jif;
cpu_prev_jif = &prev_jif;
} else {
/* Prepare for xrealloc() */