1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063 |
- #include <u.h>
- #include <libc.h>
- #include <ctype.h>
- #include <auth.h>
- #include <fcall.h>
- #include <draw.h>
- #include <event.h>
- #include <ip.h>
- #include "icmp.h"
- #define MAXNUM 8 /* maximum number of numbers on data line */
- typedef struct Graph Graph;
- typedef struct Machine Machine;
- typedef struct Req Req;
- enum {
- Gmsglen = 16,
- };
- struct Graph
- {
- int colindex;
- Rectangle r;
- long *data;
- int ndata;
- char *label;
- void (*newvalue)(Machine*, long*, long*, long*);
- void (*update)(Graph*, long, long, long);
- Machine *mach;
- int overflow;
- Image *overtmp;
- int overtmplen;
- char msg[Gmsglen];
- int cursor;
- int vmax;
- };
- enum
- {
- MSGLEN = 64,
- Rttmax = 50,
- };
- struct Req
- {
- int seq; /* sequence number */
- vlong time; /* time sent */
- // int rtt;
- Req *next;
- };
- struct Machine
- {
- Lock;
- char *name;
- int pingfd;
- int nproc;
- int rttmsgs;
- ulong rttsum;
- ulong lastrtt;
- int lostmsgs;
- int rcvdmsgs;
- ulong lostavg;
- int unreachable;
- ushort seq;
- Req *first;
- Req *last;
- Req *rcvd;
- char buf[1024];
- char *bufp;
- char *ebufp;
- };
- 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 ") */
- NPROC = 128,
- NMACH = 32,
- };
- enum Menu2
- {
- Mrtt,
- Mlost,
- Nmenu2,
- };
- char *menu2str[Nmenu2+1] = {
- "add sec rtt",
- "add % lost ",
- nil,
- };
- void rttval(Machine*, long*, long*, long*);
- void lostval(Machine*, long*, long*, long*);
- Menu menu2 = {menu2str, nil};
- int present[Nmenu2];
- void (*newvaluefn[Nmenu2])(Machine*, long*, long*, long*) = {
- rttval,
- lostval,
- };
- Image *cols[Ncolor][3];
- Graph *graph;
- Machine mach[NMACH];
- Font *mediumfont;
- int pids[NPROC];
- int npid;
- int parity; /* toggled to avoid patterns in textured background */
- int nmach;
- int ngraph; /* totaly number is ngraph*nmach */
- long starttime;
- int pinginterval;
- void dropgraph(int);
- void addgraph(int);
- void startproc(void (*)(void*), void*);
- void resize(void);
- long rttscale(long);
- int which2index(int);
- int index2which(int);
- 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, "%s: out of memory allocating %ld: %r\n", argv0, sz);
- killall("mem");
- }
- memset(v, 0, sz);
- return v;
- }
- void*
- erealloc(void *v, ulong sz)
- {
- v = realloc(v, sz);
- if(v == nil) {
- fprint(2, "%s: out of memory reallocating %ld: %r\n", argv0, sz);
- killall("mem");
- }
- return v;
- }
- char*
- estrdup(char *s)
- {
- char *t;
- if((t = strdup(s)) == nil) {
- fprint(2, "%s: out of memory in strdup(%.10s): %r\n", argv0, s);
- killall("mem");
- }
- return t;
- }
- void
- mkcol(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);
- }
- void
- colinit(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);
- }
- 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);
- if(n <= 0){
- close(*fd);
- *fd = -1;
- return 0;
- }
- m->bufp = m->buf;
- m->ebufp = m->buf+n;
- 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+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;
- }
- }
- void
- hashmark(Point p, int dy, long v, long vmax, char *label)
- {
- int y;
- int x;
- x = p.x + Labspace;
- y = p.y + (dy*(vmax-v))/vmax;
- draw(screen, Rect(p.x, y-1, p.x+Labspace, y+1), display->black, nil, ZP);
- if(dy > 5*mediumfont->height)
- string(screen, Pt(x, y-mediumfont->height/2),
- display->black, ZP, mediumfont, label);
- }
- void
- hashmarks(Point p, int dy, int which)
- {
- switch(index2which(which)){
- case Mrtt:
- hashmark(p, dy, rttscale(1000000), Rttmax, "1.");
- hashmark(p, dy, rttscale(100000), Rttmax, "0.1");
- hashmark(p, dy, rttscale(10000), Rttmax, "0.01");
- hashmark(p, dy, rttscale(1000), Rttmax, "0.001");
- break;
- case Mlost:
- hashmark(p, dy, 75, 100, " 75%");
- hashmark(p, dy, 50, 100, " 50%");
- hashmark(p, dy, 25, 100, " 25%");
- break;
- }
- }
- Point
- paritypt(int x)
- {
- return Pt(x+parity, 0);
- }
- Point
- datapoint(Graph *g, int x, long v, long vmax)
- {
- Point p;
- p.x = x;
- p.y = g->r.max.y - Dy(g->r)*v/vmax - 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, long prev, long v, long 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);
- }
- g->vmax = vmax;
- }
- void
- drawmark(Graph *g, int x)
- {
- int c;
- c = (g->colindex+1)&Ncolor;
- draw(screen, Rect(x, g->r.min.y, x+1, g->r.max.y), cols[c][2], nil, ZP);
- }
- void
- redraw(Graph *g, int 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);
- }
- void
- clearmsg(Graph *g)
- {
- if(g->overtmp != nil)
- draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min);
- g->overflow = 0;
- }
- void
- drawmsg(Graph *g, char *msg)
- {
- if(g->overtmp == nil)
- return;
- /* save previous contents of screen */
- draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
- /* draw message */
- if(strlen(msg) > g->overtmplen)
- msg[g->overtmplen] = 0;
- string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, msg);
- }
- void
- clearcursor(Graph *g)
- {
- int x;
- long prev;
- if(g->overtmp == nil)
- return;
- if(g->cursor > 0 && g->cursor < g->ndata){
- x = g->r.max.x - g->cursor;
- prev = 0;
- if(g->cursor > 0)
- prev = g->data[g->cursor-1];
- drawdatum(g, x, prev, g->data[g->cursor], g->vmax);
- g->cursor = -1;
- }
- }
- void
- drawcursor(Graph *g, int x)
- {
- if(g->overtmp == nil)
- return;
- draw(screen, Rect(x, g->r.min.y, x+1, g->r.max.y), cols[g->colindex][2], nil, ZP);
- }
- void
- update1(Graph *g, long v, long vmax, long mark)
- {
- char buf[Gmsglen];
- /* put back screen value sans message */
- if(g->overflow || *g->msg){
- clearmsg(g);
- g->overflow = 0;
- }
- 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);
- if(mark)
- drawmark(g, g->r.max.x-1);
- memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0]));
- g->data[0] = v;
- if(v>vmax){
- g->overflow = 1;
- sprint(buf, "%ld", v);
- drawmsg(g, buf);
- } else if(*g->msg)
- drawmsg(g, g->msg);
- if(g->cursor >= 0){
- g->cursor++;
- if(g->cursor >= g->ndata){
- g->cursor = -1;
- if(*g->msg){
- clearmsg(g);
- *g->msg = 0;
- }
- }
- }
- }
- void
- pinglost(Machine *m, Req*)
- {
- m->lostmsgs++;
- }
- void
- pingreply(Machine *m, Req *r)
- {
- ulong x;
- x = r->time/1000LL;
- m->rttsum += x;
- m->rcvdmsgs++;
- m->rttmsgs++;
- }
- void
- pingclean(Machine *m, ushort seq, vlong now, int)
- {
- Req **l, *r;
- vlong x, y;
- y = 10LL*1000000000LL;
- for(l = &m->first; *l; ){
- r = *l;
- x = now - r->time;
- if(x > y || r->seq == seq){
- *l = r->next;
- r->time = x;
- if(r->seq != seq)
- pinglost(m, r);
- else
- pingreply(m, r);
- free(r);
- } else
- l = &(r->next);
- }
- }
- /* IPv4 only */
- void
- pingsend(Machine *m)
- {
- int i;
- char buf[128], err[ERRMAX];
- Icmphdr *ip;
- Req *r;
- ip = (Icmphdr *)(buf + IPV4HDR_LEN);
- memset(buf, 0, sizeof buf);
- r = malloc(sizeof *r);
- if(r == nil)
- return;
- for(i = 32; i < MSGLEN; i++)
- buf[i] = i;
- ip->type = EchoRequest;
- ip->code = 0;
- ip->seq[0] = m->seq;
- ip->seq[1] = m->seq>>8;
- r->seq = m->seq;
- r->next = nil;
- lock(m);
- pingclean(m, -1, nsec(), 0);
- if(m->first == nil)
- m->first = r;
- else
- m->last->next = r;
- m->last = r;
- r->time = nsec();
- unlock(m);
- if(write(m->pingfd, buf, MSGLEN) < MSGLEN){
- errstr(err, sizeof err);
- if(strstr(err, "unreach")||strstr(err, "exceed"))
- m->unreachable++;
- }
- m->seq++;
- }
- /* IPv4 only */
- void
- pingrcv(void *arg)
- {
- int i, n, fd;
- uchar buf[512];
- ushort x;
- vlong now;
- Icmphdr *ip;
- Ip4hdr *ip4;
- Machine *m = arg;
- ip4 = (Ip4hdr *)buf;
- ip = (Icmphdr *)(buf + IPV4HDR_LEN);
- fd = dup(m->pingfd, -1);
- for(;;){
- n = read(fd, buf, sizeof(buf));
- now = nsec();
- if(n <= 0)
- continue;
- if(n < MSGLEN){
- print("bad len %d/%d\n", n, MSGLEN);
- continue;
- }
- for(i = 32; i < MSGLEN; i++)
- if(buf[i] != (i&0xff))
- continue;
- x = (ip->seq[1]<<8) | ip->seq[0];
- if(ip->type != EchoReply || ip->code != 0)
- continue;
- lock(m);
- pingclean(m, x, now, ip4->ttl);
- unlock(m);
- }
- }
- void
- initmach(Machine *m, char *name)
- {
- char *p;
- srand(time(0));
- p = strchr(name, '!');
- if(p){
- p++;
- m->name = estrdup(p+1);
- }else
- p = name;
- m->name = estrdup(p);
- m->nproc = 1;
- m->pingfd = dial(netmkaddr(m->name, "icmp", "1"), 0, 0, 0);
- if(m->pingfd < 0)
- sysfatal("dialing %s: %r", m->name);
- startproc(pingrcv, m);
- }
- long
- rttscale(long x)
- {
- if(x == 0)
- return 0;
- x = 10.0*log10(x) - 20.0;
- if(x < 0)
- x = 0;
- return x;
- }
- double
- rttunscale(long x)
- {
- double dx;
- x += 20;
- dx = x;
- return pow(10.0, dx/10.0);
- }
- void
- rttval(Machine *m, long *v, long *vmax, long *mark)
- {
- ulong x;
- if(m->rttmsgs == 0){
- x = m->lastrtt;
- } else {
- x = m->rttsum/m->rttmsgs;
- m->rttsum = m->rttmsgs = 0;
- m->lastrtt = x;
- }
- *v = rttscale(x);
- *vmax = Rttmax;
- *mark = 0;
- }
- void
- lostval(Machine *m, long *v, long *vmax, long *mark)
- {
- ulong x;
- if(m->rcvdmsgs+m->lostmsgs > 0)
- x = (m->lostavg>>1) + (((m->lostmsgs*100)/(m->lostmsgs + m->rcvdmsgs))>>1);
- else
- x = m->lostavg;
- m->lostavg = x;
- m->lostmsgs = m->rcvdmsgs = 0;
- if(m->unreachable){
- m->unreachable = 0;
- *mark = 100;
- } else
- *mark = 0;
- *v = x;
- *vmax = 100;
- }
- jmp_buf catchalarm;
- void
- alarmed(void *a, char *s)
- {
- if(strcmp(s, "alarm") == 0)
- notejmp(a, catchalarm, 1);
- noted(NDFLT);
- }
- void
- usage(void)
- {
- fprint(2, "usage: %s machine [machine...]\n", argv0);
- exits("usage");
- }
- void
- addgraph(int n)
- {
- Graph *g, *ograph;
- int i, j;
- static int nadd;
- if(n > nelem(menu2str))
- abort();
- /* avoid two adjacent graphs of same color */
- if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor)
- nadd++;
- ograph = graph;
- graph = emalloc(nmach*(ngraph+1)*sizeof(Graph));
- for(i=0; i<nmach; i++)
- for(j=0; j<ngraph; j++)
- graph[i*(ngraph+1)+j] = ograph[i*ngraph+j];
- free(ograph);
- ngraph++;
- for(i=0; i<nmach; i++){
- g = &graph[i*ngraph+(ngraph-1)];
- memset(g, 0, sizeof(Graph));
- g->label = menu2str[n]+Opwid;
- g->newvalue = newvaluefn[n];
- g->update = update1; /* no other update functions yet */
- g->mach = &mach[i];
- g->colindex = nadd%Ncolor;
- }
- present[n] = 1;
- nadd++;
- }
- int
- which2index(int which)
- {
- int i, n;
- n = -1;
- for(i=0; i<ngraph; i++){
- if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){
- n = i;
- break;
- }
- }
- if(n < 0){
- fprint(2, "%s: internal error can't drop graph\n", argv0);
- killall("error");
- }
- return n;
- }
- int
- index2which(int index)
- {
- int i, n;
- n = -1;
- for(i=0; i<Nmenu2; i++){
- if(strcmp(menu2str[i]+Opwid, graph[index].label) == 0){
- n = i;
- break;
- }
- }
- if(n < 0){
- fprint(2, "%s: internal error can't identify graph\n", argv0);
- killall("error");
- }
- return n;
- }
- void
- dropgraph(int which)
- {
- Graph *ograph;
- int i, j, n;
- if(which > nelem(menu2str))
- abort();
- /* convert n to index in graph table */
- n = which2index(which);
- ograph = graph;
- graph = emalloc(nmach*(ngraph-1)*sizeof(Graph));
- for(i=0; i<nmach; i++){
- for(j=0; j<n; j++)
- graph[i*(ngraph-1)+j] = ograph[i*ngraph+j];
- free(ograph[i*ngraph+j].data);
- freeimage(ograph[i*ngraph+j].overtmp);
- for(j++; j<ngraph; j++)
- graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j];
- }
- free(ograph);
- ngraph--;
- present[which] = 0;
- }
- void
- addmachine(char *name)
- {
- if(ngraph > 0){
- fprint(2, "%s: internal error: ngraph>0 in addmachine()\n", argv0);
- usage();
- }
- if(nmach == NMACH)
- sysfatal("too many machines");
- initmach(&mach[nmach++], name);
- }
- void
- resize(void)
- {
- int i, j, n, startx, starty, x, y, dx, dy, hashdx, ondata;
- Graph *g;
- Rectangle machr, r;
- long v, vmax, mark;
- char buf[128];
- draw(screen, screen->r, display->white, nil, ZP);
- /* label left edge */
- x = screen->r.min.x;
- y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
- dy = (screen->r.max.y - y)/ngraph;
- dx = Labspace+stringwidth(mediumfont, "0")+Labspace;
- startx = x+dx+1;
- starty = y;
- for(i=0; i<ngraph; i++,y+=dy){
- draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
- draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
- label(Pt(x, y), dy, graph[i].label);
- draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
- }
- /* label right edge */
- dx = Labspace+stringwidth(mediumfont, "0.001")+Labspace;
- hashdx = dx;
- x = screen->r.max.x - dx;
- y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
- for(i=0; i<ngraph; i++,y+=dy){
- draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
- draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
- hashmarks(Pt(x, y), dy, i);
- draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
- }
- /* label top edge */
- dx = (screen->r.max.x - dx - startx)/nmach;
- for(x=startx, i=0; i<nmach; i++,x+=dx){
- draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
- j = dx/stringwidth(mediumfont, "0");
- n = mach[i].nproc;
- if(n>1 && j>=1+3+(n>10)+(n>100)){ /* first char of name + (n) */
- j -= 3+(n>10)+(n>100);
- if(j <= 0)
- j = 1;
- snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n);
- }else
- snprint(buf, sizeof buf, "%.*s", j, mach[i].name);
- string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP,
- mediumfont, buf);
- }
- /* draw last vertical line */
- draw(screen,
- Rect(screen->r.max.x-hashdx-1, starty-1, screen->r.max.x-hashdx, screen->r.max.y),
- display->black, nil, ZP);
- /* create graphs */
- for(i=0; i<nmach; i++){
- machr = Rect(startx+i*dx, starty, screen->r.max.x, screen->r.max.y);
- if(i < nmach-1)
- machr.max.x = startx+(i+1)*dx - 1;
- else
- machr.max.x = screen->r.max.x - hashdx - 1;
- y = starty;
- for(j=0; j<ngraph; j++, y+=dy){
- g = &graph[i*ngraph+j];
- /* allocate data */
- ondata = g->ndata;
- g->ndata = Dx(machr)+1; /* may be too many if label will be drawn here; so what? */
- g->data = erealloc(g->data, g->ndata*sizeof(long));
- if(g->ndata > ondata)
- memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(long));
- /* set geometry */
- g->r = machr;
- g->r.min.y = y;
- g->r.max.y = y+dy - 1;
- if(j == ngraph-1)
- g->r.max.y = screen->r.max.y;
- draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x));
- g->overflow = 0;
- *g->msg = 0;
- freeimage(g->overtmp);
- g->overtmp = nil;
- g->overtmplen = 0;
- r = g->r;
- r.max.y = r.min.y+mediumfont->height;
- n = (g->r.max.x - r.min.x)/stringwidth(mediumfont, "9");
- if(n > 4){
- if(n > Gmsglen)
- n = Gmsglen;
- r.max.x = r.min.x+stringwidth(mediumfont, "9")*n;
- g->overtmplen = n;
- g->overtmp = allocimage(display, r, screen->chan, 0, -1);
- }
- g->newvalue(g->mach, &v, &vmax, &mark);
- redraw(g, vmax);
- }
- }
- flushimage(display, 1);
- }
- void
- eresized(int new)
- {
- lockdisplay(display);
- if(new && getwindow(display, Refnone) < 0) {
- fprint(2, "%s: can't reattach to window\n", argv0);
- killall("reattach");
- }
- resize();
- unlockdisplay(display);
- }
- void
- dobutton2(Mouse *m)
- {
- int i;
- for(i=0; i<Nmenu2; i++)
- if(present[i])
- memmove(menu2str[i], "drop ", Opwid);
- else
- memmove(menu2str[i], "add ", Opwid);
- i = emenuhit(3, m, &menu2);
- if(i >= 0){
- if(!present[i])
- addgraph(i);
- else if(ngraph > 1)
- dropgraph(i);
- resize();
- }
- }
- void
- dobutton1(Mouse *m)
- {
- int i, n, dx, dt;
- Graph *g;
- char *e;
- double f;
- for(i = 0; i < ngraph*nmach; i++){
- if(ptinrect(m->xy, graph[i].r))
- break;
- }
- if(i == ngraph*nmach)
- return;
- g = &graph[i];
- if(g->overtmp == nil)
- return;
- /* clear any previous message and cursor */
- if(g->overflow || *g->msg){
- clearmsg(g);
- *g->msg = 0;
- clearcursor(g);
- }
- dx = g->r.max.x - m->xy.x;
- g->cursor = dx;
- dt = dx*pinginterval;
- e = &g->msg[sizeof(g->msg)];
- seprint(g->msg, e, "%s", ctime(starttime-dt/1000)+11);
- g->msg[8] = 0;
- n = 8;
- switch(index2which(i)){
- case Mrtt:
- f = rttunscale(g->data[dx]);
- seprint(g->msg+n, e, " %3.3g", f/1000000);
- break;
- case Mlost:
- seprint(g->msg+n, e, " %ld%%", g->data[dx]);
- break;
- }
- drawmsg(g, g->msg);
- drawcursor(g, m->xy.x);
- }
- void
- mouseproc(void*)
- {
- Mouse mouse;
- for(;;){
- mouse = emouse();
- if(mouse.buttons == 4){
- lockdisplay(display);
- dobutton2(&mouse);
- unlockdisplay(display);
- } else if(mouse.buttons == 1){
- lockdisplay(display);
- dobutton1(&mouse);
- unlockdisplay(display);
- }
- }
- }
- void
- startproc(void (*f)(void*), void *arg)
- {
- int pid;
- switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
- case -1:
- fprint(2, "%s: fork failed: %r\n", argv0);
- killall("fork failed");
- case 0:
- f(arg);
- killall("process died");
- exits(nil);
- }
- pids[npid++] = pid;
- }
- void
- main(int argc, char *argv[])
- {
- int i, j;
- long v, vmax, mark;
- char flags[10], *f, *p;
- fmtinstall('V', eipfmt);
- f = flags;
- pinginterval = 5000; /* 5 seconds */
- ARGBEGIN{
- case 'i':
- p = ARGF();
- if(p == nil)
- usage();
- pinginterval = atoi(p);
- break;
- default:
- if(f - flags >= sizeof(flags)-1)
- usage();
- *f++ = ARGC();
- break;
- }ARGEND
- *f = 0;
- for(i=0; i<argc; i++)
- addmachine(argv[i]);
- for(f = flags; *f; f++)
- switch(*f){
- case 'l':
- addgraph(Mlost);
- break;
- case 'r':
- addgraph(Mrtt);
- break;
- }
- if(nmach == 0)
- usage();
- if(ngraph == 0)
- addgraph(Mrtt);
- for(i=0; i<nmach; i++)
- for(j=0; j<ngraph; j++)
- graph[i*ngraph+j].mach = &mach[i];
- if(initdraw(nil, nil, argv0) < 0){
- fprint(2, "%s: initdraw failed: %r\n", argv0);
- exits("initdraw");
- }
- colinit();
- einit(Emouse);
- notify(nil);
- startproc(mouseproc, 0);
- display->locking = 1; /* tell library we're using the display lock */
- resize();
- starttime = time(0);
- unlockdisplay(display); /* display is still locked from initdraw() */
- for(j = 0; ; j++){
- lockdisplay(display);
- if(j == nmach){
- parity = 1-parity;
- j = 0;
- for(i=0; i<nmach*ngraph; i++){
- graph[i].newvalue(graph[i].mach, &v, &vmax, &mark);
- graph[i].update(&graph[i], v, vmax, mark);
- }
- starttime = time(0);
- }
- flushimage(display, 1);
- unlockdisplay(display);
- pingsend(&mach[j%nmach]);
- sleep(pinginterval/nmach);
- }
- }
|