13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 3*7dd7cddfSDavid du Colombier #include <ctype.h> 4*7dd7cddfSDavid du Colombier #include <auth.h> 5*7dd7cddfSDavid du Colombier #include <fcall.h> 6*7dd7cddfSDavid du Colombier #include <draw.h> 7*7dd7cddfSDavid du Colombier #include <event.h> 83e12c5d1SDavid du Colombier 9*7dd7cddfSDavid du Colombier #define MAXNUM 8 /* maximum number of numbers on data line */ 103e12c5d1SDavid du Colombier 11*7dd7cddfSDavid du Colombier typedef struct Graph Graph; 12*7dd7cddfSDavid du Colombier typedef struct Machine Machine; 13*7dd7cddfSDavid du Colombier 14*7dd7cddfSDavid du Colombier struct Graph 15*7dd7cddfSDavid du Colombier { 16*7dd7cddfSDavid du Colombier int colindex; 17*7dd7cddfSDavid du Colombier Rectangle r; 18*7dd7cddfSDavid du Colombier int *data; 19*7dd7cddfSDavid du Colombier int ndata; 20*7dd7cddfSDavid du Colombier char *label; 21*7dd7cddfSDavid du Colombier void (*newvalue)(Machine*, long*, long*); 22*7dd7cddfSDavid du Colombier void (*update)(Graph*, long, long); 23*7dd7cddfSDavid du Colombier Machine *mach; 24*7dd7cddfSDavid du Colombier int overflow; 25*7dd7cddfSDavid du Colombier Image *overtmp; 26*7dd7cddfSDavid du Colombier }; 273e12c5d1SDavid du Colombier 283e12c5d1SDavid du Colombier enum 293e12c5d1SDavid du Colombier { 30*7dd7cddfSDavid du Colombier /* /dev/swap */ 31*7dd7cddfSDavid du Colombier Mem = 0, 32*7dd7cddfSDavid du Colombier Maxmem, 333e12c5d1SDavid du Colombier Swap, 34*7dd7cddfSDavid du Colombier Maxswap, 35*7dd7cddfSDavid du Colombier /* /dev/sysstats */ 36*7dd7cddfSDavid du Colombier Procno = 0, 37*7dd7cddfSDavid du Colombier Context, 38*7dd7cddfSDavid du Colombier Interrupt, 393e12c5d1SDavid du Colombier Syscall, 403e12c5d1SDavid du Colombier Fault, 41*7dd7cddfSDavid du Colombier TLBfault, 42*7dd7cddfSDavid du Colombier TLBpurge, 433e12c5d1SDavid du Colombier Load, 44*7dd7cddfSDavid du Colombier /* /net/ether0/0/stats */ 45*7dd7cddfSDavid du Colombier In = 0, 46*7dd7cddfSDavid du Colombier Out, 47*7dd7cddfSDavid du Colombier Err0, 483e12c5d1SDavid du Colombier }; 493e12c5d1SDavid du Colombier 50*7dd7cddfSDavid du Colombier struct Machine 513e12c5d1SDavid du Colombier { 52*7dd7cddfSDavid du Colombier char *name; 53*7dd7cddfSDavid du Colombier int remote; 54*7dd7cddfSDavid du Colombier int statsfd; 55*7dd7cddfSDavid du Colombier int swapfd; 56*7dd7cddfSDavid du Colombier int etherfd; 57*7dd7cddfSDavid du Colombier int disable; 583e12c5d1SDavid du Colombier 59*7dd7cddfSDavid du Colombier long devswap[4]; 60*7dd7cddfSDavid du Colombier long devsysstat[8]; 61*7dd7cddfSDavid du Colombier long prevsysstat[8]; 62*7dd7cddfSDavid du Colombier int nproc; 63*7dd7cddfSDavid du Colombier long netetherstats[8]; 64*7dd7cddfSDavid du Colombier long prevetherstats[8]; 653e12c5d1SDavid du Colombier 66*7dd7cddfSDavid du Colombier char buf[1024]; 67*7dd7cddfSDavid du Colombier char *bufp; 68*7dd7cddfSDavid du Colombier char *ebufp; 693e12c5d1SDavid du Colombier }; 70*7dd7cddfSDavid du Colombier 71*7dd7cddfSDavid du Colombier enum 72*7dd7cddfSDavid du Colombier { 73*7dd7cddfSDavid du Colombier Mainproc, 74*7dd7cddfSDavid du Colombier Mouseproc, 75*7dd7cddfSDavid du Colombier NPROC, 76*7dd7cddfSDavid du Colombier }; 77*7dd7cddfSDavid du Colombier 78*7dd7cddfSDavid du Colombier enum 79*7dd7cddfSDavid du Colombier { 80*7dd7cddfSDavid du Colombier Ncolor = 6, 81*7dd7cddfSDavid du Colombier Ysqueeze = 2, /* vertical squeezing of label text */ 82*7dd7cddfSDavid du Colombier Labspace = 2, /* room around label */ 83*7dd7cddfSDavid du Colombier Dot = 2, /* height of dot */ 84*7dd7cddfSDavid du Colombier Opwid = 5, /* strlen("add ") or strlen("drop ") */ 85*7dd7cddfSDavid du Colombier }; 86*7dd7cddfSDavid du Colombier 87*7dd7cddfSDavid du Colombier enum Menu2 88*7dd7cddfSDavid du Colombier { 89*7dd7cddfSDavid du Colombier Mcontext, 90*7dd7cddfSDavid du Colombier Mether, 91*7dd7cddfSDavid du Colombier Methererr, 92*7dd7cddfSDavid du Colombier Metherin, 93*7dd7cddfSDavid du Colombier Metherout, 94*7dd7cddfSDavid du Colombier Mfault, 95*7dd7cddfSDavid du Colombier Mintr, 96*7dd7cddfSDavid du Colombier Mload, 97*7dd7cddfSDavid du Colombier Mmem, 98*7dd7cddfSDavid du Colombier Mswap, 99*7dd7cddfSDavid du Colombier Msyscall, 100*7dd7cddfSDavid du Colombier Mtlbmiss, 101*7dd7cddfSDavid du Colombier Mtlbpurge, 102*7dd7cddfSDavid du Colombier Nmenu2, 103*7dd7cddfSDavid du Colombier }; 104*7dd7cddfSDavid du Colombier 105*7dd7cddfSDavid du Colombier char *menu2str[Nmenu2+1] = { 106*7dd7cddfSDavid du Colombier "add context ", 107*7dd7cddfSDavid du Colombier "add ether ", 108*7dd7cddfSDavid du Colombier "add ethererr", 109*7dd7cddfSDavid du Colombier "add etherin ", 110*7dd7cddfSDavid du Colombier "add etherout", 111*7dd7cddfSDavid du Colombier "add fault ", 112*7dd7cddfSDavid du Colombier "add intr ", 113*7dd7cddfSDavid du Colombier "add load ", 114*7dd7cddfSDavid du Colombier "add mem ", 115*7dd7cddfSDavid du Colombier "add swap ", 116*7dd7cddfSDavid du Colombier "add syscall ", 117*7dd7cddfSDavid du Colombier "add tlbmiss ", 118*7dd7cddfSDavid du Colombier "add tlbpurge", 119*7dd7cddfSDavid du Colombier nil, 120*7dd7cddfSDavid du Colombier }; 121*7dd7cddfSDavid du Colombier 122*7dd7cddfSDavid du Colombier 123*7dd7cddfSDavid du Colombier void contextval(Machine*, long*, long*), 124*7dd7cddfSDavid du Colombier etherval(Machine*, long*, long*), 125*7dd7cddfSDavid du Colombier ethererrval(Machine*, long*, long*), 126*7dd7cddfSDavid du Colombier etherinval(Machine*, long*, long*), 127*7dd7cddfSDavid du Colombier etheroutval(Machine*, long*, long*), 128*7dd7cddfSDavid du Colombier faultval(Machine*, long*, long*), 129*7dd7cddfSDavid du Colombier intrval(Machine*, long*, long*), 130*7dd7cddfSDavid du Colombier loadval(Machine*, long*, long*), 131*7dd7cddfSDavid du Colombier memval(Machine*, long*, long*), 132*7dd7cddfSDavid du Colombier swapval(Machine*, long*, long*), 133*7dd7cddfSDavid du Colombier syscallval(Machine*, long*, long*), 134*7dd7cddfSDavid du Colombier tlbmissval(Machine*, long*, long*), 135*7dd7cddfSDavid du Colombier tlbpurgeval(Machine*, long*, long*); 136*7dd7cddfSDavid du Colombier 137*7dd7cddfSDavid du Colombier Menu menu2 = {menu2str, nil}; 138*7dd7cddfSDavid du Colombier int present[Nmenu2]; 139*7dd7cddfSDavid du Colombier void (*newvaluefn[Nmenu2])(Machine*, long*, long*) = { 140*7dd7cddfSDavid du Colombier contextval, 141*7dd7cddfSDavid du Colombier etherval, 142*7dd7cddfSDavid du Colombier ethererrval, 143*7dd7cddfSDavid du Colombier etherinval, 144*7dd7cddfSDavid du Colombier etheroutval, 145*7dd7cddfSDavid du Colombier faultval, 146*7dd7cddfSDavid du Colombier intrval, 147*7dd7cddfSDavid du Colombier loadval, 148*7dd7cddfSDavid du Colombier memval, 149*7dd7cddfSDavid du Colombier swapval, 150*7dd7cddfSDavid du Colombier syscallval, 151*7dd7cddfSDavid du Colombier tlbmissval, 152*7dd7cddfSDavid du Colombier tlbpurgeval, 153*7dd7cddfSDavid du Colombier }; 154*7dd7cddfSDavid du Colombier 155*7dd7cddfSDavid du Colombier Image *cols[Ncolor][3]; 156*7dd7cddfSDavid du Colombier Graph *graph; 157*7dd7cddfSDavid du Colombier Machine *mach; 158*7dd7cddfSDavid du Colombier Font *mediumfont; 159*7dd7cddfSDavid du Colombier char *mysysname; 160*7dd7cddfSDavid du Colombier char argchars[] = "ceEfimlnpstw"; 161*7dd7cddfSDavid du Colombier int pids[NPROC]; 162*7dd7cddfSDavid du Colombier int parity; /* toggled to avoid patterns in textured background */ 163*7dd7cddfSDavid du Colombier int nmach; 164*7dd7cddfSDavid du Colombier int ngraph; /* totaly number is ngraph*nmach */ 165*7dd7cddfSDavid du Colombier 166*7dd7cddfSDavid du Colombier char *procnames[NPROC] = {"main", "mouse"}; 167*7dd7cddfSDavid du Colombier 168*7dd7cddfSDavid du Colombier void 169*7dd7cddfSDavid du Colombier killall(char *s) 170*7dd7cddfSDavid du Colombier { 171*7dd7cddfSDavid du Colombier int i, pid; 172*7dd7cddfSDavid du Colombier 173*7dd7cddfSDavid du Colombier pid = getpid(); 174*7dd7cddfSDavid du Colombier for(i=0; i<NPROC; i++) 175*7dd7cddfSDavid du Colombier if(pids[i] && pids[i]!=pid) 176*7dd7cddfSDavid du Colombier postnote(PNPROC, pids[i], "kill"); 177*7dd7cddfSDavid du Colombier exits(s); 178*7dd7cddfSDavid du Colombier } 179*7dd7cddfSDavid du Colombier 180*7dd7cddfSDavid du Colombier void* 181*7dd7cddfSDavid du Colombier emalloc(ulong sz) 182*7dd7cddfSDavid du Colombier { 183*7dd7cddfSDavid du Colombier void *v; 184*7dd7cddfSDavid du Colombier v = malloc(sz); 185*7dd7cddfSDavid du Colombier if(v == nil) { 186*7dd7cddfSDavid du Colombier fprint(2, "stats: out of memory allocating %ld: %r\n", sz); 187*7dd7cddfSDavid du Colombier killall("mem"); 188*7dd7cddfSDavid du Colombier } 189*7dd7cddfSDavid du Colombier memset(v, 0, sz); 190*7dd7cddfSDavid du Colombier return v; 191*7dd7cddfSDavid du Colombier } 192*7dd7cddfSDavid du Colombier 193*7dd7cddfSDavid du Colombier void* 194*7dd7cddfSDavid du Colombier erealloc(void *v, ulong sz) 195*7dd7cddfSDavid du Colombier { 196*7dd7cddfSDavid du Colombier v = realloc(v, sz); 197*7dd7cddfSDavid du Colombier if(v == nil) { 198*7dd7cddfSDavid du Colombier fprint(2, "stats: out of memory reallocating %ld: %r\n", sz); 199*7dd7cddfSDavid du Colombier killall("mem"); 200*7dd7cddfSDavid du Colombier } 201*7dd7cddfSDavid du Colombier return v; 2023e12c5d1SDavid du Colombier } 2033e12c5d1SDavid du Colombier 2043e12c5d1SDavid du Colombier char* 205*7dd7cddfSDavid du Colombier estrdup(char *s) 2063e12c5d1SDavid du Colombier { 207*7dd7cddfSDavid du Colombier char *t; 208*7dd7cddfSDavid du Colombier if((t = strdup(s)) == nil) { 209*7dd7cddfSDavid du Colombier fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s); 210*7dd7cddfSDavid du Colombier killall("mem"); 211*7dd7cddfSDavid du Colombier } 212*7dd7cddfSDavid du Colombier return t; 2133e12c5d1SDavid du Colombier } 2143e12c5d1SDavid du Colombier 2153e12c5d1SDavid du Colombier void 216*7dd7cddfSDavid du Colombier mkcol(int i, int c0, int c1, int c2) 2173e12c5d1SDavid du Colombier { 218*7dd7cddfSDavid du Colombier cols[i][0] = allocimagemix(display, c0, DWhite); 219*7dd7cddfSDavid du Colombier cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1); 220*7dd7cddfSDavid du Colombier cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2); 221*7dd7cddfSDavid du Colombier } 2223e12c5d1SDavid du Colombier 223*7dd7cddfSDavid du Colombier void 224*7dd7cddfSDavid du Colombier colinit(void) 225*7dd7cddfSDavid du Colombier { 226*7dd7cddfSDavid du Colombier mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font"); 227*7dd7cddfSDavid du Colombier if(mediumfont == nil) 228*7dd7cddfSDavid du Colombier mediumfont = font; 229*7dd7cddfSDavid du Colombier 230*7dd7cddfSDavid du Colombier /* Peach */ 231*7dd7cddfSDavid du Colombier mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF); 232*7dd7cddfSDavid du Colombier /* Aqua */ 233*7dd7cddfSDavid du Colombier mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue); 234*7dd7cddfSDavid du Colombier /* Yellow */ 235*7dd7cddfSDavid du Colombier mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen); 236*7dd7cddfSDavid du Colombier /* Green */ 237*7dd7cddfSDavid du Colombier mkcol(3, DPalegreen, DMedgreen, DDarkgreen); 238*7dd7cddfSDavid du Colombier /* Blue */ 239*7dd7cddfSDavid du Colombier mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF); 240*7dd7cddfSDavid du Colombier /* Grey */ 241*7dd7cddfSDavid du Colombier cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF); 242*7dd7cddfSDavid du Colombier cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF); 243*7dd7cddfSDavid du Colombier cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF); 244*7dd7cddfSDavid du Colombier } 245*7dd7cddfSDavid du Colombier 246*7dd7cddfSDavid du Colombier int 247*7dd7cddfSDavid du Colombier loadbuf(Machine *m, int *fd) 248*7dd7cddfSDavid du Colombier { 249*7dd7cddfSDavid du Colombier int n; 250*7dd7cddfSDavid du Colombier 251*7dd7cddfSDavid du Colombier 252*7dd7cddfSDavid du Colombier if(*fd < 0) 253*7dd7cddfSDavid du Colombier return 0; 254*7dd7cddfSDavid du Colombier seek(*fd, 0, 0); 255*7dd7cddfSDavid du Colombier n = read(*fd, m->buf, sizeof m->buf); 256*7dd7cddfSDavid du Colombier if(n <= 0){ 257*7dd7cddfSDavid du Colombier close(*fd); 258*7dd7cddfSDavid du Colombier *fd = -1; 259*7dd7cddfSDavid du Colombier return 0; 260*7dd7cddfSDavid du Colombier } 261*7dd7cddfSDavid du Colombier m->bufp = m->buf; 262*7dd7cddfSDavid du Colombier m->ebufp = m->buf+n; 263*7dd7cddfSDavid du Colombier return 1; 264*7dd7cddfSDavid du Colombier } 265*7dd7cddfSDavid du Colombier 266*7dd7cddfSDavid du Colombier void 267*7dd7cddfSDavid du Colombier label(Point p, int dy, char *text) 268*7dd7cddfSDavid du Colombier { 269*7dd7cddfSDavid du Colombier char *s; 270*7dd7cddfSDavid du Colombier Rune r[2]; 271*7dd7cddfSDavid du Colombier int w, maxw, maxy; 272*7dd7cddfSDavid du Colombier 273*7dd7cddfSDavid du Colombier p.x += Labspace; 274*7dd7cddfSDavid du Colombier maxy = p.y+dy; 275*7dd7cddfSDavid du Colombier maxw = 0; 276*7dd7cddfSDavid du Colombier r[1] = '\0'; 277*7dd7cddfSDavid du Colombier for(s=text; *s; ){ 278*7dd7cddfSDavid du Colombier if(p.y+mediumfont->height-Ysqueeze > maxy) 279*7dd7cddfSDavid du Colombier break; 280*7dd7cddfSDavid du Colombier w = chartorune(r, s); 281*7dd7cddfSDavid du Colombier s += w; 282*7dd7cddfSDavid du Colombier w = runestringwidth(mediumfont, r); 283*7dd7cddfSDavid du Colombier if(w > maxw) 284*7dd7cddfSDavid du Colombier maxw = w; 285*7dd7cddfSDavid du Colombier runestring(screen, p, display->black, ZP, mediumfont, r); 286*7dd7cddfSDavid du Colombier p.y += mediumfont->height-Ysqueeze; 287*7dd7cddfSDavid du Colombier } 288*7dd7cddfSDavid du Colombier } 289*7dd7cddfSDavid du Colombier 290*7dd7cddfSDavid du Colombier Point 291*7dd7cddfSDavid du Colombier paritypt(int x) 292*7dd7cddfSDavid du Colombier { 293*7dd7cddfSDavid du Colombier return Pt(x+parity, 0); 294*7dd7cddfSDavid du Colombier } 295*7dd7cddfSDavid du Colombier 296*7dd7cddfSDavid du Colombier Point 297*7dd7cddfSDavid du Colombier datapoint(Graph *g, int x, long v, long vmax) 298*7dd7cddfSDavid du Colombier { 299*7dd7cddfSDavid du Colombier Point p; 300*7dd7cddfSDavid du Colombier 301*7dd7cddfSDavid du Colombier p.x = x; 302*7dd7cddfSDavid du Colombier p.y = g->r.max.y - Dy(g->r)*v/vmax - Dot; 303*7dd7cddfSDavid du Colombier if(p.y < g->r.min.y) 304*7dd7cddfSDavid du Colombier p.y = g->r.min.y; 305*7dd7cddfSDavid du Colombier if(p.y > g->r.max.y-Dot) 306*7dd7cddfSDavid du Colombier p.y = g->r.max.y-Dot; 307*7dd7cddfSDavid du Colombier return p; 308*7dd7cddfSDavid du Colombier } 309*7dd7cddfSDavid du Colombier 310*7dd7cddfSDavid du Colombier void 311*7dd7cddfSDavid du Colombier drawdatum(Graph *g, int x, long prev, long v, long vmax) 312*7dd7cddfSDavid du Colombier { 313*7dd7cddfSDavid du Colombier int c; 314*7dd7cddfSDavid du Colombier Point p, q; 315*7dd7cddfSDavid du Colombier 316*7dd7cddfSDavid du Colombier c = g->colindex; 317*7dd7cddfSDavid du Colombier p = datapoint(g, x, v, vmax); 318*7dd7cddfSDavid du Colombier q = datapoint(g, x, prev, vmax); 319*7dd7cddfSDavid du Colombier if(p.y < q.y){ 320*7dd7cddfSDavid du Colombier draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x)); 321*7dd7cddfSDavid du Colombier draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP); 322*7dd7cddfSDavid du Colombier draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP); 323*7dd7cddfSDavid du Colombier }else{ 324*7dd7cddfSDavid du Colombier draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x)); 325*7dd7cddfSDavid du Colombier draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP); 326*7dd7cddfSDavid du Colombier draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP); 327*7dd7cddfSDavid du Colombier } 328*7dd7cddfSDavid du Colombier 329*7dd7cddfSDavid du Colombier } 330*7dd7cddfSDavid du Colombier 331*7dd7cddfSDavid du Colombier void 332*7dd7cddfSDavid du Colombier redraw(Graph *g, int vmax) 333*7dd7cddfSDavid du Colombier { 334*7dd7cddfSDavid du Colombier int i, c; 335*7dd7cddfSDavid du Colombier 336*7dd7cddfSDavid du Colombier c = g->colindex; 337*7dd7cddfSDavid du Colombier draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x)); 338*7dd7cddfSDavid du Colombier for(i=1; i<Dx(g->r); i++) 339*7dd7cddfSDavid du Colombier drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax); 340*7dd7cddfSDavid du Colombier drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax); 341*7dd7cddfSDavid du Colombier g->overflow = 0; 342*7dd7cddfSDavid du Colombier } 343*7dd7cddfSDavid du Colombier 344*7dd7cddfSDavid du Colombier void 345*7dd7cddfSDavid du Colombier update1(Graph *g, long v, long vmax) 346*7dd7cddfSDavid du Colombier { 347*7dd7cddfSDavid du Colombier char buf[32]; 348*7dd7cddfSDavid du Colombier 349*7dd7cddfSDavid du Colombier if(g->overflow && g->overtmp!=nil) 350*7dd7cddfSDavid du Colombier draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min); 351*7dd7cddfSDavid du Colombier draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y)); 352*7dd7cddfSDavid du Colombier drawdatum(g, g->r.max.x-1, g->data[0], v, vmax); 353*7dd7cddfSDavid du Colombier memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0])); 354*7dd7cddfSDavid du Colombier g->data[0] = v; 355*7dd7cddfSDavid du Colombier g->overflow = 0; 356*7dd7cddfSDavid du Colombier if(v>vmax && g->overtmp!=nil){ 357*7dd7cddfSDavid du Colombier g->overflow = 1; 358*7dd7cddfSDavid du Colombier draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min); 359*7dd7cddfSDavid du Colombier sprint(buf, "%ld", v); 360*7dd7cddfSDavid du Colombier string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, buf); 361*7dd7cddfSDavid du Colombier } 362*7dd7cddfSDavid du Colombier } 363*7dd7cddfSDavid du Colombier 364*7dd7cddfSDavid du Colombier /* read one line of text from buffer and process integers */ 365*7dd7cddfSDavid du Colombier int 366*7dd7cddfSDavid du Colombier readnums(Machine *m, int n, long *a, int spanlines) 367*7dd7cddfSDavid du Colombier { 368*7dd7cddfSDavid du Colombier int i; 369*7dd7cddfSDavid du Colombier char *p, *ep; 370*7dd7cddfSDavid du Colombier 371*7dd7cddfSDavid du Colombier if(spanlines) 372*7dd7cddfSDavid du Colombier ep = m->ebufp; 373*7dd7cddfSDavid du Colombier else 374*7dd7cddfSDavid du Colombier for(ep=m->bufp; ep<m->ebufp; ep++) 375*7dd7cddfSDavid du Colombier if(*ep == '\n') 376*7dd7cddfSDavid du Colombier break; 377*7dd7cddfSDavid du Colombier p = m->bufp; 378*7dd7cddfSDavid du Colombier for(i=0; i<n && p<ep; i++){ 379*7dd7cddfSDavid du Colombier while(p<ep && !isdigit(*p)) 380*7dd7cddfSDavid du Colombier p++; 381*7dd7cddfSDavid du Colombier if(p == ep) 382*7dd7cddfSDavid du Colombier break; 383*7dd7cddfSDavid du Colombier a[i] = strtol(p, &p, 10); 384*7dd7cddfSDavid du Colombier } 385*7dd7cddfSDavid du Colombier if(ep < m->ebufp) 386*7dd7cddfSDavid du Colombier ep++; 387*7dd7cddfSDavid du Colombier m->bufp = ep; 388*7dd7cddfSDavid du Colombier return i == n; 389*7dd7cddfSDavid du Colombier } 390*7dd7cddfSDavid du Colombier 391*7dd7cddfSDavid du Colombier /* Network on fd1, mount driver on fd0 */ 392*7dd7cddfSDavid du Colombier static int 393*7dd7cddfSDavid du Colombier filter(int fd) 394*7dd7cddfSDavid du Colombier { 395*7dd7cddfSDavid du Colombier int p[2]; 396*7dd7cddfSDavid du Colombier 397*7dd7cddfSDavid du Colombier if(pipe(p) < 0){ 398*7dd7cddfSDavid du Colombier fprint(2, "stats: can't pipe: %r\n"); 399*7dd7cddfSDavid du Colombier killall("pipe"); 400*7dd7cddfSDavid du Colombier } 401*7dd7cddfSDavid du Colombier 402*7dd7cddfSDavid du Colombier switch(rfork(RFNOWAIT|RFPROC|RFFDG)) { 403*7dd7cddfSDavid du Colombier case -1: 404*7dd7cddfSDavid du Colombier sysfatal("rfork record module"); 405*7dd7cddfSDavid du Colombier case 0: 406*7dd7cddfSDavid du Colombier dup(fd, 1); 407*7dd7cddfSDavid du Colombier close(fd); 408*7dd7cddfSDavid du Colombier dup(p[0], 0); 409*7dd7cddfSDavid du Colombier close(p[0]); 410*7dd7cddfSDavid du Colombier close(p[1]); 411*7dd7cddfSDavid du Colombier execl("/bin/aux/fcall", "fcall", 0); 412*7dd7cddfSDavid du Colombier fprint(2, "stats: can't exec fcall: %r\n"); 413*7dd7cddfSDavid du Colombier killall("fcall"); 414*7dd7cddfSDavid du Colombier default: 415*7dd7cddfSDavid du Colombier close(fd); 416*7dd7cddfSDavid du Colombier close(p[0]); 417*7dd7cddfSDavid du Colombier } 418*7dd7cddfSDavid du Colombier return p[1]; 419*7dd7cddfSDavid du Colombier } 420*7dd7cddfSDavid du Colombier 421*7dd7cddfSDavid du Colombier /* 422*7dd7cddfSDavid du Colombier * 9fs 423*7dd7cddfSDavid du Colombier */ 424*7dd7cddfSDavid du Colombier int 425*7dd7cddfSDavid du Colombier connect9fs(char *addr) 426*7dd7cddfSDavid du Colombier { 427*7dd7cddfSDavid du Colombier char dir[4*NAMELEN], *na; 428*7dd7cddfSDavid du Colombier int fd; 429*7dd7cddfSDavid du Colombier 430*7dd7cddfSDavid du Colombier fprint(2, "connect9fs..."); 431*7dd7cddfSDavid du Colombier na = netmkaddr(addr, 0, "9fs"); 432*7dd7cddfSDavid du Colombier 433*7dd7cddfSDavid du Colombier fprint(2, "dial %s...", na); 434*7dd7cddfSDavid du Colombier if((fd = dial(na, 0, dir, 0)) < 0) 435*7dd7cddfSDavid du Colombier return -1; 436*7dd7cddfSDavid du Colombier 437*7dd7cddfSDavid du Colombier fprint(2, "dir %s...", dir); 438*7dd7cddfSDavid du Colombier if(strstr(dir, "tcp")) 439*7dd7cddfSDavid du Colombier fd = filter(fd); 440*7dd7cddfSDavid du Colombier return fd; 441*7dd7cddfSDavid du Colombier } 442*7dd7cddfSDavid du Colombier 443*7dd7cddfSDavid du Colombier /* 444*7dd7cddfSDavid du Colombier * exportfs 445*7dd7cddfSDavid du Colombier */ 446*7dd7cddfSDavid du Colombier int 447*7dd7cddfSDavid du Colombier connectexportfs(char *addr) 448*7dd7cddfSDavid du Colombier { 449*7dd7cddfSDavid du Colombier char buf[ERRLEN], dir[4*NAMELEN], *na; 450*7dd7cddfSDavid du Colombier int fd, n; 451*7dd7cddfSDavid du Colombier char *tree; 452*7dd7cddfSDavid du Colombier 453*7dd7cddfSDavid du Colombier tree = "/"; 454*7dd7cddfSDavid du Colombier na = netmkaddr(addr, 0, "exportfs"); 455*7dd7cddfSDavid du Colombier if((fd = dial(na, 0, dir, 0)) < 0) 456*7dd7cddfSDavid du Colombier return -1; 457*7dd7cddfSDavid du Colombier 458*7dd7cddfSDavid du Colombier if(auth(fd) < 0){ 459*7dd7cddfSDavid du Colombier close(fd); 460*7dd7cddfSDavid du Colombier return -1; 461*7dd7cddfSDavid du Colombier } 462*7dd7cddfSDavid du Colombier 463*7dd7cddfSDavid du Colombier n = write(fd, tree, strlen(tree)); 464*7dd7cddfSDavid du Colombier if(n < 0){ 465*7dd7cddfSDavid du Colombier close(fd); 466*7dd7cddfSDavid du Colombier return -1; 467*7dd7cddfSDavid du Colombier } 468*7dd7cddfSDavid du Colombier 469*7dd7cddfSDavid du Colombier strcpy(buf, "can't read tree"); 470*7dd7cddfSDavid du Colombier n = read(fd, buf, sizeof buf - 1); 471*7dd7cddfSDavid du Colombier if(n!=2 || buf[0]!='O' || buf[1]!='K'){ 472*7dd7cddfSDavid du Colombier buf[sizeof buf - 1] = '\0'; 473*7dd7cddfSDavid du Colombier werrstr("bad remote tree: %s\n", buf); 474*7dd7cddfSDavid du Colombier close(fd); 475*7dd7cddfSDavid du Colombier return -1; 476*7dd7cddfSDavid du Colombier } 477*7dd7cddfSDavid du Colombier 478*7dd7cddfSDavid du Colombier if(strstr(dir, "tcp")) 479*7dd7cddfSDavid du Colombier fd = filter(fd); 480*7dd7cddfSDavid du Colombier 481*7dd7cddfSDavid du Colombier return fd; 482*7dd7cddfSDavid du Colombier } 483*7dd7cddfSDavid du Colombier 484*7dd7cddfSDavid du Colombier void 485*7dd7cddfSDavid du Colombier initmach(Machine *m, char *name) 486*7dd7cddfSDavid du Colombier { 487*7dd7cddfSDavid du Colombier int n, fd; 488*7dd7cddfSDavid du Colombier long a[MAXNUM]; 489*7dd7cddfSDavid du Colombier char *p, mpt[256], buf[256]; 490*7dd7cddfSDavid du Colombier 491*7dd7cddfSDavid du Colombier p = strchr(name, '!'); 492*7dd7cddfSDavid du Colombier if(p){ 493*7dd7cddfSDavid du Colombier p++; 494*7dd7cddfSDavid du Colombier m->name = estrdup(p+1); 495*7dd7cddfSDavid du Colombier }else 496*7dd7cddfSDavid du Colombier p = name; 497*7dd7cddfSDavid du Colombier m->name = estrdup(p); 498*7dd7cddfSDavid du Colombier m->remote = (strcmp(p, mysysname) != 0); 499*7dd7cddfSDavid du Colombier if(m->remote == 0) 500*7dd7cddfSDavid du Colombier strcpy(mpt, ""); 501*7dd7cddfSDavid du Colombier else{ 502*7dd7cddfSDavid du Colombier snprint(mpt, sizeof mpt, "/n/%s", p); 503*7dd7cddfSDavid du Colombier fd = connectexportfs(name); 504*7dd7cddfSDavid du Colombier if(fd < 0){ 505*7dd7cddfSDavid du Colombier fprint(2, "can't connect to %s: %r\n", name); 506*7dd7cddfSDavid du Colombier killall("connect"); 507*7dd7cddfSDavid du Colombier } 508*7dd7cddfSDavid du Colombier if(mount(fd, mpt, MREPL, "") < 0){ 509*7dd7cddfSDavid du Colombier fprint(2, "stats: mount %s on %s failed (%r); trying /n/sid\n", name, mpt); 510*7dd7cddfSDavid du Colombier strcpy(mpt, "/n/sid"); 511*7dd7cddfSDavid du Colombier if(mount(fd, mpt, MREPL, "") < 0){ 512*7dd7cddfSDavid du Colombier fprint(2, "stats: mount %s on %s failed: %r\n", name, mpt); 513*7dd7cddfSDavid du Colombier killall("mount"); 514*7dd7cddfSDavid du Colombier } 515*7dd7cddfSDavid du Colombier } 516*7dd7cddfSDavid du Colombier } 517*7dd7cddfSDavid du Colombier 518*7dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "%s/dev/swap", mpt); 519*7dd7cddfSDavid du Colombier m->swapfd = open(buf, OREAD); 520*7dd7cddfSDavid du Colombier if(loadbuf(m, &m->swapfd) && readnums(m, nelem(m->devswap), a, 0)) 521*7dd7cddfSDavid du Colombier memmove(m->devswap, a, sizeof m->devswap); 522*7dd7cddfSDavid du Colombier else 523*7dd7cddfSDavid du Colombier m->devswap[Maxmem] = m->devswap[Maxswap] = 100; 524*7dd7cddfSDavid du Colombier 525*7dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "%s/dev/sysstat", mpt); 526*7dd7cddfSDavid du Colombier m->statsfd = open(buf, OREAD); 527*7dd7cddfSDavid du Colombier if(loadbuf(m, &m->statsfd)){ 528*7dd7cddfSDavid du Colombier for(n=0; readnums(m, nelem(m->devsysstat), a, 0); n++) 529*7dd7cddfSDavid du Colombier ; 530*7dd7cddfSDavid du Colombier m->nproc = n; 531*7dd7cddfSDavid du Colombier }else 532*7dd7cddfSDavid du Colombier m->nproc = 1; 533*7dd7cddfSDavid du Colombier 534*7dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "%s/net/ether0/0/stats", mpt); 535*7dd7cddfSDavid du Colombier m->etherfd = open(buf, OREAD); 536*7dd7cddfSDavid du Colombier if(loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1)) 537*7dd7cddfSDavid du Colombier memmove(m->netetherstats, a, sizeof m->netetherstats); 538*7dd7cddfSDavid du Colombier } 539*7dd7cddfSDavid du Colombier 540*7dd7cddfSDavid du Colombier jmp_buf catchalarm; 541*7dd7cddfSDavid du Colombier 542*7dd7cddfSDavid du Colombier void 543*7dd7cddfSDavid du Colombier alarmed(void *a, char *s) 544*7dd7cddfSDavid du Colombier { 545*7dd7cddfSDavid du Colombier if(strcmp(s, "alarm") == 0) 546*7dd7cddfSDavid du Colombier notejmp(a, catchalarm, 1); 5473e12c5d1SDavid du Colombier noted(NDFLT); 5483e12c5d1SDavid du Colombier } 549*7dd7cddfSDavid du Colombier 550*7dd7cddfSDavid du Colombier int 551*7dd7cddfSDavid du Colombier needswap(int init) 552*7dd7cddfSDavid du Colombier { 553*7dd7cddfSDavid du Colombier return init | present[Mmem] | present[Mswap]; 554*7dd7cddfSDavid du Colombier } 555*7dd7cddfSDavid du Colombier 556*7dd7cddfSDavid du Colombier 557*7dd7cddfSDavid du Colombier int 558*7dd7cddfSDavid du Colombier needstat(int init) 559*7dd7cddfSDavid du Colombier { 560*7dd7cddfSDavid du Colombier return init | present[Mcontext] | present[Mfault] | present[Mintr] | present[Mload] | 561*7dd7cddfSDavid du Colombier present[Msyscall] | present[Mtlbmiss] | present[Mtlbpurge]; 562*7dd7cddfSDavid du Colombier } 563*7dd7cddfSDavid du Colombier 564*7dd7cddfSDavid du Colombier 565*7dd7cddfSDavid du Colombier int 566*7dd7cddfSDavid du Colombier needether(int init) 567*7dd7cddfSDavid du Colombier { 568*7dd7cddfSDavid du Colombier return init | present[Mether] | present[Metherin] | present[Metherout] | present[Methererr]; 569*7dd7cddfSDavid du Colombier } 570*7dd7cddfSDavid du Colombier 571*7dd7cddfSDavid du Colombier void 572*7dd7cddfSDavid du Colombier readmach(Machine *m, int init) 573*7dd7cddfSDavid du Colombier { 574*7dd7cddfSDavid du Colombier int n, i; 575*7dd7cddfSDavid du Colombier long a[8]; 576*7dd7cddfSDavid du Colombier char buf[32]; 577*7dd7cddfSDavid du Colombier 578*7dd7cddfSDavid du Colombier if(m->remote && (m->disable || setjmp(catchalarm))){ 579*7dd7cddfSDavid du Colombier if(m->disable == 0){ 580*7dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "%s(dead)", m->name); 581*7dd7cddfSDavid du Colombier m->name = estrdup(buf); 582*7dd7cddfSDavid du Colombier if(display != nil) /* else we're still initializing */ 583*7dd7cddfSDavid du Colombier eresized(0); 584*7dd7cddfSDavid du Colombier } 585*7dd7cddfSDavid du Colombier m->disable = 1; 586*7dd7cddfSDavid du Colombier memmove(m->devsysstat, m->prevsysstat, sizeof m->devsysstat); 587*7dd7cddfSDavid du Colombier memmove(m->netetherstats, m->prevetherstats, sizeof m->netetherstats); 588*7dd7cddfSDavid du Colombier return; 589*7dd7cddfSDavid du Colombier } 590*7dd7cddfSDavid du Colombier if(m->remote){ 591*7dd7cddfSDavid du Colombier notify(alarmed); 592*7dd7cddfSDavid du Colombier alarm(5000); 593*7dd7cddfSDavid du Colombier } 594*7dd7cddfSDavid du Colombier if(needswap(init) && loadbuf(m, &m->swapfd) && readnums(m, nelem(m->devswap), a, 0)) 595*7dd7cddfSDavid du Colombier memmove(m->devswap, a, sizeof m->devswap); 596*7dd7cddfSDavid du Colombier if(needstat(init) && loadbuf(m, &m->statsfd)){ 597*7dd7cddfSDavid du Colombier memmove(m->prevsysstat, m->devsysstat, sizeof m->devsysstat); 598*7dd7cddfSDavid du Colombier memset(m->devsysstat, 0, sizeof m->devsysstat); 599*7dd7cddfSDavid du Colombier for(n=0; n<m->nproc && readnums(m, nelem(m->devsysstat), a, 0); n++) 600*7dd7cddfSDavid du Colombier for(i=0; i<nelem(m->devsysstat); i++) 601*7dd7cddfSDavid du Colombier m->devsysstat[i] += a[i]; 602*7dd7cddfSDavid du Colombier } 603*7dd7cddfSDavid du Colombier if(needether(init) && loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1)){ 604*7dd7cddfSDavid du Colombier memmove(m->prevetherstats, m->netetherstats, sizeof m->netetherstats); 605*7dd7cddfSDavid du Colombier memmove(m->netetherstats, a, sizeof m->netetherstats); 606*7dd7cddfSDavid du Colombier } 607*7dd7cddfSDavid du Colombier if(m->remote){ 608*7dd7cddfSDavid du Colombier alarm(0); 609*7dd7cddfSDavid du Colombier notify(nil); 610*7dd7cddfSDavid du Colombier } 611*7dd7cddfSDavid du Colombier } 612*7dd7cddfSDavid du Colombier 613*7dd7cddfSDavid du Colombier void 614*7dd7cddfSDavid du Colombier memval(Machine *m, long *v, long *vmax) 615*7dd7cddfSDavid du Colombier { 616*7dd7cddfSDavid du Colombier *v = m->devswap[Mem]; 617*7dd7cddfSDavid du Colombier *vmax = m->devswap[Maxmem]; 618*7dd7cddfSDavid du Colombier } 619*7dd7cddfSDavid du Colombier 620*7dd7cddfSDavid du Colombier void 621*7dd7cddfSDavid du Colombier swapval(Machine *m, long *v, long *vmax) 622*7dd7cddfSDavid du Colombier { 623*7dd7cddfSDavid du Colombier *v = m->devswap[Swap]; 624*7dd7cddfSDavid du Colombier *vmax = m->devswap[Maxswap]; 625*7dd7cddfSDavid du Colombier } 626*7dd7cddfSDavid du Colombier 627*7dd7cddfSDavid du Colombier void 628*7dd7cddfSDavid du Colombier contextval(Machine *m, long *v, long *vmax) 629*7dd7cddfSDavid du Colombier { 630*7dd7cddfSDavid du Colombier *v = m->devsysstat[Context]-m->prevsysstat[Context]; 631*7dd7cddfSDavid du Colombier *vmax = 1000*m->nproc; 632*7dd7cddfSDavid du Colombier } 633*7dd7cddfSDavid du Colombier 634*7dd7cddfSDavid du Colombier void 635*7dd7cddfSDavid du Colombier intrval(Machine *m, long *v, long *vmax) 636*7dd7cddfSDavid du Colombier { 637*7dd7cddfSDavid du Colombier *v = m->devsysstat[Interrupt]-m->prevsysstat[Interrupt]; 638*7dd7cddfSDavid du Colombier *vmax = 1000*m->nproc; 639*7dd7cddfSDavid du Colombier } 640*7dd7cddfSDavid du Colombier 641*7dd7cddfSDavid du Colombier void 642*7dd7cddfSDavid du Colombier syscallval(Machine *m, long *v, long *vmax) 643*7dd7cddfSDavid du Colombier { 644*7dd7cddfSDavid du Colombier *v = m->devsysstat[Syscall]-m->prevsysstat[Syscall]; 645*7dd7cddfSDavid du Colombier *vmax = 1000*m->nproc; 646*7dd7cddfSDavid du Colombier } 647*7dd7cddfSDavid du Colombier 648*7dd7cddfSDavid du Colombier void 649*7dd7cddfSDavid du Colombier faultval(Machine *m, long *v, long *vmax) 650*7dd7cddfSDavid du Colombier { 651*7dd7cddfSDavid du Colombier *v = m->devsysstat[Fault]-m->prevsysstat[Fault]; 652*7dd7cddfSDavid du Colombier *vmax = 1000*m->nproc; 653*7dd7cddfSDavid du Colombier } 654*7dd7cddfSDavid du Colombier 655*7dd7cddfSDavid du Colombier void 656*7dd7cddfSDavid du Colombier tlbmissval(Machine *m, long *v, long *vmax) 657*7dd7cddfSDavid du Colombier { 658*7dd7cddfSDavid du Colombier *v = m->devsysstat[TLBfault]-m->prevsysstat[TLBfault]; 659*7dd7cddfSDavid du Colombier *vmax = 10*m->nproc; 660*7dd7cddfSDavid du Colombier } 661*7dd7cddfSDavid du Colombier 662*7dd7cddfSDavid du Colombier void 663*7dd7cddfSDavid du Colombier tlbpurgeval(Machine *m, long *v, long *vmax) 664*7dd7cddfSDavid du Colombier { 665*7dd7cddfSDavid du Colombier *v = m->devsysstat[TLBpurge]-m->prevsysstat[TLBpurge]; 666*7dd7cddfSDavid du Colombier *vmax = 10*m->nproc; 667*7dd7cddfSDavid du Colombier } 668*7dd7cddfSDavid du Colombier 669*7dd7cddfSDavid du Colombier void 670*7dd7cddfSDavid du Colombier loadval(Machine *m, long *v, long *vmax) 671*7dd7cddfSDavid du Colombier { 672*7dd7cddfSDavid du Colombier *v = m->devsysstat[Load]; 673*7dd7cddfSDavid du Colombier *vmax = 1000*m->nproc; 674*7dd7cddfSDavid du Colombier } 675*7dd7cddfSDavid du Colombier 676*7dd7cddfSDavid du Colombier void 677*7dd7cddfSDavid du Colombier etherval(Machine *m, long *v, long *vmax) 678*7dd7cddfSDavid du Colombier { 679*7dd7cddfSDavid du Colombier *v = m->netetherstats[In]-m->prevetherstats[In] + m->netetherstats[Out]-m->prevetherstats[Out]; 680*7dd7cddfSDavid du Colombier *vmax = 1000*m->nproc; 681*7dd7cddfSDavid du Colombier } 682*7dd7cddfSDavid du Colombier 683*7dd7cddfSDavid du Colombier void 684*7dd7cddfSDavid du Colombier etherinval(Machine *m, long *v, long *vmax) 685*7dd7cddfSDavid du Colombier { 686*7dd7cddfSDavid du Colombier *v = m->netetherstats[In]-m->prevetherstats[In]; 687*7dd7cddfSDavid du Colombier *vmax = 1000*m->nproc; 688*7dd7cddfSDavid du Colombier } 689*7dd7cddfSDavid du Colombier 690*7dd7cddfSDavid du Colombier void 691*7dd7cddfSDavid du Colombier etheroutval(Machine *m, long *v, long *vmax) 692*7dd7cddfSDavid du Colombier { 693*7dd7cddfSDavid du Colombier *v = m->netetherstats[Out]-m->prevetherstats[Out]; 694*7dd7cddfSDavid du Colombier *vmax = 1000*m->nproc; 695*7dd7cddfSDavid du Colombier } 696*7dd7cddfSDavid du Colombier 697*7dd7cddfSDavid du Colombier void 698*7dd7cddfSDavid du Colombier ethererrval(Machine *m, long *v, long *vmax) 699*7dd7cddfSDavid du Colombier { 700*7dd7cddfSDavid du Colombier int i; 701*7dd7cddfSDavid du Colombier 702*7dd7cddfSDavid du Colombier *v = 0; 703*7dd7cddfSDavid du Colombier for(i=Err0; i<nelem(m->netetherstats); i++) 704*7dd7cddfSDavid du Colombier *v += m->netetherstats[i]; 705*7dd7cddfSDavid du Colombier *vmax = 10*m->nproc; 706*7dd7cddfSDavid du Colombier } 707*7dd7cddfSDavid du Colombier 708*7dd7cddfSDavid du Colombier void 709*7dd7cddfSDavid du Colombier usage(void) 710*7dd7cddfSDavid du Colombier { 711*7dd7cddfSDavid du Colombier fprint(2, "usage: stats [-%s] [machine...]\n", argchars); 712*7dd7cddfSDavid du Colombier exits("usage"); 713*7dd7cddfSDavid du Colombier } 714*7dd7cddfSDavid du Colombier 715*7dd7cddfSDavid du Colombier void 716*7dd7cddfSDavid du Colombier addgraph(int n) 717*7dd7cddfSDavid du Colombier { 718*7dd7cddfSDavid du Colombier Graph *g, *ograph; 719*7dd7cddfSDavid du Colombier int i, j; 720*7dd7cddfSDavid du Colombier static int nadd; 721*7dd7cddfSDavid du Colombier 722*7dd7cddfSDavid du Colombier if(n > nelem(menu2str)) 723*7dd7cddfSDavid du Colombier abort(); 724*7dd7cddfSDavid du Colombier /* avoid two adjacent graphs of same color */ 725*7dd7cddfSDavid du Colombier if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor) 726*7dd7cddfSDavid du Colombier nadd++; 727*7dd7cddfSDavid du Colombier ograph = graph; 728*7dd7cddfSDavid du Colombier graph = emalloc(nmach*(ngraph+1)*sizeof(Graph)); 729*7dd7cddfSDavid du Colombier for(i=0; i<nmach; i++) 730*7dd7cddfSDavid du Colombier for(j=0; j<ngraph; j++) 731*7dd7cddfSDavid du Colombier graph[i*(ngraph+1)+j] = ograph[i*ngraph+j]; 732*7dd7cddfSDavid du Colombier free(ograph); 733*7dd7cddfSDavid du Colombier ngraph++; 734*7dd7cddfSDavid du Colombier for(i=0; i<nmach; i++){ 735*7dd7cddfSDavid du Colombier g = &graph[i*ngraph+(ngraph-1)]; 736*7dd7cddfSDavid du Colombier memset(g, 0, sizeof(Graph)); 737*7dd7cddfSDavid du Colombier g->label = menu2str[n]+Opwid; 738*7dd7cddfSDavid du Colombier g->newvalue = newvaluefn[n]; 739*7dd7cddfSDavid du Colombier g->update = update1; /* no other update functions yet */ 740*7dd7cddfSDavid du Colombier g->mach = &mach[i]; 741*7dd7cddfSDavid du Colombier g->colindex = nadd%Ncolor; 742*7dd7cddfSDavid du Colombier } 743*7dd7cddfSDavid du Colombier present[n] = 1; 744*7dd7cddfSDavid du Colombier nadd++; 745*7dd7cddfSDavid du Colombier } 746*7dd7cddfSDavid du Colombier 747*7dd7cddfSDavid du Colombier void 748*7dd7cddfSDavid du Colombier dropgraph(int which) 749*7dd7cddfSDavid du Colombier { 750*7dd7cddfSDavid du Colombier Graph *ograph; 751*7dd7cddfSDavid du Colombier int i, j, n; 752*7dd7cddfSDavid du Colombier 753*7dd7cddfSDavid du Colombier if(which > nelem(menu2str)) 754*7dd7cddfSDavid du Colombier abort(); 755*7dd7cddfSDavid du Colombier /* convert n to index in graph table */ 756*7dd7cddfSDavid du Colombier n = -1; 757*7dd7cddfSDavid du Colombier for(i=0; i<ngraph; i++) 758*7dd7cddfSDavid du Colombier if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){ 759*7dd7cddfSDavid du Colombier n = i; 760*7dd7cddfSDavid du Colombier break; 761*7dd7cddfSDavid du Colombier } 762*7dd7cddfSDavid du Colombier if(n < 0){ 763*7dd7cddfSDavid du Colombier fprint(2, "stats: internal error can't drop graph\n"); 764*7dd7cddfSDavid du Colombier killall("error"); 765*7dd7cddfSDavid du Colombier } 766*7dd7cddfSDavid du Colombier ograph = graph; 767*7dd7cddfSDavid du Colombier graph = emalloc(nmach*(ngraph-1)*sizeof(Graph)); 768*7dd7cddfSDavid du Colombier for(i=0; i<nmach; i++){ 769*7dd7cddfSDavid du Colombier for(j=0; j<n; j++) 770*7dd7cddfSDavid du Colombier graph[i*(ngraph-1)+j] = ograph[i*ngraph+j]; 771*7dd7cddfSDavid du Colombier free(ograph[i*ngraph+j].data); 772*7dd7cddfSDavid du Colombier freeimage(ograph[i*ngraph+j].overtmp); 773*7dd7cddfSDavid du Colombier for(j++; j<ngraph; j++) 774*7dd7cddfSDavid du Colombier graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j]; 775*7dd7cddfSDavid du Colombier } 776*7dd7cddfSDavid du Colombier free(ograph); 777*7dd7cddfSDavid du Colombier ngraph--; 778*7dd7cddfSDavid du Colombier present[which] = 0; 779*7dd7cddfSDavid du Colombier } 780*7dd7cddfSDavid du Colombier 781*7dd7cddfSDavid du Colombier void 782*7dd7cddfSDavid du Colombier addmachine(char *name) 783*7dd7cddfSDavid du Colombier { 784*7dd7cddfSDavid du Colombier if(ngraph > 0){ 785*7dd7cddfSDavid du Colombier fprint(2, "stats: internal error: ngraph>0 in addmachine()\n"); 786*7dd7cddfSDavid du Colombier usage(); 787*7dd7cddfSDavid du Colombier } 788*7dd7cddfSDavid du Colombier if(mach == nil) 789*7dd7cddfSDavid du Colombier nmach = 0; /* a little dance to get us started with local machine by default */ 790*7dd7cddfSDavid du Colombier mach = erealloc(mach, (nmach+1)*sizeof(Machine)); 791*7dd7cddfSDavid du Colombier memset(mach+nmach, 0, sizeof(Machine)); 792*7dd7cddfSDavid du Colombier initmach(mach+nmach, name); 793*7dd7cddfSDavid du Colombier nmach++; 794*7dd7cddfSDavid du Colombier } 795*7dd7cddfSDavid du Colombier 796*7dd7cddfSDavid du Colombier void 797*7dd7cddfSDavid du Colombier resize(void) 798*7dd7cddfSDavid du Colombier { 799*7dd7cddfSDavid du Colombier int i, j, n, startx, starty, x, y, dx, dy, ondata; 800*7dd7cddfSDavid du Colombier Graph *g; 801*7dd7cddfSDavid du Colombier Rectangle machr, r; 802*7dd7cddfSDavid du Colombier long v, vmax; 803*7dd7cddfSDavid du Colombier char buf[128]; 804*7dd7cddfSDavid du Colombier 805*7dd7cddfSDavid du Colombier draw(screen, screen->r, display->white, nil, ZP); 806*7dd7cddfSDavid du Colombier 807*7dd7cddfSDavid du Colombier /* label left edge */ 808*7dd7cddfSDavid du Colombier x = screen->r.min.x; 809*7dd7cddfSDavid du Colombier y = screen->r.min.y + Labspace+mediumfont->height+Labspace; 810*7dd7cddfSDavid du Colombier dy = (screen->r.max.y - y)/ngraph; 811*7dd7cddfSDavid du Colombier dx = Labspace+stringwidth(mediumfont, "0")+Labspace; 812*7dd7cddfSDavid du Colombier startx = x+dx+1; 813*7dd7cddfSDavid du Colombier starty = y; 814*7dd7cddfSDavid du Colombier for(i=0; i<ngraph; i++,y+=dy){ 815*7dd7cddfSDavid du Colombier draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP); 816*7dd7cddfSDavid du Colombier draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x)); 817*7dd7cddfSDavid du Colombier label(Pt(x, y), dy, graph[i].label); 818*7dd7cddfSDavid du Colombier draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP); 819*7dd7cddfSDavid du Colombier } 820*7dd7cddfSDavid du Colombier 821*7dd7cddfSDavid du Colombier /* label top edge */ 822*7dd7cddfSDavid du Colombier dx = (screen->r.max.x - startx)/nmach; 823*7dd7cddfSDavid du Colombier for(x=startx, i=0; i<nmach; i++,x+=dx){ 824*7dd7cddfSDavid du Colombier draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP); 825*7dd7cddfSDavid du Colombier j = dx/stringwidth(mediumfont, "0"); 826*7dd7cddfSDavid du Colombier n = mach[i].nproc; 827*7dd7cddfSDavid du Colombier if(n>1 && j>=1+3+(n>10)+(n>100)){ /* first char of name + (n) */ 828*7dd7cddfSDavid du Colombier j -= 3+(n>10)+(n>100); 829*7dd7cddfSDavid du Colombier if(j <= 0) 830*7dd7cddfSDavid du Colombier j = 1; 831*7dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n); 832*7dd7cddfSDavid du Colombier }else 833*7dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "%.*s", j, mach[i].name); 834*7dd7cddfSDavid du Colombier string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, mediumfont, buf); 835*7dd7cddfSDavid du Colombier } 836*7dd7cddfSDavid du Colombier 837*7dd7cddfSDavid du Colombier /* create graphs */ 838*7dd7cddfSDavid du Colombier for(i=0; i<nmach; i++){ 839*7dd7cddfSDavid du Colombier machr = Rect(startx+i*dx, starty, screen->r.max.x, screen->r.max.y); 840*7dd7cddfSDavid du Colombier if(i < nmach-1) 841*7dd7cddfSDavid du Colombier machr.max.x = startx+(i+1)*dx - 1; 842*7dd7cddfSDavid du Colombier y = starty; 843*7dd7cddfSDavid du Colombier for(j=0; j<ngraph; j++, y+=dy){ 844*7dd7cddfSDavid du Colombier g = &graph[i*ngraph+j]; 845*7dd7cddfSDavid du Colombier /* allocate data */ 846*7dd7cddfSDavid du Colombier ondata = g->ndata; 847*7dd7cddfSDavid du Colombier g->ndata = Dx(machr)+1; /* may be too many if label will be drawn here; so what? */ 848*7dd7cddfSDavid du Colombier g->data = erealloc(g->data, g->ndata*sizeof(long)); 849*7dd7cddfSDavid du Colombier if(g->ndata > ondata) 850*7dd7cddfSDavid du Colombier memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(long)); 851*7dd7cddfSDavid du Colombier /* set geometry */ 852*7dd7cddfSDavid du Colombier g->r = machr; 853*7dd7cddfSDavid du Colombier g->r.min.y = y; 854*7dd7cddfSDavid du Colombier g->r.max.y = y+dy - 1; 855*7dd7cddfSDavid du Colombier if(j == ngraph-1) 856*7dd7cddfSDavid du Colombier g->r.max.y = screen->r.max.y; 857*7dd7cddfSDavid du Colombier draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x)); 858*7dd7cddfSDavid du Colombier g->overflow = 0; 859*7dd7cddfSDavid du Colombier r = g->r; 860*7dd7cddfSDavid du Colombier r.max.y = r.min.y+mediumfont->height; 861*7dd7cddfSDavid du Colombier r.max.x = r.min.x+stringwidth(mediumfont, "9999999"); 862*7dd7cddfSDavid du Colombier freeimage(g->overtmp); 863*7dd7cddfSDavid du Colombier g->overtmp = nil; 864*7dd7cddfSDavid du Colombier if(r.max.x <= g->r.max.x) 865*7dd7cddfSDavid du Colombier g->overtmp = allocimage(display, r, screen->chan, 0, -1); 866*7dd7cddfSDavid du Colombier g->newvalue(g->mach, &v, &vmax); 867*7dd7cddfSDavid du Colombier redraw(g, vmax); 868*7dd7cddfSDavid du Colombier } 869*7dd7cddfSDavid du Colombier } 870*7dd7cddfSDavid du Colombier 871*7dd7cddfSDavid du Colombier flushimage(display, 1); 872*7dd7cddfSDavid du Colombier } 873*7dd7cddfSDavid du Colombier 874*7dd7cddfSDavid du Colombier void 875*7dd7cddfSDavid du Colombier eresized(int new) 876*7dd7cddfSDavid du Colombier { 877*7dd7cddfSDavid du Colombier lockdisplay(display); 878*7dd7cddfSDavid du Colombier if(new && getwindow(display, Refnone) < 0) { 879*7dd7cddfSDavid du Colombier fprint(2, "stats: can't reattach to window\n"); 880*7dd7cddfSDavid du Colombier killall("reattach"); 881*7dd7cddfSDavid du Colombier } 882*7dd7cddfSDavid du Colombier resize(); 883*7dd7cddfSDavid du Colombier unlockdisplay(display); 884*7dd7cddfSDavid du Colombier } 885*7dd7cddfSDavid du Colombier 886*7dd7cddfSDavid du Colombier void 887*7dd7cddfSDavid du Colombier mouseproc(void) 888*7dd7cddfSDavid du Colombier { 889*7dd7cddfSDavid du Colombier Mouse mouse; 890*7dd7cddfSDavid du Colombier int i; 891*7dd7cddfSDavid du Colombier 892*7dd7cddfSDavid du Colombier for(;;){ 893*7dd7cddfSDavid du Colombier mouse = emouse(); 894*7dd7cddfSDavid du Colombier if(mouse.buttons == 4){ 895*7dd7cddfSDavid du Colombier lockdisplay(display); 896*7dd7cddfSDavid du Colombier for(i=0; i<Nmenu2; i++) 897*7dd7cddfSDavid du Colombier if(present[i]) 898*7dd7cddfSDavid du Colombier memmove(menu2str[i], "drop ", Opwid); 899*7dd7cddfSDavid du Colombier else 900*7dd7cddfSDavid du Colombier memmove(menu2str[i], "add ", Opwid); 901*7dd7cddfSDavid du Colombier i = emenuhit(3, &mouse, &menu2); 902*7dd7cddfSDavid du Colombier if(i >= 0){ 903*7dd7cddfSDavid du Colombier if(!present[i]) 904*7dd7cddfSDavid du Colombier addgraph(i); 905*7dd7cddfSDavid du Colombier else if(ngraph > 1) 906*7dd7cddfSDavid du Colombier dropgraph(i); 907*7dd7cddfSDavid du Colombier resize(); 908*7dd7cddfSDavid du Colombier } 909*7dd7cddfSDavid du Colombier unlockdisplay(display); 910*7dd7cddfSDavid du Colombier } 911*7dd7cddfSDavid du Colombier } 912*7dd7cddfSDavid du Colombier } 913*7dd7cddfSDavid du Colombier 914*7dd7cddfSDavid du Colombier void 915*7dd7cddfSDavid du Colombier startproc(void (*f)(void), int index) 916*7dd7cddfSDavid du Colombier { 917*7dd7cddfSDavid du Colombier int pid; 918*7dd7cddfSDavid du Colombier 919*7dd7cddfSDavid du Colombier switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){ 920*7dd7cddfSDavid du Colombier case -1: 921*7dd7cddfSDavid du Colombier fprint(2, "stats: fork failed: %r\n"); 922*7dd7cddfSDavid du Colombier killall("fork failed"); 923*7dd7cddfSDavid du Colombier case 0: 924*7dd7cddfSDavid du Colombier f(); 925*7dd7cddfSDavid du Colombier fprint(2, "stats: %s process exits\n", procnames[index]); 926*7dd7cddfSDavid du Colombier if(index >= 0) 927*7dd7cddfSDavid du Colombier killall("process died"); 928*7dd7cddfSDavid du Colombier exits(nil); 929*7dd7cddfSDavid du Colombier } 930*7dd7cddfSDavid du Colombier if(index >= 0) 931*7dd7cddfSDavid du Colombier pids[index] = pid; 932*7dd7cddfSDavid du Colombier } 933*7dd7cddfSDavid du Colombier 934*7dd7cddfSDavid du Colombier void 935*7dd7cddfSDavid du Colombier main(int argc, char *argv[]) 936*7dd7cddfSDavid du Colombier { 937*7dd7cddfSDavid du Colombier int i, j; 938*7dd7cddfSDavid du Colombier long v, vmax, nargs; 939*7dd7cddfSDavid du Colombier char args[100]; 940*7dd7cddfSDavid du Colombier 941*7dd7cddfSDavid du Colombier nmach = 1; 942*7dd7cddfSDavid du Colombier mysysname = getenv("sysname"); 943*7dd7cddfSDavid du Colombier if(mysysname == nil){ 944*7dd7cddfSDavid du Colombier fprint(2, "stats: can't find $sysname: %r\n"); 945*7dd7cddfSDavid du Colombier exits("sysname"); 946*7dd7cddfSDavid du Colombier } 947*7dd7cddfSDavid du Colombier mysysname = estrdup(mysysname); 948*7dd7cddfSDavid du Colombier 949*7dd7cddfSDavid du Colombier nargs = 0; 950*7dd7cddfSDavid du Colombier ARGBEGIN{ 951*7dd7cddfSDavid du Colombier default: 952*7dd7cddfSDavid du Colombier if(nargs>=sizeof args || strchr(argchars, ARGC())==nil) 953*7dd7cddfSDavid du Colombier usage(); 954*7dd7cddfSDavid du Colombier args[nargs++] = ARGC(); 955*7dd7cddfSDavid du Colombier }ARGEND 956*7dd7cddfSDavid du Colombier 957*7dd7cddfSDavid du Colombier if(argc == 0){ 958*7dd7cddfSDavid du Colombier mach = emalloc(nmach*sizeof(Machine)); 959*7dd7cddfSDavid du Colombier initmach(&mach[0], mysysname); 960*7dd7cddfSDavid du Colombier readmach(&mach[0], 1); 961*7dd7cddfSDavid du Colombier }else{ 962*7dd7cddfSDavid du Colombier for(i=0; i<argc; i++){ 963*7dd7cddfSDavid du Colombier addmachine(argv[i]); 964*7dd7cddfSDavid du Colombier readmach(&mach[i], 1); 965*7dd7cddfSDavid du Colombier } 966*7dd7cddfSDavid du Colombier } 967*7dd7cddfSDavid du Colombier 968*7dd7cddfSDavid du Colombier for(i=0; i<nargs; i++) 969*7dd7cddfSDavid du Colombier switch(args[i]){ 970*7dd7cddfSDavid du Colombier default: 971*7dd7cddfSDavid du Colombier fprint(2, "stats: internal error: unknown arg %c\n", args[i]); 972*7dd7cddfSDavid du Colombier usage(); 973*7dd7cddfSDavid du Colombier case 'c': 974*7dd7cddfSDavid du Colombier addgraph(Mcontext); 975*7dd7cddfSDavid du Colombier break; 976*7dd7cddfSDavid du Colombier case 'e': 977*7dd7cddfSDavid du Colombier addgraph(Mether); 978*7dd7cddfSDavid du Colombier break; 979*7dd7cddfSDavid du Colombier case 'E': 980*7dd7cddfSDavid du Colombier addgraph(Metherin); 981*7dd7cddfSDavid du Colombier addgraph(Metherout); 982*7dd7cddfSDavid du Colombier break; 983*7dd7cddfSDavid du Colombier case 'f': 984*7dd7cddfSDavid du Colombier addgraph(Mfault); 985*7dd7cddfSDavid du Colombier break; 986*7dd7cddfSDavid du Colombier case 'i': 987*7dd7cddfSDavid du Colombier addgraph(Mintr); 988*7dd7cddfSDavid du Colombier break; 989*7dd7cddfSDavid du Colombier case 'l': 990*7dd7cddfSDavid du Colombier addgraph(Mload); 991*7dd7cddfSDavid du Colombier break; 992*7dd7cddfSDavid du Colombier case 'm': 993*7dd7cddfSDavid du Colombier addgraph(Mmem); 994*7dd7cddfSDavid du Colombier break; 995*7dd7cddfSDavid du Colombier case 'n': 996*7dd7cddfSDavid du Colombier addgraph(Metherin); 997*7dd7cddfSDavid du Colombier addgraph(Metherout); 998*7dd7cddfSDavid du Colombier addgraph(Methererr); 999*7dd7cddfSDavid du Colombier break; 1000*7dd7cddfSDavid du Colombier case 'p': 1001*7dd7cddfSDavid du Colombier addgraph(Mtlbpurge); 1002*7dd7cddfSDavid du Colombier break; 1003*7dd7cddfSDavid du Colombier case 's': 1004*7dd7cddfSDavid du Colombier addgraph(Msyscall); 1005*7dd7cddfSDavid du Colombier break; 1006*7dd7cddfSDavid du Colombier case 't': 1007*7dd7cddfSDavid du Colombier addgraph(Mtlbmiss); 1008*7dd7cddfSDavid du Colombier addgraph(Mtlbpurge); 1009*7dd7cddfSDavid du Colombier break; 1010*7dd7cddfSDavid du Colombier case 'w': 1011*7dd7cddfSDavid du Colombier addgraph(Mswap); 1012*7dd7cddfSDavid du Colombier break; 1013*7dd7cddfSDavid du Colombier } 1014*7dd7cddfSDavid du Colombier 1015*7dd7cddfSDavid du Colombier if(ngraph == 0) 1016*7dd7cddfSDavid du Colombier addgraph(Mload); 1017*7dd7cddfSDavid du Colombier 1018*7dd7cddfSDavid du Colombier for(i=0; i<nmach; i++) 1019*7dd7cddfSDavid du Colombier for(j=0; j<ngraph; j++) 1020*7dd7cddfSDavid du Colombier graph[i*ngraph+j].mach = &mach[i]; 1021*7dd7cddfSDavid du Colombier 1022*7dd7cddfSDavid du Colombier if(initdraw(nil, nil, "stats") < 0){ 1023*7dd7cddfSDavid du Colombier fprint(2, "stats: initdraw failed: %r\n"); 1024*7dd7cddfSDavid du Colombier exits("initdraw"); 1025*7dd7cddfSDavid du Colombier } 1026*7dd7cddfSDavid du Colombier colinit(); 1027*7dd7cddfSDavid du Colombier einit(Emouse); 1028*7dd7cddfSDavid du Colombier notify(nil); 1029*7dd7cddfSDavid du Colombier startproc(mouseproc, Mouseproc); 1030*7dd7cddfSDavid du Colombier pids[Mainproc] = getpid(); 1031*7dd7cddfSDavid du Colombier display->locking = 1; /* tell library we're using the display lock */ 1032*7dd7cddfSDavid du Colombier 1033*7dd7cddfSDavid du Colombier resize(); 1034*7dd7cddfSDavid du Colombier 1035*7dd7cddfSDavid du Colombier unlockdisplay(display); /* display is still locked from initdraw() */ 1036*7dd7cddfSDavid du Colombier for(;;){ 1037*7dd7cddfSDavid du Colombier for(i=0; i<nmach; i++) 1038*7dd7cddfSDavid du Colombier readmach(&mach[i], 0); 1039*7dd7cddfSDavid du Colombier lockdisplay(display); 1040*7dd7cddfSDavid du Colombier parity = 1-parity; 1041*7dd7cddfSDavid du Colombier for(i=0; i<nmach*ngraph; i++){ 1042*7dd7cddfSDavid du Colombier graph[i].newvalue(graph[i].mach, &v, &vmax); 1043*7dd7cddfSDavid du Colombier graph[i].update(&graph[i], v, vmax); 1044*7dd7cddfSDavid du Colombier } 1045*7dd7cddfSDavid du Colombier flushimage(display, 1); 1046*7dd7cddfSDavid du Colombier unlockdisplay(display); 1047*7dd7cddfSDavid du Colombier sleep(1000); 1048*7dd7cddfSDavid du Colombier } 1049*7dd7cddfSDavid du Colombier } 1050