aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbb/Config.in7
-rw-r--r--libbb/procps.c55
2 files changed, 60 insertions, 2 deletions
diff --git a/libbb/Config.in b/libbb/Config.in
index 5f4e416dd..f82a2b1ce 100644
--- a/libbb/Config.in
+++ b/libbb/Config.in
@@ -26,6 +26,13 @@ config MD5_SIZE_VS_SPEED
2 3.0 5088
3 (smallest) 5.1 4912
+config FEATURE_FAST_TOP
+ bool "Faster /proc scanning code (+100 bytes)"
+ default n
+ help
+ This option makes top (and ps) ~20% faster (or 20% less CPU hungry),
+ but code size is slightly bigger.
+
config FEATURE_ETC_NETWORKS
bool "Support for /etc/networks"
default n
diff --git a/libbb/procps.c b/libbb/procps.c
index 1e2495a5a..879cc105a 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -107,6 +107,28 @@ void free_procps_scan(procps_status_t* sp)
free(sp);
}
+#if ENABLE_FEATURE_FAST_TOP
+/* We cut a lot of corners here for speed */
+static unsigned long fast_strtoul_10(char *str, char **endptr)
+{
+ char c;
+ unsigned long n = *str - '0';
+
+ while ((c = *++str) != ' ')
+ n = n*10 + (c - '0');
+
+ *endptr = str + 1; /* We skip trailing space! */
+ return n;
+}
+static char *skip_fields(char *str, int count)
+{
+ do {
+ str = skip_non_whitespace(str); str++;
+ } while (--count);
+ return str;
+}
+#endif
+
void BUG_comm_size(void);
procps_status_t* procps_scan(procps_status_t* sp, int flags)
{
@@ -160,7 +182,9 @@ procps_status_t* procps_scan(procps_status_t* sp, int flags)
if (flags & PSSCAN_STAT) {
char *cp;
+#if !ENABLE_FEATURE_FAST_TOP
unsigned long vsz, rss;
+#endif
int tty;
/* see proc(5) for some details on this */
@@ -175,6 +199,8 @@ procps_status_t* procps_scan(procps_status_t* sp, int flags)
if (sizeof(sp->comm) < 16)
BUG_comm_size();
sscanf(buf, "%*s (%15c", sp->comm);
+
+#if !ENABLE_FEATURE_FAST_TOP
n = sscanf(cp+2,
"%c %u " /* state, ppid */
"%u %u %d %*s " /* pgid, sid, tty, tpgid */
@@ -197,6 +223,8 @@ procps_status_t* procps_scan(procps_status_t* sp, int flags)
&rss);
if (n != 10)
break;
+ sp->vsz = vsz >> 10; /* vsize is in bytes and we want kb */
+ sp->rss = rss >> 10;
sp->tty_str[0] = '?';
/* sp->tty_str[1] = '\0'; - done by memset */
@@ -204,6 +232,31 @@ procps_status_t* procps_scan(procps_status_t* sp, int flags)
snprintf(sp->tty_str, sizeof(sp->tty_str), "%u,%u",
(tty >> 8) & 0xfff, /* major */
(tty & 0xff) | ((tty >> 12) & 0xfff00));
+#else
+/* This costs ~100 bytes more but makes top faster by 20%
+ * If you run 10000 processes, this may be important for you */
+ cp += 2;
+ sp->state[0] = *cp++; cp++;
+ sp->ppid = fast_strtoul_10(cp, &cp);
+ sp->pgid = fast_strtoul_10(cp, &cp);
+ sp->sid = fast_strtoul_10(cp, &cp);
+ sp->tty_str[0] = '?';
+ /* sp->tty_str[1] = '\0'; - done by memset */
+ tty = fast_strtoul_10(cp, &cp);
+ if (tty) /* tty field of "0" means "no tty" */
+ snprintf(sp->tty_str, sizeof(sp->tty_str), "%u,%u",
+ (tty >> 8) & 0xfff, /* major */
+ (tty & 0xff) | ((tty >> 12) & 0xfff00));
+ cp = skip_fields(cp, 6); /* tpgid, flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
+ sp->utime = fast_strtoul_10(cp, &cp);
+ sp->stime = fast_strtoul_10(cp, &cp);
+ cp = skip_fields(cp, 3); /* cutime, cstime, priority */
+ tasknice = fast_strtoul_10(cp, &cp);
+ cp = skip_fields(cp, 3); /* timeout, it_real_value, start_time */
+ sp->vsz = fast_strtoul_10(cp, &cp) >> 10; /* vsize is in bytes and we want kb */
+ sp->rss = fast_strtoul_10(cp, &cp) >> 10;
+#endif
+
if (sp->vsz == 0 && sp->state[0] != 'Z')
sp->state[1] = 'W';
else
@@ -215,8 +268,6 @@ procps_status_t* procps_scan(procps_status_t* sp, int flags)
else
sp->state[2] = ' ';
- sp->vsz = vsz >> 10; /* vsize is in bytes and we want kb */
- sp->rss = rss >> 10;
}
if (flags & PSSCAN_CMD) {