#include #include #include #include #include typedef struct Win Win; struct Win { int n; int dirty; char *label; Rectangle r; }; Reprog *exclude = nil; Win *win; int nwin; int mwin; int onwin; int rows, cols; Font *font; Image *lightblue; enum { PAD = 3, MARGIN = 5 }; typedef struct Process Process; struct Process { char *name; int pid; int updated; Qid qid; unsigned int lastdelta; unsigned int acc; unsigned int mem; }; int nproc = 0; Process **procs = nil; int mypid; Process * newproc(char *name,int pid,Qid *qid) { Process *n = malloc(sizeof *n); if(n == nil) exits("out of memory :-("); n->name = strdup(name); n->pid = pid; n->lastdelta = n->acc = 0; n->qid = *qid; n->updated = 0; return n; } int sameqid(Qid *a,Qid *b) { return a->path == b->path && a->vers == b->vers && a->type == b->type; } void update(int pid,char *name,Qid *qid,int acc,int mem) { int i; Process *this = nil; for(i = 0; i < nproc; i++) { if(sameqid(&procs[i]->qid,qid)) { this = procs[i]; break; } } if(this == nil) { ++nproc; procs = realloc(procs,sizeof(Process *)*nproc); this = newproc(name,pid,qid); procs[nproc-1] = this; this->acc = acc; } this->lastdelta = acc - this->acc; this->acc = acc; this->updated = 1; this->mem = mem; } void freeprocs(void) { for(int i=0;iname); fd = open(buf,OREAD); if(fd < 0) return; if((len = read(fd,buf,sizeof(buf) -1)) <= 0) { close(fd); return; } buf[len] = 0; tokenize(buf,fields,10); //print("%s - %d\n",fields[0],atoi(fields[3])+atoi(fields[4])); update(atoi(d->name),fields[0],&d->qid,atoi(fields[3])+atoi(fields[4]),atoi(fields[9])); close(fd); return; } void dopids(int procfd) { Dir *d; int ndirs; int i; ndirs = dirreadall(procfd,&d); if(d == nil) exits("Shit.."); for(i = 0; i < ndirs ; i++) { /*the trace file and our own process is of no interrest.*/ if(strcmp(d[i].name,"trace") && atoi(d[i].name) != mypid) dopid(&d[i]); } free(d); } int proccmp(void *_a, void *_b) { Process **a = (Process **)_a; Process **b = (Process **)_b; return (*b)->lastdelta - (*a)->lastdelta; } void* erealloc(void *v, ulong n) { v = realloc(v, n); if(v == nil) sysfatal("out of memory reallocating %lud", n); return v; } void* emalloc(ulong n) { void *v; v = malloc(n); if(v == nil) sysfatal("out of memory allocating %lud", n); memset(v, 0, n); return v; } char* estrdup(char *s) { int l; char *t; if (s == nil) return nil; l = strlen(s)+1; t = emalloc(l); memcpy(t, s, l); return t; } int refreshwin(void) { char label[128]; int i, nw; nw=0; for(i = 0; i < nproc; i++) { if(procs[i]->updated && procs[i]->lastdelta > 80){ procs[i]->updated = 0; if(exclude != nil && regexec(exclude,label,nil,0)) continue; if(nw < nwin && win[nw].n == i){ nw++; continue; } if(nw < nwin){ free(win[nw].label); win[nw].label = nil; } if(nw >= mwin){ mwin += 8; win = erealloc(win, mwin*sizeof(win[0])); } win[nw].n = i; win[nw].label = smprint("%d %s %d",procs[i]->pid,procs[i]->name,procs[i]->lastdelta); win[nw].dirty = 1; win[nw].r = Rect(0,0,0,0); nw++; } } while(nwin > nw) free(win[--nwin].label); nwin = nw; return nw; } void drawnowin(int i) { Rectangle r; r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height); r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows), MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min); draw(screen, insetrect(r, -1), lightblue, nil, ZP); } void drawwin(int i) { draw(screen, win[i].r, lightblue, nil, ZP); _string(screen, addpt(win[i].r.min, Pt(2,0)), display->black, ZP, font, win[i].label, nil, strlen(win[i].label), win[i].r, nil, ZP, SoverD); border(screen, win[i].r, 1, display->black, ZP); win[i].dirty = 0; } int geometry(void) { int i, ncols, z; Rectangle r; z = 0; rows = (Dy(screen->r)-2*MARGIN+PAD)/(font->height+PAD); if(rows*cols < nwin || rows*cols >= nwin*2){ ncols = nwin <= 0 ? 1 : (nwin+rows-1)/rows; if(ncols != cols){ cols = ncols; z = 1; } } r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height); for(i=0; ir.min); return z; } void redraw(Image *screen, int all) { int i; if ( all == 2 ) { draw(screen, screen->r, lightblue, nil, ZP); return; } all |= geometry(); if(all) draw(screen, screen->r, lightblue, nil, ZP); for(i=0; ipid); char *buttons[] = { win[i].label, "-------", "yes", "no", 0 }; Menu menu = { buttons }; if(emenuhit(3, &m, &menu) != 2) return; if(fd=open(buf, OWRITE) < 0){ fprint(2, "can't open %s\n", buf); return; } fprint(fd, "kill\n"); close(fd); } void usage(void) { fprint(2, "usage: wintop [-e exclude] [-f font] [-d delay]\n"); exits("usage"); } void main(int argc, char **argv) { char *fontname; int delay, Etimer, procfd; Event e; delay=1; fontname = "/lib/font/bit/lucidasans/unicode.8.font"; ARGBEGIN{ case 'f': fontname = EARGF(usage()); break; case 'e': exclude = regcomp(EARGF(usage())); if(exclude == nil) sysfatal("Bad regexp"); break; case 'd': delay=atoi(ARGF()); break; default: usage(); }ARGEND if(argc) usage(); initdraw(0, 0, "wintop"); lightblue = allocimagemix(display, DPalebluegreen, DWhite); if(lightblue == nil) sysfatal("allocimagemix: %r"); if((font = openfont(display, fontname)) == nil) sysfatal("font '%s' not found", fontname); redraw(screen, 2); einit(Emouse|Ekeyboard); Etimer = etimer(0, 5000); for(;;){ switch(eread(Emouse|Ekeyboard|Etimer, &e)){ case Ekeyboard: if(e.kbdc==0x7F || e.kbdc=='q') exits(0); break; case Emouse: if(e.mouse.buttons) click(e.mouse); break; default: /* Etimer */ procfd = open("/proc/",OREAD); if(procfd < 0) exits("Couldn't open /proc/"); dopids(procfd); close(procfd); qsort(procs,nproc,sizeof(Process *),proccmp); refreshwin(); redraw(screen, 0); break; } sleep(delay); } }