#include <u.h>#include <libc.h>#include <ctype.h>#include <draw.h>#include <event.h>#include <keyboard.h> #define MAXNUM 10 /* maximum number of numbers on data line */ typedef struct Graph Graph;typedef struct Machine Machine; struct Graph{ int colindex; Rectangle r; int *data; int ndata; char *label; void (*newvalue)(Machine*, uvlong*, uvlong*, int); void (*update)(Graph*, uvlong, uvlong); Machine *mach; int overflow; Image *overtmp;}; enum{ /* /dev/swap */ Mem = 0, Maxmem, Swap, Maxswap, Reclaim, Maxreclaim, Kern, Maxkern, Draw, Maxdraw, /* /dev/sysstats */ Procno = 0, Context, Interrupt, Syscall, Fault, TLBfault, TLBpurge, Load, Idle, InIntr, /* /net/ether0/stats */ In = 0, Link, Out, Err0,}; struct Machine{ char *name; char *shortname; int remote; int statsfd; int swapfd; int etherfd; int ifstatsfd; int batteryfd; int bitsybatfd; int tempfd; int disable; uvlong devswap[10]; uvlong devsysstat[10]; uvlong prevsysstat[10]; int nproc; int lgproc; uvlong netetherstats[8]; uvlong prevetherstats[8]; uvlong batterystats[2]; uvlong netetherifstats[2]; uvlong temp[10]; /* big enough to hold /dev/sysstat even with many processors */ char buf[8*1024]; char *bufp; char *ebufp;}; enum{ Mainproc, Inputproc, NPROC,}; enum{ Ncolor = 6, Ysqueeze = 2, /* vertical squeezing of label text */ Labspace = 2, /* room around label */ Dot = 2, /* height of dot */ Opwid = 5, /* strlen("add ") or strlen("drop ") */ Nlab = 3, /* max number of labels on y axis */ Lablen = 16, /* max length of label */ Lx = 4, /* label tick length */}; enum Menu2{ Mbattery, Mcontext, Mether, Methererr, Metherin, Metherout, Mfault, Midle, Minintr, Mintr, Mload, Mmem, Mswap, Mreclaim, Mkern, Mdraw, Msyscall, Mtlbmiss, Mtlbpurge, Msignal, Mtemp, Nmenu2,}; char *menu2str[Nmenu2+1] = { "add battery ", "add context ", "add ether ", "add ethererr", "add etherin ", "add etherout", "add fault ", "add idle ", "add inintr ", "add intr ", "add load ", "add mem ", "add swap ", "add reclaim ", "add kern ", "add draw ", "add syscall ", "add tlbmiss ", "add tlbpurge", "add 802.11b ", "add temp ", nil,}; void contextval(Machine*, uvlong*, uvlong*, int), etherval(Machine*, uvlong*, uvlong*, int), ethererrval(Machine*, uvlong*, uvlong*, int), etherinval(Machine*, uvlong*, uvlong*, int), etheroutval(Machine*, uvlong*, uvlong*, int), faultval(Machine*, uvlong*, uvlong*, int), intrval(Machine*, uvlong*, uvlong*, int), inintrval(Machine*, uvlong*, uvlong*, int), loadval(Machine*, uvlong*, uvlong*, int), idleval(Machine*, uvlong*, uvlong*, int), memval(Machine*, uvlong*, uvlong*, int), swapval(Machine*, uvlong*, uvlong*, int), reclaimval(Machine*, uvlong*, uvlong*, int), kernval(Machine*, uvlong*, uvlong*, int), drawval(Machine*, uvlong*, uvlong*, int), syscallval(Machine*, uvlong*, uvlong*, int), tlbmissval(Machine*, uvlong*, uvlong*, int), tlbpurgeval(Machine*, uvlong*, uvlong*, int), batteryval(Machine*, uvlong*, uvlong*, int), signalval(Machine*, uvlong*, uvlong*, int), tempval(Machine*, uvlong*, uvlong*, int); Menu menu2 = {menu2str, nil};int present[Nmenu2];void (*newvaluefn[Nmenu2])(Machine*, uvlong*, uvlong*, int init) = { batteryval, contextval, etherval, ethererrval, etherinval, etheroutval, faultval, idleval, inintrval, intrval, loadval, memval, swapval, reclaimval, kernval, drawval, syscallval, tlbmissval, tlbpurgeval, signalval, tempval,}; Image *cols[Ncolor][3];Graph *graph;Machine *mach;char *mysysname;char argchars[] = "8bcdeEfiIkmlnprstwz";int pids[NPROC];int parity; /* toggled to avoid patterns in textured background */int nmach;int ngraph; /* totaly number is ngraph*nmach */double scale = 1.0;int logscale = 0;int ylabels = 0;int sleeptime = 1000; char *procnames[NPROC] = {"main", "input"}; voidkillall(char *s){ int i, pid; pid = getpid(); for(i=0; i<NPROC; i++) if(pids[i] && pids[i]!=pid) postnote(PNPROC, pids[i], "kill"); exits(s);} void*emalloc(ulong sz){ void *v; v = malloc(sz); if(v == nil) { fprint(2, "stats: out of memory allocating %ld: %r\n", sz); killall("mem"); } memset(v, 0, sz); return v;} void*erealloc(void *v, ulong sz){ v = realloc(v, sz); if(v == nil) { fprint(2, "stats: out of memory reallocating %ld: %r\n", sz); killall("mem"); } return v;} char*estrdup(char *s){ char *t; if((t = strdup(s)) == nil) { fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s); killall("mem"); } return t;} voidmkcol(int i, int c0, int c1, int c2){ cols[i][0] = allocimagemix(display, c0, DBlack); cols[i][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c1); cols[i][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c2);} voidcolinit(void){ /* Peach */ mkcol(0, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Aqua */ mkcol(1, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Yellow */ mkcol(2, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Green */ mkcol(3, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Blue */ mkcol(4, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Grey */ cols[5][0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEEEEEEFF); cols[5][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF); cols[5][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x888888FF);} intloadbuf(Machine *m, int *fd){ int n; if(*fd < 0) return 0; seek(*fd, 0, 0); n = read(*fd, m->buf, sizeof m->buf-1); if(n <= 0){ close(*fd); *fd = -1; return 0; } m->bufp = m->buf; m->ebufp = m->buf+n; m->buf[n] = 0; return 1;} voidlabel(Point p, int dy, char *text){ char *s; Rune r[2]; int w, maxw, maxy; p.x += Labspace; maxy = p.y+dy; maxw = 0; r[1] = '\0'; for(s=text; *s; ){ if(p.y+font->height-Ysqueeze > maxy) break; w = chartorune(r, s); s += w; w = runestringwidth(font, r); if(w > maxw) maxw = w; runestring(screen, p, display->black, ZP, font, r); p.y += font->height-Ysqueeze; }} Pointparitypt(int x){ return Pt(x+parity, 0);} Pointdatapoint(Graph *g, int x, uvlong v, uvlong vmax){ Point p; double y; p.x = x; y = ((double)v)/(vmax*scale); if(logscale){ /* * Arrange scale to cover a factor of 1000. * vmax corresponds to the 100 mark. * 10*vmax is the top of the scale. */ if(y <= 0.) y = 0; else{ y = log10(y); /* 1 now corresponds to the top; -2 to the bottom; rescale */ y = (y+2.)/3.; } } if(y >= 1.) y = 1; if(y <= 0.) y = 0; p.y = g->r.max.y - Dy(g->r)*y - Dot; if(p.y < g->r.min.y) p.y = g->r.min.y; if(p.y > g->r.max.y-Dot) p.y = g->r.max.y-Dot; return p;} voiddrawdatum(Graph *g, int x, uvlong prev, uvlong v, uvlong vmax){ int c; Point p, q; c = g->colindex; p = datapoint(g, x, v, vmax); q = datapoint(g, x, prev, vmax); if(p.y < q.y){ draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x)); draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP); draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP); }else{ draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x)); draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP); draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP); } } voidredraw(Graph *g, uvlong vmax){ int i, c; c = g->colindex; draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x)); for(i=1; i<Dx(g->r); i++) drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax); drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax); g->overflow = 0;} voidupdate1(Graph *g, uvlong v, uvlong vmax){ char buf[48]; int overflow; if(g->overflow && g->overtmp!=nil) draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min); draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y)); drawdatum(g, g->r.max.x-1, g->data[0], v, vmax); memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0])); g->data[0] = v; g->overflow = 0; if(logscale) overflow = (v>10*vmax*scale); else overflow = (v>vmax*scale); if(overflow && g->overtmp!=nil){ g->overflow = 1; draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min); sprint(buf, "%llud", v); string(screen, g->overtmp->r.min, display->black, ZP, font, buf); }} /* read one line of text from buffer and process integers */intreadnums(Machine *m, int n, uvlong *a, int spanlines){ int i; char *p, *ep; if(spanlines) ep = m->ebufp; else for(ep=m->bufp; ep<m->ebufp; ep++) if(*ep == '\n') break; p = m->bufp; for(i=0; i<n && p<ep; i++){ while(p<ep && (!isascii(*p) || !isdigit(*p)) && *p!='-') p++; if(p == ep) break; a[i] = strtoull(p, &p, 10); } if(ep < m->ebufp) ep++; m->bufp = ep; return i == n;} intreadswap(Machine *m, uvlong *a){ static int xxx = 0; if(strstr(m->buf, "memory\n")){ /* new /dev/swap - skip first 3 numbers */ if(!readnums(m, 7, a, 1)) return 0; a[Mem] = a[3]; a[Maxmem] = a[4]; a[Swap] = a[5]; a[Maxswap] = a[6]; a[Reclaim] = 0; a[Maxreclaim] = 0; if(m->bufp = strstr(m->buf, "reclaim")){ while(m->bufp > m->buf && m->bufp[-1] != '\n') m->bufp--; a[Reclaim] = strtoull(m->bufp, &m->bufp, 10); while(*m->bufp++ == '/') a[Maxreclaim] = strtoull(m->bufp, &m->bufp, 10); } a[Kern] = 0; a[Maxkern] = 0; if(m->bufp = strstr(m->buf, "kernel malloc")){ while(m->bufp > m->buf && m->bufp[-1] != '\n') m->bufp--;Lines 1–500 of 1417. Load more
#include <u.h> #include <libc.h> #include <ctype.h> #include <draw.h> #include <event.h> #include <keyboard.h> #define MAXNUM 10 /* maximum number of numbers on data line */ typedef struct Graph Graph; typedef struct Machine Machine; struct Graph { int colindex; Rectangle r; int *data; int ndata; char *label; void (*newvalue)(Machine*, uvlong*, uvlong*, int); void (*update)(Graph*, uvlong, uvlong); Machine *mach; int overflow; Image *overtmp; }; enum { /* /dev/swap */ Mem = 0, Maxmem, Swap, Maxswap, Reclaim, Maxreclaim, Kern, Maxkern, Draw, Maxdraw, /* /dev/sysstats */ Procno = 0, Context, Interrupt, Syscall, Fault, TLBfault, TLBpurge, Load, Idle, InIntr, /* /net/ether0/stats */ In = 0, Link, Out, Err0, }; struct Machine { char *name; char *shortname; int remote; int statsfd; int swapfd; int etherfd; int ifstatsfd; int batteryfd; int bitsybatfd; int tempfd; int disable; uvlong devswap[10]; uvlong devsysstat[10]; uvlong prevsysstat[10]; int nproc; int lgproc; uvlong netetherstats[8]; uvlong prevetherstats[8]; uvlong batterystats[2]; uvlong netetherifstats[2]; uvlong temp[10]; /* big enough to hold /dev/sysstat even with many processors */ char buf[8*1024]; char *bufp; char *ebufp; }; enum { Mainproc, Inputproc, NPROC, }; enum { Ncolor = 6, Ysqueeze = 2, /* vertical squeezing of label text */ Labspace = 2, /* room around label */ Dot = 2, /* height of dot */ Opwid = 5, /* strlen("add ") or strlen("drop ") */ Nlab = 3, /* max number of labels on y axis */ Lablen = 16, /* max length of label */ Lx = 4, /* label tick length */ }; enum Menu2 { Mbattery, Mcontext, Mether, Methererr, Metherin, Metherout, Mfault, Midle, Minintr, Mintr, Mload, Mmem, Mswap, Mreclaim, Mkern, Mdraw, Msyscall, Mtlbmiss, Mtlbpurge, Msignal, Mtemp, Nmenu2, }; char *menu2str[Nmenu2+1] = { "add battery ", "add context ", "add ether ", "add ethererr", "add etherin ", "add etherout", "add fault ", "add idle ", "add inintr ", "add intr ", "add load ", "add mem ", "add swap ", "add reclaim ", "add kern ", "add draw ", "add syscall ", "add tlbmiss ", "add tlbpurge", "add 802.11b ", "add temp ", nil, }; void contextval(Machine*, uvlong*, uvlong*, int), etherval(Machine*, uvlong*, uvlong*, int), ethererrval(Machine*, uvlong*, uvlong*, int), etherinval(Machine*, uvlong*, uvlong*, int), etheroutval(Machine*, uvlong*, uvlong*, int), faultval(Machine*, uvlong*, uvlong*, int), intrval(Machine*, uvlong*, uvlong*, int), inintrval(Machine*, uvlong*, uvlong*, int), loadval(Machine*, uvlong*, uvlong*, int), idleval(Machine*, uvlong*, uvlong*, int), memval(Machine*, uvlong*, uvlong*, int), swapval(Machine*, uvlong*, uvlong*, int), reclaimval(Machine*, uvlong*, uvlong*, int), kernval(Machine*, uvlong*, uvlong*, int), drawval(Machine*, uvlong*, uvlong*, int), syscallval(Machine*, uvlong*, uvlong*, int), tlbmissval(Machine*, uvlong*, uvlong*, int), tlbpurgeval(Machine*, uvlong*, uvlong*, int), batteryval(Machine*, uvlong*, uvlong*, int), signalval(Machine*, uvlong*, uvlong*, int), tempval(Machine*, uvlong*, uvlong*, int); Menu menu2 = {menu2str, nil}; int present[Nmenu2]; void (*newvaluefn[Nmenu2])(Machine*, uvlong*, uvlong*, int init) = { batteryval, contextval, etherval, ethererrval, etherinval, etheroutval, faultval, idleval, inintrval, intrval, loadval, memval, swapval, reclaimval, kernval, drawval, syscallval, tlbmissval, tlbpurgeval, signalval, tempval, }; Image *cols[Ncolor][3]; Graph *graph; Machine *mach; char *mysysname; char argchars[] = "8bcdeEfiIkmlnprstwz"; int pids[NPROC]; int parity; /* toggled to avoid patterns in textured background */ int nmach; int ngraph; /* totaly number is ngraph*nmach */ double scale = 1.0; int logscale = 0; int ylabels = 0; int sleeptime = 1000; char *procnames[NPROC] = {"main", "input"}; void killall(char *s) { int i, pid; pid = getpid(); for(i=0; i<NPROC; i++) if(pids[i] && pids[i]!=pid) postnote(PNPROC, pids[i], "kill"); exits(s); } void* emalloc(ulong sz) { void *v; v = malloc(sz); if(v == nil) { fprint(2, "stats: out of memory allocating %ld: %r\n", sz); killall("mem"); } memset(v, 0, sz); return v; } void* erealloc(void *v, ulong sz) { v = realloc(v, sz); if(v == nil) { fprint(2, "stats: out of memory reallocating %ld: %r\n", sz); killall("mem"); } return v; } char* estrdup(char *s) { char *t; if((t = strdup(s)) == nil) { fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s); killall("mem"); } return t; } void mkcol(int i, int c0, int c1, int c2) { cols[i][0] = allocimagemix(display, c0, DBlack); cols[i][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c1); cols[i][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c2); } void colinit(void) { /* Peach */ mkcol(0, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Aqua */ mkcol(1, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Yellow */ mkcol(2, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Green */ mkcol(3, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Blue */ mkcol(4, 0xFFFFFFFF, 0x383838FF, 0xC8C8C8FF); /* Grey */ cols[5][0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEEEEEEFF); cols[5][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF); cols[5][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x888888FF); } int loadbuf(Machine *m, int *fd) { int n; if(*fd < 0) return 0; seek(*fd, 0, 0); n = read(*fd, m->buf, sizeof m->buf-1); if(n <= 0){ close(*fd); *fd = -1; return 0; } m->bufp = m->buf; m->ebufp = m->buf+n; m->buf[n] = 0; return 1; } void label(Point p, int dy, char *text) { char *s; Rune r[2]; int w, maxw, maxy; p.x += Labspace; maxy = p.y+dy; maxw = 0; r[1] = '\0'; for(s=text; *s; ){ if(p.y+font->height-Ysqueeze > maxy) break; w = chartorune(r, s); s += w; w = runestringwidth(font, r); if(w > maxw) maxw = w; runestring(screen, p, display->black, ZP, font, r); p.y += font->height-Ysqueeze; } } Point paritypt(int x) { return Pt(x+parity, 0); } Point datapoint(Graph *g, int x, uvlong v, uvlong vmax) { Point p; double y; p.x = x; y = ((double)v)/(vmax*scale); if(logscale){ /* * Arrange scale to cover a factor of 1000. * vmax corresponds to the 100 mark. * 10*vmax is the top of the scale. */ if(y <= 0.) y = 0; else{ y = log10(y); /* 1 now corresponds to the top; -2 to the bottom; rescale */ y = (y+2.)/3.; } } if(y >= 1.) y = 1; if(y <= 0.) y = 0; p.y = g->r.max.y - Dy(g->r)*y - Dot; if(p.y < g->r.min.y) p.y = g->r.min.y; if(p.y > g->r.max.y-Dot) p.y = g->r.max.y-Dot; return p; } void drawdatum(Graph *g, int x, uvlong prev, uvlong v, uvlong vmax) { int c; Point p, q; c = g->colindex; p = datapoint(g, x, v, vmax); q = datapoint(g, x, prev, vmax); if(p.y < q.y){ draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x)); draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP); draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP); }else{ draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x)); draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP); draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP); } } void redraw(Graph *g, uvlong vmax) { int i, c; c = g->colindex; draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x)); for(i=1; i<Dx(g->r); i++) drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax); drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax); g->overflow = 0; } void update1(Graph *g, uvlong v, uvlong vmax) { char buf[48]; int overflow; if(g->overflow && g->overtmp!=nil) draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min); draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y)); drawdatum(g, g->r.max.x-1, g->data[0], v, vmax); memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0])); g->data[0] = v; g->overflow = 0; if(logscale) overflow = (v>10*vmax*scale); else overflow = (v>vmax*scale); if(overflow && g->overtmp!=nil){ g->overflow = 1; draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min); sprint(buf, "%llud", v); string(screen, g->overtmp->r.min, display->black, ZP, font, buf); } } /* read one line of text from buffer and process integers */ int readnums(Machine *m, int n, uvlong *a, int spanlines) { int i; char *p, *ep; if(spanlines) ep = m->ebufp; else for(ep=m->bufp; ep<m->ebufp; ep++) if(*ep == '\n') break; p = m->bufp; for(i=0; i<n && p<ep; i++){ while(p<ep && (!isascii(*p) || !isdigit(*p)) && *p!='-') p++; if(p == ep) break; a[i] = strtoull(p, &p, 10); } if(ep < m->ebufp) ep++; m->bufp = ep; return i == n; } int readswap(Machine *m, uvlong *a) { static int xxx = 0; if(strstr(m->buf, "memory\n")){ /* new /dev/swap - skip first 3 numbers */ if(!readnums(m, 7, a, 1)) return 0; a[Mem] = a[3]; a[Maxmem] = a[4]; a[Swap] = a[5]; a[Maxswap] = a[6]; a[Reclaim] = 0; a[Maxreclaim] = 0; if(m->bufp = strstr(m->buf, "reclaim")){ while(m->bufp > m->buf && m->bufp[-1] != '\n') m->bufp--; a[Reclaim] = strtoull(m->bufp, &m->bufp, 10); while(*m->bufp++ == '/') a[Maxreclaim] = strtoull(m->bufp, &m->bufp, 10); } a[Kern] = 0; a[Maxkern] = 0; if(m->bufp = strstr(m->buf, "kernel malloc")){ while(m->bufp > m->buf && m->bufp[-1] != '\n') m->bufp--;