aboutsummaryrefslogtreecommitdiff
path: root/toys/posix/ps.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2016-01-27 20:27:33 -0600
committerRob Landley <rob@landley.net>2016-01-27 20:27:33 -0600
commitc35aabc1af80da053136acf8feb53947d219b87c (patch)
tree0db8a4aa4c52c76a30e0963e32008ef71f344f06 /toys/posix/ps.c
parent5f238a3b5c3de7d9500cc55f33969fe516e1cb86 (diff)
downloadtoybox-c35aabc1af80da053136acf8feb53947d219b87c.tar.gz
Add cpu line to top, and fix a bug initializing upticks slot.
Diffstat (limited to 'toys/posix/ps.c')
-rw-r--r--toys/posix/ps.c90
1 files changed, 69 insertions, 21 deletions
diff --git a/toys/posix/ps.c b/toys/posix/ps.c
index 0dee6bd1..3a5c9410 100644
--- a/toys/posix/ps.c
+++ b/toys/posix/ps.c
@@ -40,6 +40,7 @@
* TODO: thread support /proc/$d/task/%d/stat (and -o stat has "l")
* TODO: iotop: Window size change: respond immediately. Why not padding
* at right edge? (Not adjusting to screen size at all? Header wraps?)
+ * TODO: top: thread support and SMP
USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*u*U*g*G*wZ[!ol][+Ae]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
// stayroot because iotop needs root to read other process' proc/$$/io
@@ -128,9 +129,6 @@ config TOP
-o Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)
-s Sort by field number (1-X, default 9)
- H toggle threads
- C,1 toggle SMP
-
# Requires CONFIG_IRQ_TIME_ACCOUNTING in the kernel for /proc/$$/io
config IOTOP
bool "iotop"
@@ -234,6 +232,8 @@ GLOBALS(
struct arg_list *p;
struct arg_list *o;
struct arg_list *k;
+
+ long long milistart;
} top;
struct{
char *L;
@@ -642,7 +642,7 @@ static int get_ps(struct dirtree *new)
// systems (or ps | more) we re-fetch uptime as we fetch each /proc line.
sysinfo(&TT.si);
slot[SLOT_uptime] = TT.si.uptime;
- slot[SLOT_upticks] = slot[SLOT_uptime]*TT.ticks - slot[SLOT_rss];
+ slot[SLOT_upticks] = slot[SLOT_uptime]*TT.ticks - slot[SLOT_starttime];
// Do we need to read "statm"?
if (TT.bits&(_PS_VIRT|_PS_RES|_PS_SHR)) {
@@ -1130,14 +1130,15 @@ static void setsort(int pos)
// If we have both, adjust slot[deltas[]] to be relative to previous
// measurement rather than process start. Stomping old.data is fine
// because we free it after displaying.
-static int merge_deltas(long long *oslot, long long *nslot)
+static int merge_deltas(long long *oslot, long long *nslot, int milis)
{
- char deltas[] = {SLOT_utime2, SLOT_iobytes, SLOT_diobytes, SLOT_upticks,
- SLOT_rchar, SLOT_wchar, SLOT_rbytes, SLOT_wbytes, SLOT_swap};
+ char deltas[] = {SLOT_utime2, SLOT_iobytes, SLOT_diobytes, SLOT_rchar,
+ SLOT_wchar, SLOT_rbytes, SLOT_wbytes, SLOT_swap};
int i;
for (i = 0; i<ARRAY_LEN(deltas); i++)
oslot[deltas[i]] = nslot[deltas[i]] - oslot[deltas[i]];
+ oslot[SLOT_upticks] = (milis*TT.ticks)/1000;
return 1;
}
@@ -1153,29 +1154,53 @@ static int header_line(int line, int rev)
return line-1;
}
-static void top_common(int (*filter)(long long *oslot, long long *nslot))
+// Get current time in miliseconds
+static long long militime(void)
{
struct timespec ts;
- long long timeout = 0, now;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ return ts.tv_sec*1000+ts.tv_nsec/1000000;
+}
+
+static void top_common(
+ int (*filter)(long long *oslot, long long *nslot, int milis))
+{
+ long long timeout = 0, now, stats[16];
struct proclist {
struct carveup **tb;
int count;
+ long long whence;
} plist[2], *plold, *plnew, old, new, mix;
- char scratch[16];
+ char scratch[16], *pos, *cpufields[] = {"user", "nice", "sys", "idle",
+ "iow", "irq", "sirq", "host"};
+
unsigned tock = 0;
int i, lines, topoff = 0, done = 0;
TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
*scratch = 0;
memset(plist, 0, sizeof(plist));
+ memset(stats, 0, sizeof(stats));
do {
- struct dirtree *dt = dirtree_read("/proc", get_ps);
+ struct dirtree *dt;
plold = plist+(tock++&1);
plnew = plist+(tock&1);
+ plnew->whence = militime();
+ dt= dirtree_read("/proc", get_ps);
plnew->tb = collate(plnew->count = TT.kcount, dt, ksort);
TT.kcount = 0;
+ if (readfile("/proc/stat", pos = toybuf, sizeof(toybuf))) {
+ long long *st = stats+8*(tock&1);
+
+ // user nice system idle iowait irq softirq host
+ sscanf(pos, "cpu %lld %lld %lld %lld %lld %lld %lld %lld",
+ st, st+1, st+2, st+3, st+4, st+5, st+6, st+7);
+ }
+
// First time, wait a quarter of a second to collect a little delta data.
if (!plold->tb) {
msleep(250);
@@ -1203,7 +1228,7 @@ static void top_common(int (*filter)(long long *oslot, long long *nslot))
if (!old.count || *otb->slot > *ntb->slot) mix.tb[mix.count] = ntb;
else {
// Keep or discard
- if (filter(otb->slot, ntb->slot)) {
+ if (filter(otb->slot, ntb->slot, new.whence-old.whence)) {
mix.tb[mix.count] = otb;
mix.count++;
}
@@ -1216,15 +1241,17 @@ static void top_common(int (*filter)(long long *oslot, long long *nslot))
// We will re-fetch no data before its time. - Mork calling Orson Welles
for (;;) {
- char *pos, *end=end, was, is;
+ char was, is;
qsort(mix.tb, mix.count, sizeof(struct carveup *), (void *)ksort);
lines = TT.height;
if (!(toys.optflags&FLAG_b)) printf("\033[H\033[J");
if (!(toys.optflags&FLAG_q)) {
if (*toys.which->name == 't') {
- long run[6];
struct strawberry alluc;
+ long long ll, up = 0;
+ long run[6];
+ int j;
alluc.which = PS_S;
memset(run, 0, sizeof(run));
@@ -1251,6 +1278,26 @@ static void top_common(int (*filter)(long long *oslot, long long *nslot))
run[4], run[4]-run[5], run[5], run[3]);
lines = header_line(lines, 0);
}
+
+ pos = toybuf;
+ i = sysconf(_SC_NPROCESSORS_CONF);
+ pos += sprintf(pos, "%d%%cpu", i*100);
+ j = 4+(i>10);
+
+ // If a processor goes idle it's powered down and its idle ticks don't
+ // advance, so calculate idle time as potential time - used.
+ if (mix.count) up = mix.tb[0]->slot[SLOT_upticks];
+ if (!up) up = 1;
+ now = up*i;
+ ll = stats[3] = stats[11] = 0;
+ for (i = 0; i<8; i++) ll += stats[i]-stats[i+8];
+ stats[3] = now - llabs(ll);
+
+ for (i = 0; i<8; i++) {
+ ll = (llabs(stats[i]-stats[i+8])*1000)/up;
+ pos += sprintf(pos, "% *lld%%%s", j, (ll+5)/10, cpufields[i]);
+ }
+ lines = header_line(lines, 0);
} else {
struct strawberry *fields;
struct carveup tb;
@@ -1300,10 +1347,9 @@ static void top_common(int (*filter)(long long *oslot, long long *nslot))
}
// Get current time in miliseconds
- clock_gettime(CLOCK_MONOTONIC, &ts);
- now = ts.tv_sec*1000+ts.tv_nsec/1000000;
- if (timeout<=now) timeout += TT.top.d;
- if (timeout<=now) timeout = now+TT.top.d;
+ now = militime();
+ if (timeout<=now) timeout = new.whence+TT.top.d;
+ if (timeout<=now || timeout>now+TT.top.d) timeout = now+TT.top.d;
i = scan_key_getsize(scratch, timeout-now, &TT.width, &TT.height);
if (i==-1 || i==3 || toupper(i)=='Q') {
@@ -1315,7 +1361,7 @@ static void top_common(int (*filter)(long long *oslot, long long *nslot))
// Flush unknown escape sequences.
if (i==27) while (0<scan_key_getsize(scratch, 0, &TT.width, &TT.height));
else if (i==' ') {
- timeout = now;
+ timeout = 0;
break;
} else if (toupper(i)=='R')
((struct strawberry *)TT.kfields)->reverse *= -1;
@@ -1379,9 +1425,10 @@ void top_main(void)
#define FOR_iotop
#include "generated/flags.h"
-static int iotop_filter(long long *oslot, long long *nslot)
+static int iotop_filter(long long *oslot, long long *nslot, int milis)
{
- if (!(toys.optflags&FLAG_a)) merge_deltas(oslot, nslot);
+ if (!(toys.optflags&FLAG_a)) merge_deltas(oslot, nslot, milis);
+ else oslot[SLOT_upticks] = ((militime()-TT.top.milistart)*TT.ticks)/1000;
return !(toys.optflags&FLAG_o)||oslot[SLOT_iobytes+!(toys.optflags&FLAG_A)];
}
@@ -1392,6 +1439,7 @@ void iotop_main(void)
if (toys.optflags&FLAG_K) TT.forcek++;
+ TT.top.milistart = militime();
top_setup(s1 = xmprintf("PID,PR,USER,%sREAD,%sWRITE,SWAP,%sIO,COMM",d,d,d),
s2 = xmprintf("-%sIO,-ETIME,-PID",d));
free(s1);