#include #include #include #include typedef struct Proc Proc; struct Proc { char pid[32]; char name[32]; char user[32]; long cpri; long bpri; long promil; long usr; long sys; long mem; long pusr; long psys; long pmem; }; enum { Mcpu, Mmem, Muser, Mprio, Mexit, }; char *menustr[] = { "cpu", "mem", "user", "prio", "exit", nil }; Menu menu = { menustr, nil, -1 }; int (*cmp)(void *, void *); Image *normal; Image *title; int procallo; int nproc, sleeptime = 5000; int sort = Mcpu; Proc *procs; void updater(int fd); void usage(void) { fprint(2, "usage: %s [-f font]\n", argv0); exits("usage"); } int cpucmp(void *aptr, void *bptr) { Proc *a, *b; a = aptr; b = bptr; return b->promil - a->promil; } int memcmpr(void *aptr, void *bptr) { Proc *a, *b; a = aptr; b = bptr; return b->mem - a->mem; } int usercmp(void *aptr, void *bptr) { Proc *a, *b; a = aptr; b = bptr; return strcmp(a->user, b->user); } int priocmp(void *aptr, void *bptr) { Proc *a, *b; a = aptr; b = bptr; return b->cpri - a->cpri; } void main(int argc, char **argv) { Event e; char path[64]; char *font = nil; int kupd, k, p[2], pid, fd; ARGBEGIN{ case 'f': font = EARGF(usage()); break; case 'T': sleeptime = atoi(EARGF(usage())); if(sleeptime <= 0) sysfatal("bad sleep time: %d\n", sleeptime); break; default: usage(); }ARGEND if(font == nil) font = getenv("font"); if(initdraw(nil, font, "top") == -1) sysfatal("initdraw"); normal = allocimagemix(display, DPalebluegreen, DWhite); title = allocimagemix(display, DPalegreyblue, DWhite); if(normal == nil || title == nil) sysfatal("allocimagemix"); pipe(p); pid = rfork(RFPROC|RFMEM); if(!pid) updater(p[0]); cmp = cpucmp; einit(Ekeyboard|Emouse); kupd = estart(0, p[1], 1); eresized(0); for(;;) switch(k = event(&e)){ default: if(k == kupd){ eresized(0); write(p[1], &k, 1); /* release */ } break; case Ekeyboard: switch(e.kbdc){ default: break; case 0x7f: case 'q': goto casequit; } break; case Emouse: if(e.mouse.buttons & 4) switch(emenuhit(3, &e.mouse, &menu)){ default: break; case Mcpu: cmp = cpucmp; break; case Mmem: cmp = memcmpr; break; case Muser: cmp = usercmp; break; case Mprio: cmp = priocmp; break; case Mexit: casequit: snprint(path, sizeof path, "/proc/%d/note", pid); fd = open(path, OWRITE); write(fd, "die", 3); close(fd); exits(0); } } } long msec(void) { vlong ms; ms = nsec(); ms /= 1000000LL; return (long)ms; } void updater(int syncfd) { static char buf[256]; long prev, now, elaps; prev = msec(); for(;;){ int fd, proci; long i, j, n, ndir; Dir *dir; fd = open("/proc", OREAD); ndir = dirreadall(fd, &dir); close(fd); chdir("/proc"); if(procallo < ndir){ procallo = ndir; /* * allocate for worst case: all old processes died and as many * new ones were created */ procs = realloc(procs, 2 * sizeof(Proc) * procallo); } now = msec(); elaps = now - prev; if(elaps == 0) elaps = 1; proci = 0; for(i = 0; i < nproc; i++) *procs[i].name = 0; for(i = 0; i < ndir; i++){ char *tok[12]; if(*dir[i].name < '0' || *dir[i].name > '9') continue; chdir(dir[i].name); fd = open("status", OREAD); if(fd == -1) continue; n = read(fd, buf, sizeof buf - 1); close(fd); chdir(".."); buf[n] = 0; tokenize(buf, tok, nelem(tok)); for(j = 0; j < nproc; j++) { if(!strcmp(procs[j].pid, dir[i].name)){ long dif; strncpy(procs[j].user, tok[1], 31); procs[j].user[31] = '\0'; procs[j].pusr = procs[j].usr; procs[j].psys = procs[j].sys; procs[j].pmem = procs[j].mem; procs[j].usr = atol(tok[3]) + atol(tok[6]); procs[j].sys = atol(tok[4]) + atol(tok[7]); procs[j].mem = atol(tok[9]); procs[j].bpri = atol(tok[10]); procs[j].cpri = atol(tok[11]); strncpy(procs[j].name, tok[0], 32); dif = procs[j].usr + procs[j].sys; dif -= procs[j].pusr + procs[j].psys; procs[j].promil = (dif * 1000) / elaps; break; } } if(j == nproc){ strncpy(procs[nproc].pid, dir[i].name, 32); strncpy(procs[nproc].name, tok[0], 32); strncpy(procs[j].user, tok[1], 31); procs[j].user[31] = '\0'; procs[nproc].promil = 0; procs[nproc].usr = atol(tok[3]) + atol(tok[6]); procs[nproc].sys = atol(tok[4]) + atol(tok[7]); procs[nproc].mem = atol(tok[9]); procs[nproc].pusr = atol(tok[3]) + atol(tok[6]); procs[nproc].psys = atol(tok[4]) + atol(tok[7]); procs[nproc].pmem = atol(tok[9]); procs[nproc].bpri = atol(tok[10]); procs[nproc].cpri = atol(tok[11]); nproc++; } proci++; } j = 0; for(i = 0; i < nproc; i++) if(*procs[i].name != 0) memmove(&procs[j++], &procs[i], sizeof procs[0]); nproc = j; qsort(procs, nproc, sizeof(Proc), cmp); nproc = proci; free(dir); write(syncfd, buf, 1); read(syncfd, buf, 1); prev = now; sleep(sleeptime); } } void eresized(int new) { Point p, dp; int i, wid, namewid, userwid, memwid, difwid, priwid; long t; char str[256]; Image *bnc; if(new) if(getwindow(display, Refmesg) == -1) sysfatal("can't reattach window"); priwid = namewid = userwid = memwid = difwid = 0; p = screen->r.min; for(i = 0; i < nproc; i++){ wid = stringwidth(font, procs[i].name); if(wid > namewid) namewid = wid; wid = stringwidth(font, procs[i].user); if(wid > userwid) userwid = wid; t = procs[i].promil; snprint(str, sizeof str, "%ld.%01ld%%", t / 10, t % 10); wid = stringwidth(font, str); if(wid > difwid) difwid = wid; t = procs[i].mem; snprint(str, sizeof str, "%ld.%01ldM", t / 1000, (t % 1000) / 100); wid = stringwidth(font, str); if(wid > memwid) memwid = wid; t = procs[i].cpri; snprint(str, sizeof str, "%ld", t); wid = stringwidth(font, str); if(wid > priwid) priwid = wid; } wid = stringwidth(font, "prio"); if(priwid < wid) priwid = wid; priwid += 10; namewid += 10; userwid += 10; memwid += 10; difwid += 10; bnc = allocimage(display, Rect(0,0, Dx(screen->r), font->height), screen->chan, 0, DOpaque); dp = screen->r.min; p = bnc->r.min; p.x += 10; draw(bnc, bnc->r, title, nil, ZP); string(bnc, p, display->black, ZP, font, "name"); p.x += namewid; string(bnc, p, display->black, ZP, font, "user"); p.x += userwid; wid = stringwidth(font, "%cpu"); p.x += difwid - wid; string(bnc, p, display->black, ZP, font, "%cpu"); p.x += wid; wid = stringwidth(font, "mem"); p.x += memwid - wid; string(bnc, p, display->black, ZP, font, "mem"); p.x += wid; wid = stringwidth(font, "prio"); p.x += priwid - wid; string(bnc, p, display->black, ZP, font, "prio"); p.x += wid; border(bnc, bnc->r, 1, display->black, ZP); draw(screen, Rpt(dp, addpt(dp, Pt(Dx(bnc->r), font->height))), bnc, nil, ZP); dp.y += Dy(bnc->r) + 2; for(i = 0; dp.y < screen->r.max.y && i < nproc; i++){ p = bnc->r.min; p.x += 10; draw(bnc, bnc->r, normal, nil, ZP); string(bnc, p, display->black, ZP, font, procs[i].name); p.x += namewid; string(bnc, p, display->black, ZP, font, procs[i].user); p.x += userwid; t = procs[i].promil; snprint(str, sizeof str, "%ld.%01ld%%", t / 10, t % 10); wid = stringwidth(font, str); p.x += difwid - wid; string(bnc, p, display->black, ZP, font, str); p.x += wid; t = procs[i].mem; snprint(str, sizeof str, "%ld.%01ldM", t / 1000, (t % 1000) / 100); wid = stringwidth(font, str); p.x += memwid - wid; string(bnc, p, display->black, ZP, font, str); p.x += wid; t = procs[i].cpri; snprint(str, sizeof str, "%ld", t); wid = stringwidth(font, str); p.x += priwid - wid; string(bnc, p, display->black, ZP, font, str); p.x += wid; border(bnc, bnc->r, 1, display->black, ZP); draw(screen, Rpt(dp, addpt(dp, Pt(Dx(bnc->r), font->height))), bnc, nil, ZP); dp.y += Dy(bnc->r) + 2; } if(dp.y < screen->r.max.y) draw(screen, Rpt(dp, screen->r.max), display->white, nil, ZP); freeimage(bnc); }