📄 stats.c
字号:
#include <u.h>#include <libc.h>#include <ctype.h>#include <auth.h>#include <fcall.h>#include <draw.h>#include <event.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*, ulong*, ulong*, int); void (*update)(Graph*, ulong, ulong); Machine *mach; int overflow; Image *overtmp;};enum{ /* old /dev/swap */ Mem = 0, Maxmem, Swap, Maxswap, /* /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; int remote; int statsfd; int swapfd; int etherfd; int ifstatsfd; int batteryfd; int bitsybatfd; int disable; ulong devswap[4]; ulong devsysstat[10]; ulong prevsysstat[10]; int nproc; ulong netetherstats[8]; ulong prevetherstats[8]; ulong batterystats[2]; ulong netetherifstats[2]; char buf[1024]; char *bufp; char *ebufp;};enum{ Mainproc, Mouseproc, 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, Msyscall, Mtlbmiss, Mtlbpurge, Msignal, 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 syscall ", "add tlbmiss ", "add tlbpurge", "add 802.11b ", nil,};void contextval(Machine*, ulong*, ulong*, int), etherval(Machine*, ulong*, ulong*, int), ethererrval(Machine*, ulong*, ulong*, int), etherinval(Machine*, ulong*, ulong*, int), etheroutval(Machine*, ulong*, ulong*, int), faultval(Machine*, ulong*, ulong*, int), intrval(Machine*, ulong*, ulong*, int), inintrval(Machine*, ulong*, ulong*, int), loadval(Machine*, ulong*, ulong*, int), idleval(Machine*, ulong*, ulong*, int), memval(Machine*, ulong*, ulong*, int), swapval(Machine*, ulong*, ulong*, int), syscallval(Machine*, ulong*, ulong*, int), tlbmissval(Machine*, ulong*, ulong*, int), tlbpurgeval(Machine*, ulong*, ulong*, int), batteryval(Machine*, ulong*, ulong*, int), signalval(Machine*, ulong*, ulong*, int);Menu menu2 = {menu2str, nil};int present[Nmenu2];void (*newvaluefn[Nmenu2])(Machine*, ulong*, ulong*, int init) = { batteryval, contextval, etherval, ethererrval, etherinval, etheroutval, faultval, idleval, inintrval, intrval, loadval, memval, swapval, syscallval, tlbmissval, tlbpurgeval, signalval,};Image *cols[Ncolor][3];Graph *graph;Machine *mach;Font *mediumfont;char *mysysname;char argchars[] = "8bceEfiImlnpstw";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 oldsystem = 0;int sleeptime = 1000;char *procnames[NPROC] = {"main", "mouse"};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, DWhite); cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1); cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);}voidcolinit(void){ mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font"); if(mediumfont == nil) mediumfont = font; /* Peach */ mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF); /* Aqua */ mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue); /* Yellow */ mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen); /* Green */ mkcol(3, DPalegreen, DMedgreen, DDarkgreen); /* Blue */ mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF); /* Grey */ cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF); cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF); cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 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+mediumfont->height-Ysqueeze > maxy) break; w = chartorune(r, s); s += w; w = runestringwidth(mediumfont, r); if(w > maxw) maxw = w; runestring(screen, p, display->black, ZP, mediumfont, r); p.y += mediumfont->height-Ysqueeze; }}Pointparitypt(int x){ return Pt(x+parity, 0);}Pointdatapoint(Graph *g, int x, ulong v, ulong 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.; } } 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, ulong prev, ulong v, ulong 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, ulong 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, ulong v, ulong 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, "%lud", v); string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, buf); }}/* read one line of text from buffer and process integers */intreadnums(Machine *m, int n, ulong *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 && !isdigit(*p) && *p!='-') p++; if(p == ep) break; a[i] = strtoul(p, &p, 10); } if(ep < m->ebufp) ep++; m->bufp = ep; return i == n;}/* Network on fd1, mount driver on fd0 */static intfilter(int fd){ int p[2]; if(pipe(p) < 0){ fprint(2, "stats: can't pipe: %r\n"); killall("pipe"); } switch(rfork(RFNOWAIT|RFPROC|RFFDG)) { case -1: sysfatal("rfork record module"); case 0: dup(fd, 1); close(fd); dup(p[0], 0); close(p[0]); close(p[1]); execl("/bin/aux/fcall", "fcall", nil); fprint(2, "stats: can't exec fcall: %r\n"); killall("fcall"); default: close(fd); close(p[0]); } return p[1]; }/* * 9fs */intconnect9fs(char *addr){ char dir[256], *na; int fd; fprint(2, "connect9fs..."); na = netmkaddr(addr, 0, "9fs"); fprint(2, "dial %s...", na); if((fd = dial(na, 0, dir, 0)) < 0) return -1; fprint(2, "dir %s...", dir);// if(strstr(dir, "tcp"))// fd = filter(fd); return fd;}intold9p(int fd){ int p[2]; if(pipe(p) < 0) return -1; switch(rfork(RFPROC|RFFDG|RFNAMEG)) { case -1: return -1; case 0: if(fd != 1){ dup(fd, 1); close(fd); } if(p[0] != 0){ dup(p[0], 0); close(p[0]); } close(p[1]); if(0){ fd = open("/sys/log/cpu", OWRITE); if(fd != 2){ dup(fd, 2); close(fd); } execl("/bin/srvold9p", "srvold9p", "-ds", nil); } else execl("/bin/srvold9p", "srvold9p", "-s", nil); return -1; default: close(fd); close(p[0]); } return p[1]; }/* * exportfs */int connectexportfs(char *addr){ char buf[ERRMAX], dir[256], *na; int fd, n; char *tree; AuthInfo *ai; tree = "/"; na = netmkaddr(addr, 0, "exportfs"); if((fd = dial(na, 0, dir, 0)) < 0) return -1; ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client"); if(ai == nil) return -1; n = write(fd, tree, strlen(tree)); if(n < 0){ close(fd); return -1; } strcpy(buf, "can't read tree"); n = read(fd, buf, sizeof buf - 1); if(n!=2 || buf[0]!='O' || buf[1]!='K'){ buf[sizeof buf - 1] = '\0'; werrstr("bad remote tree: %s\n", buf); close(fd); return -1; }// if(strstr(dir, "tcp"))// fd = filter(fd); if(oldsystem) return old9p(fd); return fd;}intreadswap(Machine *m, ulong *a){ if(strstr(m->buf, "memory\n")){ /* new /dev/swap - skip first 3 numbers */ if(!readnums(m, 7, a, 1)) return 0; a[0] = a[3]; a[1] = a[4]; a[2] = a[5]; a[3] = a[6]; return 1; } return readnums(m, nelem(m->devswap), a, 0);}intinitmach(Machine *m, char *name){ int n, fd; ulong a[MAXNUM]; char *p, mpt[256], buf[256]; p = strchr(name, '!'); if(p) p++; else p = name; m->name = estrdup(p); m->remote = (strcmp(p, mysysname) != 0); if(m->remote == 0) strcpy(mpt, ""); else{ snprint(mpt, sizeof mpt, "/n/%s", p); fd = connectexportfs(name); if(fd < 0){ fprint(2, "can't connect to %s: %r\n", name); return 0; } /* BUG? need to use amount() now? */ if(mount(fd, -1, mpt, MREPL, "") < 0){ fprint(2, "stats: mount %s on %s failed (%r); trying /n/sid\n", name, mpt); strcpy(mpt, "/n/sid"); if(mount(fd, -1, mpt, MREPL, "") < 0){ fprint(2, "stats: mount %s on %s failed: %r\n", name, mpt); return 0; } } } snprint(buf, sizeof buf, "%s/dev/swap", mpt); m->swapfd = open(buf, OREAD); if(loadbuf(m, &m->swapfd) && readswap(m, a)) memmove(m->devswap, a, sizeof m->devswap); else m->devswap[Maxmem] = m->devswap[Maxswap] = 100; snprint(buf, sizeof buf, "%s/dev/sysstat", mpt); m->statsfd = open(buf, OREAD); if(loadbuf(m, &m->statsfd)){ for(n=0; readnums(m, nelem(m->devsysstat), a, 0); n++) ; m->nproc = n; }else m->nproc = 1; snprint(buf, sizeof buf, "%s/net/ether0/stats", mpt); m->etherfd = open(buf, OREAD); if(loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1)) memmove(m->netetherstats, a, sizeof m->netetherstats); snprint(buf, sizeof buf, "%s/net/ether0/ifstats", mpt); m->ifstatsfd = open(buf, OREAD); if(loadbuf(m, &m->ifstatsfd)){ /* need to check that this is a wavelan interface */ if(strncmp(m->buf, "Signal: ", 8) == 0 && readnums(m, nelem(m->netetherifstats), a, 1)) memmove(m->netetherifstats, a, sizeof m->netetherifstats); } snprint(buf, sizeof buf, "%s/mnt/apm/battery", mpt); m->batteryfd = open(buf, OREAD); m->bitsybatfd = -1; if(m->batteryfd >= 0){ if(loadbuf(m, &m->batteryfd) && readnums(m, nelem(m->batterystats), a, 0)) memmove(m->batterystats, a, sizeof(m->batterystats)); }else{ snprint(buf, sizeof buf, "%s/dev/battery", mpt); m->bitsybatfd = open(buf, OREAD); if(loadbuf(m, &m->bitsybatfd) && readnums(m, 1, a, 0)) memmove(m->batterystats, a, sizeof(m->batterystats)); } return 1;}jmp_buf catchalarm;voidalarmed(void *a, char *s){ if(strcmp(s, "alarm") == 0) notejmp(a, catchalarm, 1); noted(NDFLT);}intneedswap(int init)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -