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
This commit is contained in:
144
procps/top.c
144
procps/top.c
@@ -30,37 +30,76 @@
|
||||
|
||||
#include "busybox.h"
|
||||
|
||||
typedef int (*cmp_t)(procps_status_t *P, procps_status_t *Q);
|
||||
|
||||
static procps_status_t *top; /* Hehe */
|
||||
typedef struct {
|
||||
unsigned long rss;
|
||||
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
|
||||
unsigned long ticks;
|
||||
unsigned pcpu; /* delta of ticks */
|
||||
#endif
|
||||
unsigned pid, ppid;
|
||||
unsigned uid;
|
||||
char state[4];
|
||||
char comm[COMM_LEN];
|
||||
} top_status_t;
|
||||
static top_status_t *top;
|
||||
static int ntop;
|
||||
/* This structure stores some critical information from one frame to
|
||||
the next. Used for finding deltas. */
|
||||
struct save_hist {
|
||||
unsigned long ticks;
|
||||
unsigned pid;
|
||||
};
|
||||
static struct save_hist *prev_hist;
|
||||
static int prev_hist_count;
|
||||
/* static int hist_iterations; */
|
||||
static unsigned total_pcpu;
|
||||
/* static unsigned long total_rss; */
|
||||
|
||||
|
||||
#define OPT_BATCH_MODE (option_mask32 & 0x4)
|
||||
|
||||
#if ENABLE_FEATURE_USE_TERMIOS
|
||||
static int pid_sort(procps_status_t *P, procps_status_t *Q)
|
||||
static int pid_sort(top_status_t *P, top_status_t *Q)
|
||||
{
|
||||
/* Buggy wrt pids with high bit set */
|
||||
/* (linux pids are in [1..2^15-1]) */
|
||||
return (Q->pid - P->pid);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mem_sort(procps_status_t *P, procps_status_t *Q)
|
||||
static int mem_sort(top_status_t *P, top_status_t *Q)
|
||||
{
|
||||
return (int)(Q->rss - P->rss);
|
||||
/* We want to avoid unsigned->signed and truncation errors */
|
||||
if (Q->rss < P->rss) return -1;
|
||||
return Q->rss != P->rss; /* 0 if ==, 1 if > */
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
|
||||
|
||||
typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q);
|
||||
|
||||
#if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
|
||||
|
||||
static cmp_funcp sort_function;
|
||||
|
||||
#else
|
||||
|
||||
enum { SORT_DEPTH = 3 };
|
||||
static cmp_t sort_function[SORT_DEPTH];
|
||||
|
||||
static int pcpu_sort(procps_status_t *P, procps_status_t *Q)
|
||||
static cmp_funcp sort_function[SORT_DEPTH];
|
||||
|
||||
static int pcpu_sort(top_status_t *P, top_status_t *Q)
|
||||
{
|
||||
return (Q->pcpu - P->pcpu);
|
||||
/* Buggy wrt ticks with high bit set */
|
||||
/* Affects only processes for which ticks overflow */
|
||||
return (int)Q->pcpu - (int)P->pcpu;
|
||||
}
|
||||
|
||||
static int time_sort(procps_status_t *P, procps_status_t *Q)
|
||||
static int time_sort(top_status_t *P, top_status_t *Q)
|
||||
{
|
||||
return (int)((Q->stime + Q->utime) - (P->stime + P->utime));
|
||||
/* We want to avoid unsigned->signed and truncation errors */
|
||||
if (Q->ticks < P->ticks) return -1;
|
||||
return Q->ticks != P->ticks; /* 0 if ==, 1 if > */
|
||||
}
|
||||
|
||||
static int mult_lvl_cmp(void* a, void* b) {
|
||||
@@ -74,24 +113,6 @@ static int mult_lvl_cmp(void* a, void* b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This structure stores some critical information from one frame to
|
||||
the next. Mostly used for sorting. */
|
||||
struct save_hist {
|
||||
int ticks;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
/*
|
||||
* Calculates percent cpu usage for each task.
|
||||
*/
|
||||
|
||||
static struct save_hist *prev_hist;
|
||||
static int prev_hist_count;
|
||||
/* static int hist_iterations; */
|
||||
|
||||
|
||||
static unsigned total_pcpu;
|
||||
/* static unsigned long total_rss; */
|
||||
|
||||
typedef struct {
|
||||
unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal;
|
||||
@@ -115,11 +136,12 @@ static void get_jiffy_counts(void)
|
||||
jif.busy = jif.total - jif.idle - jif.iowait;
|
||||
}
|
||||
|
||||
|
||||
static void do_stats(void)
|
||||
{
|
||||
procps_status_t *cur;
|
||||
top_status_t *cur;
|
||||
pid_t pid;
|
||||
int total_time, i, last_i, n;
|
||||
int i, last_i, n;
|
||||
struct save_hist *new_hist;
|
||||
|
||||
get_jiffy_counts();
|
||||
@@ -139,8 +161,7 @@ static void do_stats(void)
|
||||
* and system time
|
||||
*/
|
||||
pid = cur->pid;
|
||||
total_time = cur->stime + cur->utime;
|
||||
new_hist[n].ticks = total_time;
|
||||
new_hist[n].ticks = cur->ticks;
|
||||
new_hist[n].pid = pid;
|
||||
|
||||
/* find matching entry from previous pass */
|
||||
@@ -150,13 +171,13 @@ static void do_stats(void)
|
||||
last_i = i;
|
||||
if (prev_hist_count) do {
|
||||
if (prev_hist[i].pid == pid) {
|
||||
cur->pcpu = total_time - prev_hist[i].ticks;
|
||||
cur->pcpu = cur->ticks - prev_hist[i].ticks;
|
||||
total_pcpu += cur->pcpu;
|
||||
break;
|
||||
}
|
||||
i = (i+1) % prev_hist_count;
|
||||
/* hist_iterations++; */
|
||||
} while (i != last_i);
|
||||
total_pcpu += cur->pcpu;
|
||||
/* total_rss += cur->rss; */
|
||||
}
|
||||
|
||||
@@ -167,10 +188,9 @@ static void do_stats(void)
|
||||
prev_hist = new_hist;
|
||||
prev_hist_count = ntop;
|
||||
}
|
||||
#else
|
||||
static cmp_t sort_function;
|
||||
#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
|
||||
|
||||
|
||||
/* display generic info (meminfo / loadavg) */
|
||||
static unsigned long display_generic(int scr_width)
|
||||
{
|
||||
@@ -265,7 +285,7 @@ static void display_status(int count, int scr_width)
|
||||
bits_per_int = sizeof(int)*8
|
||||
};
|
||||
|
||||
procps_status_t *s = top;
|
||||
top_status_t *s = top;
|
||||
char rss_str_buf[8];
|
||||
unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */
|
||||
unsigned pmem_shift, pmem_scale;
|
||||
@@ -333,14 +353,19 @@ static void display_status(int count, int scr_width)
|
||||
sprintf(rss_str_buf, "%6ldM", s->rss/1024);
|
||||
else
|
||||
sprintf(rss_str_buf, "%7ld", s->rss);
|
||||
USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10);)
|
||||
col -= printf("\n%5u %-8s %s %s%6u%3u.%c" \
|
||||
USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c") " ",
|
||||
(unsigned)s->pid, s->user, s->state, rss_str_buf, (unsigned)s->ppid,
|
||||
USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(
|
||||
pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10);
|
||||
)
|
||||
col -= printf("\n%5u %-8s %s "
|
||||
"%s%6u"
|
||||
USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c")
|
||||
"%3u.%c ",
|
||||
s->pid, get_cached_username(s->uid), s->state,
|
||||
rss_str_buf, s->ppid,
|
||||
USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,)
|
||||
pmem.quot, '0'+pmem.rem);
|
||||
if (col > 0)
|
||||
printf("%.*s", col, s->short_cmd);
|
||||
printf("%.*s", col, s->comm);
|
||||
/* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
|
||||
jif.busy - prev_jif.busy, jif.total - prev_jif.total); */
|
||||
s++;
|
||||
@@ -350,18 +375,20 @@ static void display_status(int count, int scr_width)
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
static void clearmems(void)
|
||||
{
|
||||
clear_username_cache();
|
||||
free(top);
|
||||
top = 0;
|
||||
ntop = 0;
|
||||
}
|
||||
|
||||
|
||||
#if ENABLE_FEATURE_USE_TERMIOS
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
static struct termios initial_settings;
|
||||
|
||||
static void reset_term(void)
|
||||
@@ -427,7 +454,7 @@ int top_main(int argc, char **argv)
|
||||
#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
|
||||
|
||||
while (1) {
|
||||
procps_status_t *p;
|
||||
procps_status_t *p = NULL;
|
||||
|
||||
/* Default to 25 lines - 5 lines for status */
|
||||
lines = 24 - 3;
|
||||
@@ -442,11 +469,26 @@ int top_main(int argc, char **argv)
|
||||
#endif /* FEATURE_USE_TERMIOS */
|
||||
|
||||
/* read process IDs & status for all the processes */
|
||||
while ((p = procps_scan(0)) != 0) {
|
||||
while ((p = procps_scan(p, 0
|
||||
| PSSCAN_PID
|
||||
| PSSCAN_PPID
|
||||
| PSSCAN_RSS
|
||||
| PSSCAN_STIME
|
||||
| PSSCAN_UTIME
|
||||
| PSSCAN_STATE
|
||||
| PSSCAN_COMM
|
||||
| PSSCAN_SID
|
||||
| PSSCAN_UIDGID
|
||||
))) {
|
||||
int n = ntop;
|
||||
|
||||
top = xrealloc(top, (++ntop)*sizeof(procps_status_t));
|
||||
memcpy(top + n, p, sizeof(procps_status_t));
|
||||
top = xrealloc(top, (++ntop)*sizeof(top_status_t));
|
||||
top[n].pid = p->pid;
|
||||
top[n].ppid = p->ppid;
|
||||
top[n].rss = p->rss;
|
||||
top[n].ticks = p->stime + p->utime;
|
||||
top[n].uid = p->uid;
|
||||
strcpy(top[n].state, p->state);
|
||||
strcpy(top[n].comm, p->comm);
|
||||
}
|
||||
if (ntop == 0) {
|
||||
bb_error_msg_and_die("can't find process info in /proc");
|
||||
@@ -459,9 +501,9 @@ int top_main(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
do_stats();
|
||||
qsort(top, ntop, sizeof(procps_status_t), (void*)mult_lvl_cmp);
|
||||
qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
|
||||
#else
|
||||
qsort(top, ntop, sizeof(procps_status_t), (void*)sort_function);
|
||||
qsort(top, ntop, sizeof(top_status_t), (void*)sort_function);
|
||||
#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
|
||||
count = lines;
|
||||
if (OPT_BATCH_MODE || count > ntop) {
|
||||
|
Reference in New Issue
Block a user