xref: /plan9/sys/src/cmd/ip/gping.c (revision 94aa1c4c0955b2b4e990c9f4679be8e9f67a469b)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <ctype.h>
47dd7cddfSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include <fcall.h>
67dd7cddfSDavid du Colombier #include <draw.h>
77dd7cddfSDavid du Colombier #include <event.h>
87dd7cddfSDavid du Colombier #include <ip.h>
95a354e27SDavid du Colombier #include "icmp.h"
107dd7cddfSDavid du Colombier 
117dd7cddfSDavid du Colombier #define	MAXNUM	8	/* maximum number of numbers on data line */
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier typedef struct Graph	Graph;
147dd7cddfSDavid du Colombier typedef struct Machine	Machine;
157dd7cddfSDavid du Colombier typedef struct Req	Req;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier enum {
187dd7cddfSDavid du Colombier 	Gmsglen	= 16,
197dd7cddfSDavid du Colombier };
207dd7cddfSDavid du Colombier 
217dd7cddfSDavid du Colombier struct Graph
227dd7cddfSDavid du Colombier {
237dd7cddfSDavid du Colombier 	int		colindex;
247dd7cddfSDavid du Colombier 	Rectangle	r;
25c93608ccSDavid du Colombier 	long		*data;
267dd7cddfSDavid du Colombier 	int		ndata;
277dd7cddfSDavid du Colombier 	char		*label;
287dd7cddfSDavid du Colombier 	void		(*newvalue)(Machine*, long*, long*, long*);
297dd7cddfSDavid du Colombier 	void		(*update)(Graph*, long, long, long);
307dd7cddfSDavid du Colombier 	Machine		*mach;
317dd7cddfSDavid du Colombier 	int		overflow;
327dd7cddfSDavid du Colombier 	Image		*overtmp;
337dd7cddfSDavid du Colombier 	int		overtmplen;
347dd7cddfSDavid du Colombier 	char		msg[Gmsglen];
357dd7cddfSDavid du Colombier 	int		cursor;
367dd7cddfSDavid du Colombier 	int		vmax;
377dd7cddfSDavid du Colombier };
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier enum
405a354e27SDavid du Colombier {
417dd7cddfSDavid du Colombier 	MSGLEN		= 64,
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier 	Rttmax		= 50,
447dd7cddfSDavid du Colombier };
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier struct Req
477dd7cddfSDavid du Colombier {
485a354e27SDavid du Colombier 	int	seq;	/* sequence number */
495a354e27SDavid du Colombier 	vlong	time;	/* time sent */
50*94aa1c4cSDavid du Colombier //	int	rtt;
517dd7cddfSDavid du Colombier 	Req	*next;
527dd7cddfSDavid du Colombier };
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier struct Machine
557dd7cddfSDavid du Colombier {
567dd7cddfSDavid du Colombier 	Lock;
577dd7cddfSDavid du Colombier 	char	*name;
587dd7cddfSDavid du Colombier 	int	pingfd;
597dd7cddfSDavid du Colombier 	int	nproc;
607dd7cddfSDavid du Colombier 
617dd7cddfSDavid du Colombier 	int	rttmsgs;
627dd7cddfSDavid du Colombier 	ulong	rttsum;
637dd7cddfSDavid du Colombier 	ulong	lastrtt;
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier 	int	lostmsgs;
667dd7cddfSDavid du Colombier 	int	rcvdmsgs;
677dd7cddfSDavid du Colombier 	ulong	lostavg;
687dd7cddfSDavid du Colombier 	int	unreachable;
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier 	ushort	seq;
717dd7cddfSDavid du Colombier 	Req	*first;
727dd7cddfSDavid du Colombier 	Req	*last;
737dd7cddfSDavid du Colombier 	Req	*rcvd;
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier 	char	buf[1024];
767dd7cddfSDavid du Colombier 	char	*bufp;
777dd7cddfSDavid du Colombier 	char	*ebufp;
787dd7cddfSDavid du Colombier };
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier enum
817dd7cddfSDavid du Colombier {
827dd7cddfSDavid du Colombier 	Ncolor		= 6,
837dd7cddfSDavid du Colombier 	Ysqueeze	= 2,	/* vertical squeezing of label text */
847dd7cddfSDavid du Colombier 	Labspace	= 2,	/* room around label */
857dd7cddfSDavid du Colombier 	Dot		= 2,	/* height of dot */
867dd7cddfSDavid du Colombier 	Opwid		= 5,	/* strlen("add  ") or strlen("drop ") */
877dd7cddfSDavid du Colombier 	NPROC		= 128,
887dd7cddfSDavid du Colombier 	NMACH		= 32,
897dd7cddfSDavid du Colombier };
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier enum Menu2
927dd7cddfSDavid du Colombier {
937dd7cddfSDavid du Colombier 	Mrtt,
947dd7cddfSDavid du Colombier 	Mlost,
957dd7cddfSDavid du Colombier 	Nmenu2,
967dd7cddfSDavid du Colombier };
977dd7cddfSDavid du Colombier 
987dd7cddfSDavid du Colombier char	*menu2str[Nmenu2+1] = {
997dd7cddfSDavid du Colombier 	"add  sec rtt",
1007dd7cddfSDavid du Colombier 	"add  % lost ",
1017dd7cddfSDavid du Colombier 	nil,
1027dd7cddfSDavid du Colombier };
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier 
1057dd7cddfSDavid du Colombier void	rttval(Machine*, long*, long*, long*);
1067dd7cddfSDavid du Colombier void	lostval(Machine*, long*, long*, long*);
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier Menu	menu2 = {menu2str, nil};
1097dd7cddfSDavid du Colombier int		present[Nmenu2];
1107dd7cddfSDavid du Colombier void		(*newvaluefn[Nmenu2])(Machine*, long*, long*, long*) = {
1117dd7cddfSDavid du Colombier 	rttval,
1127dd7cddfSDavid du Colombier 	lostval,
1137dd7cddfSDavid du Colombier };
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier Image		*cols[Ncolor][3];
1167dd7cddfSDavid du Colombier Graph		*graph;
1177dd7cddfSDavid du Colombier Machine		mach[NMACH];
1187dd7cddfSDavid du Colombier Font		*mediumfont;
1197dd7cddfSDavid du Colombier int		pids[NPROC];
1207dd7cddfSDavid du Colombier int		npid;
1217dd7cddfSDavid du Colombier int 		parity;	/* toggled to avoid patterns in textured background */
1227dd7cddfSDavid du Colombier int		nmach;
1237dd7cddfSDavid du Colombier int		ngraph;	/* totaly number is ngraph*nmach */
1247dd7cddfSDavid du Colombier long		starttime;
1257dd7cddfSDavid du Colombier int		pinginterval;
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier void	dropgraph(int);
1287dd7cddfSDavid du Colombier void	addgraph(int);
1297dd7cddfSDavid du Colombier void	startproc(void (*)(void*), void*);
1307dd7cddfSDavid du Colombier void	resize(void);
131c93608ccSDavid du Colombier long	rttscale(long);
1327dd7cddfSDavid du Colombier int	which2index(int);
1337dd7cddfSDavid du Colombier int	index2which(int);
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier void
killall(char * s)1367dd7cddfSDavid du Colombier killall(char *s)
1377dd7cddfSDavid du Colombier {
1387dd7cddfSDavid du Colombier 	int i, pid;
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier 	pid = getpid();
1417dd7cddfSDavid du Colombier 	for(i=0; i<NPROC; i++)
1427dd7cddfSDavid du Colombier 		if(pids[i] && pids[i]!=pid)
1437dd7cddfSDavid du Colombier 			postnote(PNPROC, pids[i], "kill");
1447dd7cddfSDavid du Colombier 	exits(s);
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier void*
emalloc(ulong sz)1487dd7cddfSDavid du Colombier emalloc(ulong sz)
1497dd7cddfSDavid du Colombier {
1507dd7cddfSDavid du Colombier 	void *v;
1517dd7cddfSDavid du Colombier 	v = malloc(sz);
1527dd7cddfSDavid du Colombier 	if(v == nil) {
1537dd7cddfSDavid du Colombier 		fprint(2, "%s: out of memory allocating %ld: %r\n", argv0, sz);
1547dd7cddfSDavid du Colombier 		killall("mem");
1557dd7cddfSDavid du Colombier 	}
1567dd7cddfSDavid du Colombier 	memset(v, 0, sz);
1577dd7cddfSDavid du Colombier 	return v;
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier 
1607dd7cddfSDavid du Colombier void*
erealloc(void * v,ulong sz)1617dd7cddfSDavid du Colombier erealloc(void *v, ulong sz)
1627dd7cddfSDavid du Colombier {
1637dd7cddfSDavid du Colombier 	v = realloc(v, sz);
1647dd7cddfSDavid du Colombier 	if(v == nil) {
1657dd7cddfSDavid du Colombier 		fprint(2, "%s: out of memory reallocating %ld: %r\n", argv0, sz);
1667dd7cddfSDavid du Colombier 		killall("mem");
1677dd7cddfSDavid du Colombier 	}
1687dd7cddfSDavid du Colombier 	return v;
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier char*
estrdup(char * s)1727dd7cddfSDavid du Colombier estrdup(char *s)
1737dd7cddfSDavid du Colombier {
1747dd7cddfSDavid du Colombier 	char *t;
1757dd7cddfSDavid du Colombier 	if((t = strdup(s)) == nil) {
1767dd7cddfSDavid du Colombier 		fprint(2, "%s: out of memory in strdup(%.10s): %r\n", argv0, s);
1777dd7cddfSDavid du Colombier 		killall("mem");
1787dd7cddfSDavid du Colombier 	}
1797dd7cddfSDavid du Colombier 	return t;
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier void
mkcol(int i,int c0,int c1,int c2)1837dd7cddfSDavid du Colombier mkcol(int i, int c0, int c1, int c2)
1847dd7cddfSDavid du Colombier {
1857dd7cddfSDavid du Colombier 	cols[i][0] = allocimagemix(display, c0, DWhite);
1867dd7cddfSDavid du Colombier 	cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1);
1877dd7cddfSDavid du Colombier 	cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);
1887dd7cddfSDavid du Colombier }
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier void
colinit(void)1917dd7cddfSDavid du Colombier colinit(void)
1927dd7cddfSDavid du Colombier {
1937dd7cddfSDavid du Colombier 	mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
1947dd7cddfSDavid du Colombier 	if(mediumfont == nil)
1957dd7cddfSDavid du Colombier 		mediumfont = font;
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	/* Peach */
1987dd7cddfSDavid du Colombier 	mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
1997dd7cddfSDavid du Colombier 	/* Aqua */
2007dd7cddfSDavid du Colombier 	mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
2017dd7cddfSDavid du Colombier 	/* Yellow */
2027dd7cddfSDavid du Colombier 	mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
2037dd7cddfSDavid du Colombier 	/* Green */
2047dd7cddfSDavid du Colombier 	mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
2057dd7cddfSDavid du Colombier 	/* Blue */
2067dd7cddfSDavid du Colombier 	mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
2077dd7cddfSDavid du Colombier 	/* Grey */
2087dd7cddfSDavid du Colombier 	cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
2097dd7cddfSDavid du Colombier 	cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
2107dd7cddfSDavid du Colombier 	cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
2117dd7cddfSDavid du Colombier }
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier int
loadbuf(Machine * m,int * fd)2147dd7cddfSDavid du Colombier loadbuf(Machine *m, int *fd)
2157dd7cddfSDavid du Colombier {
2167dd7cddfSDavid du Colombier 	int n;
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier 	if(*fd < 0)
2207dd7cddfSDavid du Colombier 		return 0;
2217dd7cddfSDavid du Colombier 	seek(*fd, 0, 0);
2227dd7cddfSDavid du Colombier 	n = read(*fd, m->buf, sizeof m->buf);
2237dd7cddfSDavid du Colombier 	if(n <= 0){
2247dd7cddfSDavid du Colombier 		close(*fd);
2257dd7cddfSDavid du Colombier 		*fd = -1;
2267dd7cddfSDavid du Colombier 		return 0;
2277dd7cddfSDavid du Colombier 	}
2287dd7cddfSDavid du Colombier 	m->bufp = m->buf;
2297dd7cddfSDavid du Colombier 	m->ebufp = m->buf+n;
2307dd7cddfSDavid du Colombier 	return 1;
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier void
label(Point p,int dy,char * text)2347dd7cddfSDavid du Colombier label(Point p, int dy, char *text)
2357dd7cddfSDavid du Colombier {
2367dd7cddfSDavid du Colombier 	char *s;
2377dd7cddfSDavid du Colombier 	Rune r[2];
2387dd7cddfSDavid du Colombier 	int w, maxw, maxy;
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	p.x += Labspace;
2417dd7cddfSDavid du Colombier 	maxy = p.y+dy;
2427dd7cddfSDavid du Colombier 	maxw = 0;
2437dd7cddfSDavid du Colombier 	r[1] = '\0';
2447dd7cddfSDavid du Colombier 	for(s=text; *s; ){
2457dd7cddfSDavid du Colombier 		if(p.y+mediumfont->height-Ysqueeze > maxy)
2467dd7cddfSDavid du Colombier 			break;
2477dd7cddfSDavid du Colombier 		w = chartorune(r, s);
2487dd7cddfSDavid du Colombier 		s += w;
2497dd7cddfSDavid du Colombier 		w = runestringwidth(mediumfont, r);
2507dd7cddfSDavid du Colombier 		if(w > maxw)
2517dd7cddfSDavid du Colombier 			maxw = w;
2527dd7cddfSDavid du Colombier 		runestring(screen, p, display->black, ZP, mediumfont, r);
2537dd7cddfSDavid du Colombier 		p.y += mediumfont->height-Ysqueeze;
2547dd7cddfSDavid du Colombier 	}
2557dd7cddfSDavid du Colombier }
2567dd7cddfSDavid du Colombier 
2577dd7cddfSDavid du Colombier void
hashmark(Point p,int dy,long v,long vmax,char * label)258c93608ccSDavid du Colombier hashmark(Point p, int dy, long v, long vmax, char *label)
2597dd7cddfSDavid du Colombier {
2607dd7cddfSDavid du Colombier 	int y;
2617dd7cddfSDavid du Colombier 	int x;
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier 	x = p.x + Labspace;
2647dd7cddfSDavid du Colombier 	y = p.y + (dy*(vmax-v))/vmax;
2657dd7cddfSDavid du Colombier 	draw(screen, Rect(p.x, y-1, p.x+Labspace, y+1), display->black, nil, ZP);
2667dd7cddfSDavid du Colombier 	if(dy > 5*mediumfont->height)
2677dd7cddfSDavid du Colombier 		string(screen, Pt(x, y-mediumfont->height/2),
2687dd7cddfSDavid du Colombier 			display->black, ZP, mediumfont, label);
2697dd7cddfSDavid du Colombier }
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier void
hashmarks(Point p,int dy,int which)2727dd7cddfSDavid du Colombier hashmarks(Point p, int dy, int which)
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier 	switch(index2which(which)){
2757dd7cddfSDavid du Colombier 	case Mrtt:
2767dd7cddfSDavid du Colombier 		hashmark(p, dy, rttscale(1000000), Rttmax, "1.");
2777dd7cddfSDavid du Colombier 		hashmark(p, dy, rttscale(100000), Rttmax, "0.1");
2787dd7cddfSDavid du Colombier 		hashmark(p, dy, rttscale(10000), Rttmax, "0.01");
2797dd7cddfSDavid du Colombier 		hashmark(p, dy, rttscale(1000), Rttmax, "0.001");
2807dd7cddfSDavid du Colombier 		break;
2817dd7cddfSDavid du Colombier 	case Mlost:
2827dd7cddfSDavid du Colombier 		hashmark(p, dy, 75, 100, " 75%");
2837dd7cddfSDavid du Colombier 		hashmark(p, dy, 50, 100, " 50%");
2847dd7cddfSDavid du Colombier 		hashmark(p, dy, 25, 100, " 25%");
2857dd7cddfSDavid du Colombier 		break;
2867dd7cddfSDavid du Colombier 	}
2877dd7cddfSDavid du Colombier }
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier Point
paritypt(int x)2907dd7cddfSDavid du Colombier paritypt(int x)
2917dd7cddfSDavid du Colombier {
2927dd7cddfSDavid du Colombier 	return Pt(x+parity, 0);
2937dd7cddfSDavid du Colombier }
2947dd7cddfSDavid du Colombier 
2957dd7cddfSDavid du Colombier Point
datapoint(Graph * g,int x,long v,long vmax)2967dd7cddfSDavid du Colombier datapoint(Graph *g, int x, long v, long vmax)
2977dd7cddfSDavid du Colombier {
2987dd7cddfSDavid du Colombier 	Point p;
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier 	p.x = x;
3017dd7cddfSDavid du Colombier 	p.y = g->r.max.y - Dy(g->r)*v/vmax - Dot;
3027dd7cddfSDavid du Colombier 	if(p.y < g->r.min.y)
3037dd7cddfSDavid du Colombier 		p.y = g->r.min.y;
3047dd7cddfSDavid du Colombier 	if(p.y > g->r.max.y-Dot)
3057dd7cddfSDavid du Colombier 		p.y = g->r.max.y-Dot;
3067dd7cddfSDavid du Colombier 	return p;
3077dd7cddfSDavid du Colombier }
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier void
drawdatum(Graph * g,int x,long prev,long v,long vmax)3107dd7cddfSDavid du Colombier drawdatum(Graph *g, int x, long prev, long v, long vmax)
3117dd7cddfSDavid du Colombier {
3127dd7cddfSDavid du Colombier 	int c;
3137dd7cddfSDavid du Colombier 	Point p, q;
3147dd7cddfSDavid du Colombier 
3157dd7cddfSDavid du Colombier 	c = g->colindex;
3167dd7cddfSDavid du Colombier 	p = datapoint(g, x, v, vmax);
3177dd7cddfSDavid du Colombier 	q = datapoint(g, x, prev, vmax);
3187dd7cddfSDavid du Colombier 	if(p.y < q.y){
3197dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x));
3207dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP);
3217dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
3227dd7cddfSDavid du Colombier 	}else{
3237dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x));
3247dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP);
3257dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
3267dd7cddfSDavid du Colombier 	}
3277dd7cddfSDavid du Colombier 	g->vmax = vmax;
3287dd7cddfSDavid du Colombier }
3297dd7cddfSDavid du Colombier 
3307dd7cddfSDavid du Colombier void
drawmark(Graph * g,int x)3317dd7cddfSDavid du Colombier drawmark(Graph *g, int x)
3327dd7cddfSDavid du Colombier {
3337dd7cddfSDavid du Colombier 	int c;
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier 	c = (g->colindex+1)&Ncolor;
3367dd7cddfSDavid du Colombier 	draw(screen, Rect(x, g->r.min.y, x+1, g->r.max.y), cols[c][2], nil, ZP);
3377dd7cddfSDavid du Colombier }
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier void
redraw(Graph * g,int vmax)3407dd7cddfSDavid du Colombier redraw(Graph *g, int vmax)
3417dd7cddfSDavid du Colombier {
3427dd7cddfSDavid du Colombier 	int i, c;
3437dd7cddfSDavid du Colombier 
3447dd7cddfSDavid du Colombier 	c = g->colindex;
3457dd7cddfSDavid du Colombier 	draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x));
3467dd7cddfSDavid du Colombier 	for(i=1; i<Dx(g->r); i++)
3477dd7cddfSDavid du Colombier 		drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax);
3487dd7cddfSDavid du Colombier 	drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax);
3497dd7cddfSDavid du Colombier }
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier void
clearmsg(Graph * g)3527dd7cddfSDavid du Colombier clearmsg(Graph *g)
3537dd7cddfSDavid du Colombier {
3547dd7cddfSDavid du Colombier 	if(g->overtmp != nil)
3557dd7cddfSDavid du Colombier 		draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min);
3567dd7cddfSDavid du Colombier 	g->overflow = 0;
3577dd7cddfSDavid du Colombier }
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier void
drawmsg(Graph * g,char * msg)3607dd7cddfSDavid du Colombier drawmsg(Graph *g, char *msg)
3617dd7cddfSDavid du Colombier {
3627dd7cddfSDavid du Colombier 	if(g->overtmp == nil)
3637dd7cddfSDavid du Colombier 		return;
3647dd7cddfSDavid du Colombier 
3655a354e27SDavid du Colombier 	/* save previous contents of screen */
3667dd7cddfSDavid du Colombier 	draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
3677dd7cddfSDavid du Colombier 
3685a354e27SDavid du Colombier 	/* draw message */
3697dd7cddfSDavid du Colombier 	if(strlen(msg) > g->overtmplen)
3707dd7cddfSDavid du Colombier 		msg[g->overtmplen] = 0;
3717dd7cddfSDavid du Colombier 	string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, msg);
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier 
3747dd7cddfSDavid du Colombier void
clearcursor(Graph * g)3757dd7cddfSDavid du Colombier clearcursor(Graph *g)
3767dd7cddfSDavid du Colombier {
3777dd7cddfSDavid du Colombier 	int x;
3787dd7cddfSDavid du Colombier 	long prev;
3797dd7cddfSDavid du Colombier 
3807dd7cddfSDavid du Colombier 	if(g->overtmp == nil)
3817dd7cddfSDavid du Colombier 		return;
3827dd7cddfSDavid du Colombier 
3837dd7cddfSDavid du Colombier 	if(g->cursor > 0 && g->cursor < g->ndata){
3847dd7cddfSDavid du Colombier 		x = g->r.max.x - g->cursor;
3857dd7cddfSDavid du Colombier 		prev = 0;
3867dd7cddfSDavid du Colombier 		if(g->cursor > 0)
3877dd7cddfSDavid du Colombier 			prev = g->data[g->cursor-1];
3887dd7cddfSDavid du Colombier 		drawdatum(g, x, prev, g->data[g->cursor], g->vmax);
3897dd7cddfSDavid du Colombier 		g->cursor = -1;
3907dd7cddfSDavid du Colombier 	}
3917dd7cddfSDavid du Colombier }
3927dd7cddfSDavid du Colombier 
3937dd7cddfSDavid du Colombier void
drawcursor(Graph * g,int x)3947dd7cddfSDavid du Colombier drawcursor(Graph *g, int x)
3957dd7cddfSDavid du Colombier {
3967dd7cddfSDavid du Colombier 	if(g->overtmp == nil)
3977dd7cddfSDavid du Colombier 		return;
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier 	draw(screen, Rect(x, g->r.min.y, x+1, g->r.max.y), cols[g->colindex][2], nil, ZP);
4007dd7cddfSDavid du Colombier }
4017dd7cddfSDavid du Colombier 
4027dd7cddfSDavid du Colombier void
update1(Graph * g,long v,long vmax,long mark)4037dd7cddfSDavid du Colombier update1(Graph *g, long v, long vmax, long mark)
4047dd7cddfSDavid du Colombier {
4057dd7cddfSDavid du Colombier 	char buf[Gmsglen];
4067dd7cddfSDavid du Colombier 
4075a354e27SDavid du Colombier 	/* put back screen value sans message */
4087dd7cddfSDavid du Colombier 	if(g->overflow || *g->msg){
4097dd7cddfSDavid du Colombier 		clearmsg(g);
4107dd7cddfSDavid du Colombier 		g->overflow = 0;
4117dd7cddfSDavid du Colombier 	}
4127dd7cddfSDavid du Colombier 
4137dd7cddfSDavid du Colombier 	draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y));
4147dd7cddfSDavid du Colombier 	drawdatum(g, g->r.max.x-1, g->data[0], v, vmax);
4157dd7cddfSDavid du Colombier 	if(mark)
4167dd7cddfSDavid du Colombier 		drawmark(g, g->r.max.x-1);
4177dd7cddfSDavid du Colombier 	memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0]));
4187dd7cddfSDavid du Colombier 	g->data[0] = v;
4197dd7cddfSDavid du Colombier 	if(v>vmax){
4207dd7cddfSDavid du Colombier 		g->overflow = 1;
4217dd7cddfSDavid du Colombier 		sprint(buf, "%ld", v);
4227dd7cddfSDavid du Colombier 		drawmsg(g, buf);
4237dd7cddfSDavid du Colombier 	} else if(*g->msg)
4247dd7cddfSDavid du Colombier 		drawmsg(g, g->msg);
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 	if(g->cursor >= 0){
4277dd7cddfSDavid du Colombier 		g->cursor++;
4287dd7cddfSDavid du Colombier 		if(g->cursor >= g->ndata){
4297dd7cddfSDavid du Colombier 			g->cursor = -1;
4307dd7cddfSDavid du Colombier 			if(*g->msg){
4317dd7cddfSDavid du Colombier 				clearmsg(g);
4327dd7cddfSDavid du Colombier 				*g->msg = 0;
4337dd7cddfSDavid du Colombier 			}
4347dd7cddfSDavid du Colombier 		}
4357dd7cddfSDavid du Colombier 	}
4367dd7cddfSDavid du Colombier 
4377dd7cddfSDavid du Colombier }
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier void
pinglost(Machine * m,Req *)4407dd7cddfSDavid du Colombier pinglost(Machine *m, Req*)
4417dd7cddfSDavid du Colombier {
4427dd7cddfSDavid du Colombier 	m->lostmsgs++;
4437dd7cddfSDavid du Colombier }
4447dd7cddfSDavid du Colombier 
4457dd7cddfSDavid du Colombier void
pingreply(Machine * m,Req * r)4467dd7cddfSDavid du Colombier pingreply(Machine *m, Req *r)
4477dd7cddfSDavid du Colombier {
4487dd7cddfSDavid du Colombier 	ulong x;
4497dd7cddfSDavid du Colombier 
4507dd7cddfSDavid du Colombier 	x = r->time/1000LL;
4517dd7cddfSDavid du Colombier 	m->rttsum += x;
4527dd7cddfSDavid du Colombier 	m->rcvdmsgs++;
4537dd7cddfSDavid du Colombier 	m->rttmsgs++;
4547dd7cddfSDavid du Colombier }
4557dd7cddfSDavid du Colombier 
4567dd7cddfSDavid du Colombier 
4577dd7cddfSDavid du Colombier void
pingclean(Machine * m,ushort seq,vlong now,int)4587dd7cddfSDavid du Colombier pingclean(Machine *m, ushort seq, vlong now, int)
4597dd7cddfSDavid du Colombier {
4607dd7cddfSDavid du Colombier 	Req **l, *r;
4617dd7cddfSDavid du Colombier 	vlong x, y;
4627dd7cddfSDavid du Colombier 
4637dd7cddfSDavid du Colombier 	y = 10LL*1000000000LL;
4647dd7cddfSDavid du Colombier 	for(l = &m->first; *l; ){
4657dd7cddfSDavid du Colombier 		r = *l;
4667dd7cddfSDavid du Colombier 		x = now - r->time;
4677dd7cddfSDavid du Colombier 		if(x > y || r->seq == seq){
4687dd7cddfSDavid du Colombier 			*l = r->next;
4697dd7cddfSDavid du Colombier 			r->time = x;
4707dd7cddfSDavid du Colombier 			if(r->seq != seq)
4717dd7cddfSDavid du Colombier 				pinglost(m, r);
4727dd7cddfSDavid du Colombier 			else
4737dd7cddfSDavid du Colombier 				pingreply(m, r);
4747dd7cddfSDavid du Colombier 			free(r);
4757dd7cddfSDavid du Colombier 		} else
4767dd7cddfSDavid du Colombier 			l = &(r->next);
4777dd7cddfSDavid du Colombier 	}
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier 
480*94aa1c4cSDavid du Colombier /* IPv4 only */
4817dd7cddfSDavid du Colombier void
pingsend(Machine * m)4827dd7cddfSDavid du Colombier pingsend(Machine *m)
4837dd7cddfSDavid du Colombier {
4847dd7cddfSDavid du Colombier 	int i;
485*94aa1c4cSDavid du Colombier 	char buf[128], err[ERRMAX];
486*94aa1c4cSDavid du Colombier 	Icmphdr *ip;
4877dd7cddfSDavid du Colombier 	Req *r;
4887dd7cddfSDavid du Colombier 
489*94aa1c4cSDavid du Colombier 	ip = (Icmphdr *)(buf + IPV4HDR_LEN);
490*94aa1c4cSDavid du Colombier 	memset(buf, 0, sizeof buf);
4917dd7cddfSDavid du Colombier 	r = malloc(sizeof *r);
4927dd7cddfSDavid du Colombier 	if(r == nil)
4937dd7cddfSDavid du Colombier 		return;
4947dd7cddfSDavid du Colombier 
495*94aa1c4cSDavid du Colombier 	for(i = 32; i < MSGLEN; i++)
4967dd7cddfSDavid du Colombier 		buf[i] = i;
4977dd7cddfSDavid du Colombier 	ip->type = EchoRequest;
4987dd7cddfSDavid du Colombier 	ip->code = 0;
4997dd7cddfSDavid du Colombier 	ip->seq[0] = m->seq;
5007dd7cddfSDavid du Colombier 	ip->seq[1] = m->seq>>8;
5017dd7cddfSDavid du Colombier 	r->seq = m->seq;
5027dd7cddfSDavid du Colombier 	r->next = nil;
5037dd7cddfSDavid du Colombier 	lock(m);
5047dd7cddfSDavid du Colombier 	pingclean(m, -1, nsec(), 0);
5057dd7cddfSDavid du Colombier 	if(m->first == nil)
5067dd7cddfSDavid du Colombier 		m->first = r;
5077dd7cddfSDavid du Colombier 	else
5087dd7cddfSDavid du Colombier 		m->last->next = r;
5097dd7cddfSDavid du Colombier 	m->last = r;
5107dd7cddfSDavid du Colombier 	r->time = nsec();
5117dd7cddfSDavid du Colombier 	unlock(m);
512*94aa1c4cSDavid du Colombier 	if(write(m->pingfd, buf, MSGLEN) < MSGLEN){
5139a747e4fSDavid du Colombier 		errstr(err, sizeof err);
5147dd7cddfSDavid du Colombier 		if(strstr(err, "unreach")||strstr(err, "exceed"))
5157dd7cddfSDavid du Colombier 			m->unreachable++;
5167dd7cddfSDavid du Colombier 	}
5177dd7cddfSDavid du Colombier 	m->seq++;
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier 
520*94aa1c4cSDavid du Colombier /* IPv4 only */
5217dd7cddfSDavid du Colombier void
pingrcv(void * arg)5227dd7cddfSDavid du Colombier pingrcv(void *arg)
5237dd7cddfSDavid du Colombier {
5247dd7cddfSDavid du Colombier 	int i, n, fd;
525*94aa1c4cSDavid du Colombier 	uchar buf[512];
526*94aa1c4cSDavid du Colombier 	ushort x;
5277dd7cddfSDavid du Colombier 	vlong now;
528*94aa1c4cSDavid du Colombier 	Icmphdr *ip;
529*94aa1c4cSDavid du Colombier 	Ip4hdr *ip4;
5307dd7cddfSDavid du Colombier 	Machine *m = arg;
5317dd7cddfSDavid du Colombier 
532*94aa1c4cSDavid du Colombier 	ip4 = (Ip4hdr *)buf;
533*94aa1c4cSDavid du Colombier 	ip = (Icmphdr *)(buf + IPV4HDR_LEN);
5347dd7cddfSDavid du Colombier 	fd = dup(m->pingfd, -1);
5357dd7cddfSDavid du Colombier 	for(;;){
5367dd7cddfSDavid du Colombier 		n = read(fd, buf, sizeof(buf));
5377dd7cddfSDavid du Colombier 		now = nsec();
5387dd7cddfSDavid du Colombier 		if(n <= 0)
5397dd7cddfSDavid du Colombier 			continue;
5407dd7cddfSDavid du Colombier 		if(n < MSGLEN){
5417dd7cddfSDavid du Colombier 			print("bad len %d/%d\n", n, MSGLEN);
5427dd7cddfSDavid du Colombier 			continue;
5437dd7cddfSDavid du Colombier 		}
5447dd7cddfSDavid du Colombier 		for(i = 32; i < MSGLEN; i++)
5457dd7cddfSDavid du Colombier 			if(buf[i] != (i&0xff))
5467dd7cddfSDavid du Colombier 				continue;
5477dd7cddfSDavid du Colombier 		x = (ip->seq[1]<<8) | ip->seq[0];
5487dd7cddfSDavid du Colombier 		if(ip->type != EchoReply || ip->code != 0)
5497dd7cddfSDavid du Colombier 			continue;
5507dd7cddfSDavid du Colombier 		lock(m);
551*94aa1c4cSDavid du Colombier 		pingclean(m, x, now, ip4->ttl);
5527dd7cddfSDavid du Colombier 		unlock(m);
5537dd7cddfSDavid du Colombier 	}
5547dd7cddfSDavid du Colombier }
5557dd7cddfSDavid du Colombier 
5567dd7cddfSDavid du Colombier void
initmach(Machine * m,char * name)5577dd7cddfSDavid du Colombier initmach(Machine *m, char *name)
5587dd7cddfSDavid du Colombier {
5597dd7cddfSDavid du Colombier 	char *p;
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier 	srand(time(0));
5627dd7cddfSDavid du Colombier 	p = strchr(name, '!');
5637dd7cddfSDavid du Colombier 	if(p){
5647dd7cddfSDavid du Colombier 		p++;
5657dd7cddfSDavid du Colombier 		m->name = estrdup(p+1);
5667dd7cddfSDavid du Colombier 	}else
5677dd7cddfSDavid du Colombier 		p = name;
5687dd7cddfSDavid du Colombier 
5697dd7cddfSDavid du Colombier 	m->name = estrdup(p);
5707dd7cddfSDavid du Colombier 	m->nproc = 1;
5717dd7cddfSDavid du Colombier 	m->pingfd = dial(netmkaddr(m->name, "icmp", "1"), 0, 0, 0);
5727dd7cddfSDavid du Colombier 	if(m->pingfd < 0)
5737dd7cddfSDavid du Colombier 		sysfatal("dialing %s: %r", m->name);
5747dd7cddfSDavid du Colombier 	startproc(pingrcv, m);
5757dd7cddfSDavid du Colombier }
5767dd7cddfSDavid du Colombier 
577c93608ccSDavid du Colombier long
rttscale(long x)578c93608ccSDavid du Colombier rttscale(long x)
5797dd7cddfSDavid du Colombier {
5807dd7cddfSDavid du Colombier 	if(x == 0)
5817dd7cddfSDavid du Colombier 		return 0;
5827dd7cddfSDavid du Colombier 	x = 10.0*log10(x) - 20.0;
5837dd7cddfSDavid du Colombier 	if(x < 0)
5847dd7cddfSDavid du Colombier 		x = 0;
5857dd7cddfSDavid du Colombier 	return x;
5867dd7cddfSDavid du Colombier }
5877dd7cddfSDavid du Colombier 
588c93608ccSDavid du Colombier double
rttunscale(long x)589c93608ccSDavid du Colombier rttunscale(long x)
5907dd7cddfSDavid du Colombier {
5917dd7cddfSDavid du Colombier 	double dx;
5927dd7cddfSDavid du Colombier 
5937dd7cddfSDavid du Colombier 	x += 20;
5947dd7cddfSDavid du Colombier 	dx = x;
5957dd7cddfSDavid du Colombier 	return pow(10.0, dx/10.0);
5967dd7cddfSDavid du Colombier }
5977dd7cddfSDavid du Colombier 
5987dd7cddfSDavid du Colombier void
rttval(Machine * m,long * v,long * vmax,long * mark)5997dd7cddfSDavid du Colombier rttval(Machine *m, long *v, long *vmax, long *mark)
6007dd7cddfSDavid du Colombier {
6017dd7cddfSDavid du Colombier 	ulong x;
6027dd7cddfSDavid du Colombier 
6037dd7cddfSDavid du Colombier 	if(m->rttmsgs == 0){
6047dd7cddfSDavid du Colombier 		x = m->lastrtt;
6057dd7cddfSDavid du Colombier 	} else {
6067dd7cddfSDavid du Colombier 		x = m->rttsum/m->rttmsgs;
6077dd7cddfSDavid du Colombier 		m->rttsum = m->rttmsgs = 0;
6087dd7cddfSDavid du Colombier 		m->lastrtt = x;
6097dd7cddfSDavid du Colombier 	}
6107dd7cddfSDavid du Colombier 
6117dd7cddfSDavid du Colombier 	*v = rttscale(x);
6127dd7cddfSDavid du Colombier 	*vmax = Rttmax;
6137dd7cddfSDavid du Colombier 	*mark = 0;
6147dd7cddfSDavid du Colombier }
6157dd7cddfSDavid du Colombier 
6167dd7cddfSDavid du Colombier void
lostval(Machine * m,long * v,long * vmax,long * mark)6177dd7cddfSDavid du Colombier lostval(Machine *m, long *v, long *vmax, long *mark)
6187dd7cddfSDavid du Colombier {
6197dd7cddfSDavid du Colombier 	ulong x;
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier 	if(m->rcvdmsgs+m->lostmsgs > 0)
6227dd7cddfSDavid du Colombier 		x = (m->lostavg>>1) + (((m->lostmsgs*100)/(m->lostmsgs + m->rcvdmsgs))>>1);
6237dd7cddfSDavid du Colombier 	else
6247dd7cddfSDavid du Colombier 		x = m->lostavg;
6257dd7cddfSDavid du Colombier 	m->lostavg = x;
6267dd7cddfSDavid du Colombier 	m->lostmsgs = m->rcvdmsgs = 0;
6277dd7cddfSDavid du Colombier 
6287dd7cddfSDavid du Colombier 	if(m->unreachable){
6297dd7cddfSDavid du Colombier 		m->unreachable = 0;
6307dd7cddfSDavid du Colombier 		*mark = 100;
6317dd7cddfSDavid du Colombier 	} else
6327dd7cddfSDavid du Colombier 		*mark = 0;
6337dd7cddfSDavid du Colombier 
6347dd7cddfSDavid du Colombier 	*v = x;
6357dd7cddfSDavid du Colombier 	*vmax = 100;
6367dd7cddfSDavid du Colombier }
6377dd7cddfSDavid du Colombier 
6387dd7cddfSDavid du Colombier jmp_buf catchalarm;
6397dd7cddfSDavid du Colombier 
6407dd7cddfSDavid du Colombier void
alarmed(void * a,char * s)6417dd7cddfSDavid du Colombier alarmed(void *a, char *s)
6427dd7cddfSDavid du Colombier {
6437dd7cddfSDavid du Colombier 	if(strcmp(s, "alarm") == 0)
6447dd7cddfSDavid du Colombier 		notejmp(a, catchalarm, 1);
6457dd7cddfSDavid du Colombier 	noted(NDFLT);
6467dd7cddfSDavid du Colombier }
6477dd7cddfSDavid du Colombier 
6487dd7cddfSDavid du Colombier void
usage(void)6497dd7cddfSDavid du Colombier usage(void)
6507dd7cddfSDavid du Colombier {
6517dd7cddfSDavid du Colombier 	fprint(2, "usage: %s machine [machine...]\n", argv0);
6527dd7cddfSDavid du Colombier 	exits("usage");
6537dd7cddfSDavid du Colombier }
6547dd7cddfSDavid du Colombier 
6557dd7cddfSDavid du Colombier void
addgraph(int n)6567dd7cddfSDavid du Colombier addgraph(int n)
6577dd7cddfSDavid du Colombier {
6587dd7cddfSDavid du Colombier 	Graph *g, *ograph;
6597dd7cddfSDavid du Colombier 	int i, j;
6607dd7cddfSDavid du Colombier 	static int nadd;
6617dd7cddfSDavid du Colombier 
6627dd7cddfSDavid du Colombier 	if(n > nelem(menu2str))
6637dd7cddfSDavid du Colombier 		abort();
6647dd7cddfSDavid du Colombier 	/* avoid two adjacent graphs of same color */
6657dd7cddfSDavid du Colombier 	if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor)
6667dd7cddfSDavid du Colombier 		nadd++;
6677dd7cddfSDavid du Colombier 	ograph = graph;
6687dd7cddfSDavid du Colombier 	graph = emalloc(nmach*(ngraph+1)*sizeof(Graph));
6697dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++)
6707dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++)
6717dd7cddfSDavid du Colombier 			graph[i*(ngraph+1)+j] = ograph[i*ngraph+j];
6727dd7cddfSDavid du Colombier 	free(ograph);
6737dd7cddfSDavid du Colombier 	ngraph++;
6747dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
6757dd7cddfSDavid du Colombier 		g = &graph[i*ngraph+(ngraph-1)];
6767dd7cddfSDavid du Colombier 		memset(g, 0, sizeof(Graph));
6777dd7cddfSDavid du Colombier 		g->label = menu2str[n]+Opwid;
6787dd7cddfSDavid du Colombier 		g->newvalue = newvaluefn[n];
6797dd7cddfSDavid du Colombier 		g->update = update1;	/* no other update functions yet */
6807dd7cddfSDavid du Colombier 		g->mach = &mach[i];
6817dd7cddfSDavid du Colombier 		g->colindex = nadd%Ncolor;
6827dd7cddfSDavid du Colombier 	}
6837dd7cddfSDavid du Colombier 	present[n] = 1;
6847dd7cddfSDavid du Colombier 	nadd++;
6857dd7cddfSDavid du Colombier }
6867dd7cddfSDavid du Colombier 
6877dd7cddfSDavid du Colombier int
which2index(int which)6887dd7cddfSDavid du Colombier which2index(int which)
6897dd7cddfSDavid du Colombier {
6907dd7cddfSDavid du Colombier 	int i, n;
6917dd7cddfSDavid du Colombier 
6927dd7cddfSDavid du Colombier 	n = -1;
6937dd7cddfSDavid du Colombier 	for(i=0; i<ngraph; i++){
6947dd7cddfSDavid du Colombier 		if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){
6957dd7cddfSDavid du Colombier 			n = i;
6967dd7cddfSDavid du Colombier 			break;
6977dd7cddfSDavid du Colombier 		}
6987dd7cddfSDavid du Colombier 	}
6997dd7cddfSDavid du Colombier 	if(n < 0){
7007dd7cddfSDavid du Colombier 		fprint(2, "%s: internal error can't drop graph\n", argv0);
7017dd7cddfSDavid du Colombier 		killall("error");
7027dd7cddfSDavid du Colombier 	}
7037dd7cddfSDavid du Colombier 	return n;
7047dd7cddfSDavid du Colombier }
7057dd7cddfSDavid du Colombier 
7067dd7cddfSDavid du Colombier int
index2which(int index)7077dd7cddfSDavid du Colombier index2which(int index)
7087dd7cddfSDavid du Colombier {
7097dd7cddfSDavid du Colombier 	int i, n;
7107dd7cddfSDavid du Colombier 
7117dd7cddfSDavid du Colombier 	n = -1;
7127dd7cddfSDavid du Colombier 	for(i=0; i<Nmenu2; i++){
7137dd7cddfSDavid du Colombier 		if(strcmp(menu2str[i]+Opwid, graph[index].label) == 0){
7147dd7cddfSDavid du Colombier 			n = i;
7157dd7cddfSDavid du Colombier 			break;
7167dd7cddfSDavid du Colombier 		}
7177dd7cddfSDavid du Colombier 	}
7187dd7cddfSDavid du Colombier 	if(n < 0){
7197dd7cddfSDavid du Colombier 		fprint(2, "%s: internal error can't identify graph\n", argv0);
7207dd7cddfSDavid du Colombier 		killall("error");
7217dd7cddfSDavid du Colombier 	}
7227dd7cddfSDavid du Colombier 	return n;
7237dd7cddfSDavid du Colombier }
7247dd7cddfSDavid du Colombier 
7257dd7cddfSDavid du Colombier void
dropgraph(int which)7267dd7cddfSDavid du Colombier dropgraph(int which)
7277dd7cddfSDavid du Colombier {
7287dd7cddfSDavid du Colombier 	Graph *ograph;
7297dd7cddfSDavid du Colombier 	int i, j, n;
7307dd7cddfSDavid du Colombier 
7317dd7cddfSDavid du Colombier 	if(which > nelem(menu2str))
7327dd7cddfSDavid du Colombier 		abort();
7337dd7cddfSDavid du Colombier 	/* convert n to index in graph table */
7347dd7cddfSDavid du Colombier 	n = which2index(which);
7357dd7cddfSDavid du Colombier 	ograph = graph;
7367dd7cddfSDavid du Colombier 	graph = emalloc(nmach*(ngraph-1)*sizeof(Graph));
7377dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
7387dd7cddfSDavid du Colombier 		for(j=0; j<n; j++)
7397dd7cddfSDavid du Colombier 			graph[i*(ngraph-1)+j] = ograph[i*ngraph+j];
7407dd7cddfSDavid du Colombier 		free(ograph[i*ngraph+j].data);
7417dd7cddfSDavid du Colombier 		freeimage(ograph[i*ngraph+j].overtmp);
7427dd7cddfSDavid du Colombier 		for(j++; j<ngraph; j++)
7437dd7cddfSDavid du Colombier 			graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j];
7447dd7cddfSDavid du Colombier 	}
7457dd7cddfSDavid du Colombier 	free(ograph);
7467dd7cddfSDavid du Colombier 	ngraph--;
7477dd7cddfSDavid du Colombier 	present[which] = 0;
7487dd7cddfSDavid du Colombier }
7497dd7cddfSDavid du Colombier 
7507dd7cddfSDavid du Colombier void
addmachine(char * name)7517dd7cddfSDavid du Colombier addmachine(char *name)
7527dd7cddfSDavid du Colombier {
7537dd7cddfSDavid du Colombier 	if(ngraph > 0){
7547dd7cddfSDavid du Colombier 		fprint(2, "%s: internal error: ngraph>0 in addmachine()\n", argv0);
7557dd7cddfSDavid du Colombier 		usage();
7567dd7cddfSDavid du Colombier 	}
7577dd7cddfSDavid du Colombier 	if(nmach == NMACH)
7587dd7cddfSDavid du Colombier 		sysfatal("too many machines");
7597dd7cddfSDavid du Colombier 	initmach(&mach[nmach++], name);
7607dd7cddfSDavid du Colombier }
7617dd7cddfSDavid du Colombier 
7627dd7cddfSDavid du Colombier 
7637dd7cddfSDavid du Colombier void
resize(void)7647dd7cddfSDavid du Colombier resize(void)
7657dd7cddfSDavid du Colombier {
7667dd7cddfSDavid du Colombier 	int i, j, n, startx, starty, x, y, dx, dy, hashdx, ondata;
7677dd7cddfSDavid du Colombier 	Graph *g;
7687dd7cddfSDavid du Colombier 	Rectangle machr, r;
7697dd7cddfSDavid du Colombier 	long v, vmax, mark;
7707dd7cddfSDavid du Colombier 	char buf[128];
7717dd7cddfSDavid du Colombier 
7727dd7cddfSDavid du Colombier 	draw(screen, screen->r, display->white, nil, ZP);
7737dd7cddfSDavid du Colombier 
7747dd7cddfSDavid du Colombier 	/* label left edge */
7757dd7cddfSDavid du Colombier 	x = screen->r.min.x;
7767dd7cddfSDavid du Colombier 	y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
7777dd7cddfSDavid du Colombier 	dy = (screen->r.max.y - y)/ngraph;
7787dd7cddfSDavid du Colombier 	dx = Labspace+stringwidth(mediumfont, "0")+Labspace;
7797dd7cddfSDavid du Colombier 	startx = x+dx+1;
7807dd7cddfSDavid du Colombier 	starty = y;
7817dd7cddfSDavid du Colombier 	for(i=0; i<ngraph; i++,y+=dy){
7827dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
7837dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
7847dd7cddfSDavid du Colombier 		label(Pt(x, y), dy, graph[i].label);
7857dd7cddfSDavid du Colombier 		draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
7867dd7cddfSDavid du Colombier 	}
7877dd7cddfSDavid du Colombier 
7887dd7cddfSDavid du Colombier 	/* label right edge */
7897dd7cddfSDavid du Colombier 	dx = Labspace+stringwidth(mediumfont, "0.001")+Labspace;
7907dd7cddfSDavid du Colombier 	hashdx = dx;
7917dd7cddfSDavid du Colombier 	x = screen->r.max.x - dx;
7927dd7cddfSDavid du Colombier 	y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
7937dd7cddfSDavid du Colombier 	for(i=0; i<ngraph; i++,y+=dy){
7947dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
7957dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
7967dd7cddfSDavid du Colombier 		hashmarks(Pt(x, y), dy, i);
7977dd7cddfSDavid du Colombier 		draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
7987dd7cddfSDavid du Colombier 	}
7997dd7cddfSDavid du Colombier 
8007dd7cddfSDavid du Colombier 	/* label top edge */
8017dd7cddfSDavid du Colombier 	dx = (screen->r.max.x - dx - startx)/nmach;
8027dd7cddfSDavid du Colombier 	for(x=startx, i=0; i<nmach; i++,x+=dx){
8037dd7cddfSDavid du Colombier 		draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
8047dd7cddfSDavid du Colombier 		j = dx/stringwidth(mediumfont, "0");
8057dd7cddfSDavid du Colombier 		n = mach[i].nproc;
8067dd7cddfSDavid du Colombier 		if(n>1 && j>=1+3+(n>10)+(n>100)){	/* first char of name + (n) */
8077dd7cddfSDavid du Colombier 			j -= 3+(n>10)+(n>100);
8087dd7cddfSDavid du Colombier 			if(j <= 0)
8097dd7cddfSDavid du Colombier 				j = 1;
8107dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n);
8117dd7cddfSDavid du Colombier 		}else
8127dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s", j, mach[i].name);
8137dd7cddfSDavid du Colombier 		string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP,
8147dd7cddfSDavid du Colombier 			mediumfont, buf);
8157dd7cddfSDavid du Colombier 	}
8167dd7cddfSDavid du Colombier 	/* draw last vertical line */
8177dd7cddfSDavid du Colombier 	draw(screen,
8187dd7cddfSDavid du Colombier 		Rect(screen->r.max.x-hashdx-1, starty-1, screen->r.max.x-hashdx, screen->r.max.y),
8197dd7cddfSDavid du Colombier 		display->black, nil, ZP);
8207dd7cddfSDavid du Colombier 
8217dd7cddfSDavid du Colombier 	/* create graphs */
8227dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
8237dd7cddfSDavid du Colombier 		machr = Rect(startx+i*dx, starty, screen->r.max.x, screen->r.max.y);
8247dd7cddfSDavid du Colombier 		if(i < nmach-1)
8257dd7cddfSDavid du Colombier 			machr.max.x = startx+(i+1)*dx - 1;
8267dd7cddfSDavid du Colombier 		else
8277dd7cddfSDavid du Colombier 			machr.max.x = screen->r.max.x - hashdx - 1;
8287dd7cddfSDavid du Colombier 		y = starty;
8297dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++, y+=dy){
8307dd7cddfSDavid du Colombier 			g = &graph[i*ngraph+j];
8317dd7cddfSDavid du Colombier 			/* allocate data */
8327dd7cddfSDavid du Colombier 			ondata = g->ndata;
8337dd7cddfSDavid du Colombier 			g->ndata = Dx(machr)+1;	/* may be too many if label will be drawn here; so what? */
8347dd7cddfSDavid du Colombier 			g->data = erealloc(g->data, g->ndata*sizeof(long));
8357dd7cddfSDavid du Colombier 			if(g->ndata > ondata)
8367dd7cddfSDavid du Colombier 				memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(long));
8377dd7cddfSDavid du Colombier 			/* set geometry */
8387dd7cddfSDavid du Colombier 			g->r = machr;
8397dd7cddfSDavid du Colombier 			g->r.min.y = y;
8407dd7cddfSDavid du Colombier 			g->r.max.y = y+dy - 1;
8417dd7cddfSDavid du Colombier 			if(j == ngraph-1)
8427dd7cddfSDavid du Colombier 				g->r.max.y = screen->r.max.y;
8437dd7cddfSDavid du Colombier 			draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x));
8447dd7cddfSDavid du Colombier 			g->overflow = 0;
8457dd7cddfSDavid du Colombier 			*g->msg = 0;
8467dd7cddfSDavid du Colombier 			freeimage(g->overtmp);
8477dd7cddfSDavid du Colombier 			g->overtmp = nil;
8487dd7cddfSDavid du Colombier 			g->overtmplen = 0;
8497dd7cddfSDavid du Colombier 			r = g->r;
8507dd7cddfSDavid du Colombier 			r.max.y = r.min.y+mediumfont->height;
8517dd7cddfSDavid du Colombier 			n = (g->r.max.x - r.min.x)/stringwidth(mediumfont, "9");
8527dd7cddfSDavid du Colombier 			if(n > 4){
8537dd7cddfSDavid du Colombier 				if(n > Gmsglen)
8547dd7cddfSDavid du Colombier 					n = Gmsglen;
8557dd7cddfSDavid du Colombier 				r.max.x = r.min.x+stringwidth(mediumfont, "9")*n;
8567dd7cddfSDavid du Colombier 				g->overtmplen = n;
8577dd7cddfSDavid du Colombier 				g->overtmp = allocimage(display, r, screen->chan, 0, -1);
8587dd7cddfSDavid du Colombier 			}
8597dd7cddfSDavid du Colombier 			g->newvalue(g->mach, &v, &vmax, &mark);
8607dd7cddfSDavid du Colombier 			redraw(g, vmax);
8617dd7cddfSDavid du Colombier 		}
8627dd7cddfSDavid du Colombier 	}
8637dd7cddfSDavid du Colombier 
8647dd7cddfSDavid du Colombier 	flushimage(display, 1);
8657dd7cddfSDavid du Colombier }
8667dd7cddfSDavid du Colombier 
8677dd7cddfSDavid du Colombier void
eresized(int new)8687dd7cddfSDavid du Colombier eresized(int new)
8697dd7cddfSDavid du Colombier {
8707dd7cddfSDavid du Colombier 	lockdisplay(display);
8717dd7cddfSDavid du Colombier 	if(new && getwindow(display, Refnone) < 0) {
8727dd7cddfSDavid du Colombier 		fprint(2, "%s: can't reattach to window\n", argv0);
8737dd7cddfSDavid du Colombier 		killall("reattach");
8747dd7cddfSDavid du Colombier 	}
8757dd7cddfSDavid du Colombier 	resize();
8767dd7cddfSDavid du Colombier 	unlockdisplay(display);
8777dd7cddfSDavid du Colombier }
8787dd7cddfSDavid du Colombier 
8797dd7cddfSDavid du Colombier void
dobutton2(Mouse * m)8807dd7cddfSDavid du Colombier dobutton2(Mouse *m)
8817dd7cddfSDavid du Colombier {
8827dd7cddfSDavid du Colombier 	int i;
8837dd7cddfSDavid du Colombier 
8847dd7cddfSDavid du Colombier 	for(i=0; i<Nmenu2; i++)
8857dd7cddfSDavid du Colombier 		if(present[i])
8867dd7cddfSDavid du Colombier 			memmove(menu2str[i], "drop ", Opwid);
8877dd7cddfSDavid du Colombier 		else
8887dd7cddfSDavid du Colombier 			memmove(menu2str[i], "add  ", Opwid);
8897dd7cddfSDavid du Colombier 	i = emenuhit(3, m, &menu2);
8907dd7cddfSDavid du Colombier 	if(i >= 0){
8917dd7cddfSDavid du Colombier 		if(!present[i])
8927dd7cddfSDavid du Colombier 			addgraph(i);
8937dd7cddfSDavid du Colombier 		else if(ngraph > 1)
8947dd7cddfSDavid du Colombier 			dropgraph(i);
8957dd7cddfSDavid du Colombier 		resize();
8967dd7cddfSDavid du Colombier 	}
8977dd7cddfSDavid du Colombier }
8987dd7cddfSDavid du Colombier 
8997dd7cddfSDavid du Colombier void
dobutton1(Mouse * m)9007dd7cddfSDavid du Colombier dobutton1(Mouse *m)
9017dd7cddfSDavid du Colombier {
9027dd7cddfSDavid du Colombier 	int i, n, dx, dt;
9037dd7cddfSDavid du Colombier 	Graph *g;
9047dd7cddfSDavid du Colombier 	char *e;
9057dd7cddfSDavid du Colombier 	double f;
9067dd7cddfSDavid du Colombier 
9077dd7cddfSDavid du Colombier 	for(i = 0; i < ngraph*nmach; i++){
9087dd7cddfSDavid du Colombier 		if(ptinrect(m->xy, graph[i].r))
9097dd7cddfSDavid du Colombier 			break;
9107dd7cddfSDavid du Colombier 	}
9117dd7cddfSDavid du Colombier 	if(i == ngraph*nmach)
9127dd7cddfSDavid du Colombier 		return;
9137dd7cddfSDavid du Colombier 
9147dd7cddfSDavid du Colombier 	g = &graph[i];
9157dd7cddfSDavid du Colombier 	if(g->overtmp == nil)
9167dd7cddfSDavid du Colombier 		return;
9177dd7cddfSDavid du Colombier 
9185a354e27SDavid du Colombier 	/* clear any previous message and cursor */
9197dd7cddfSDavid du Colombier 	if(g->overflow || *g->msg){
9207dd7cddfSDavid du Colombier 		clearmsg(g);
9217dd7cddfSDavid du Colombier 		*g->msg = 0;
9227dd7cddfSDavid du Colombier 		clearcursor(g);
9237dd7cddfSDavid du Colombier 	}
9247dd7cddfSDavid du Colombier 
9257dd7cddfSDavid du Colombier 	dx = g->r.max.x - m->xy.x;
9267dd7cddfSDavid du Colombier 	g->cursor = dx;
9277dd7cddfSDavid du Colombier 	dt = dx*pinginterval;
9287dd7cddfSDavid du Colombier 	e = &g->msg[sizeof(g->msg)];
9297dd7cddfSDavid du Colombier 	seprint(g->msg, e, "%s", ctime(starttime-dt/1000)+11);
9307dd7cddfSDavid du Colombier 	g->msg[8] = 0;
9317dd7cddfSDavid du Colombier 	n = 8;
9327dd7cddfSDavid du Colombier 
9337dd7cddfSDavid du Colombier 	switch(index2which(i)){
9347dd7cddfSDavid du Colombier 	case Mrtt:
9357dd7cddfSDavid du Colombier 		f = rttunscale(g->data[dx]);
9367dd7cddfSDavid du Colombier 		seprint(g->msg+n, e, " %3.3g", f/1000000);
9377dd7cddfSDavid du Colombier 		break;
9387dd7cddfSDavid du Colombier 	case Mlost:
939c93608ccSDavid du Colombier 		seprint(g->msg+n, e, " %ld%%", g->data[dx]);
9407dd7cddfSDavid du Colombier 		break;
9417dd7cddfSDavid du Colombier 	}
9427dd7cddfSDavid du Colombier 
9437dd7cddfSDavid du Colombier 	drawmsg(g, g->msg);
9447dd7cddfSDavid du Colombier 	drawcursor(g, m->xy.x);
9457dd7cddfSDavid du Colombier }
9467dd7cddfSDavid du Colombier 
9477dd7cddfSDavid du Colombier void
mouseproc(void *)9487dd7cddfSDavid du Colombier mouseproc(void*)
9497dd7cddfSDavid du Colombier {
9507dd7cddfSDavid du Colombier 	Mouse mouse;
9517dd7cddfSDavid du Colombier 
9527dd7cddfSDavid du Colombier 	for(;;){
9537dd7cddfSDavid du Colombier 		mouse = emouse();
9547dd7cddfSDavid du Colombier 		if(mouse.buttons == 4){
9557dd7cddfSDavid du Colombier 			lockdisplay(display);
9567dd7cddfSDavid du Colombier 			dobutton2(&mouse);
9577dd7cddfSDavid du Colombier 			unlockdisplay(display);
9587dd7cddfSDavid du Colombier 		} else if(mouse.buttons == 1){
9597dd7cddfSDavid du Colombier 			lockdisplay(display);
9607dd7cddfSDavid du Colombier 			dobutton1(&mouse);
9617dd7cddfSDavid du Colombier 			unlockdisplay(display);
9627dd7cddfSDavid du Colombier 		}
9637dd7cddfSDavid du Colombier 	}
9647dd7cddfSDavid du Colombier }
9657dd7cddfSDavid du Colombier 
9667dd7cddfSDavid du Colombier void
startproc(void (* f)(void *),void * arg)9677dd7cddfSDavid du Colombier startproc(void (*f)(void*), void *arg)
9687dd7cddfSDavid du Colombier {
9697dd7cddfSDavid du Colombier 	int pid;
9707dd7cddfSDavid du Colombier 
9717dd7cddfSDavid du Colombier 	switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
9727dd7cddfSDavid du Colombier 	case -1:
9737dd7cddfSDavid du Colombier 		fprint(2, "%s: fork failed: %r\n", argv0);
9747dd7cddfSDavid du Colombier 		killall("fork failed");
9757dd7cddfSDavid du Colombier 	case 0:
9767dd7cddfSDavid du Colombier 		f(arg);
9777dd7cddfSDavid du Colombier 		killall("process died");
9787dd7cddfSDavid du Colombier 		exits(nil);
9797dd7cddfSDavid du Colombier 	}
9807dd7cddfSDavid du Colombier 	pids[npid++] = pid;
9817dd7cddfSDavid du Colombier }
9827dd7cddfSDavid du Colombier 
9837dd7cddfSDavid du Colombier void
main(int argc,char * argv[])9847dd7cddfSDavid du Colombier main(int argc, char *argv[])
9857dd7cddfSDavid du Colombier {
9867dd7cddfSDavid du Colombier 	int i, j;
9877dd7cddfSDavid du Colombier 	long v, vmax, mark;
9887dd7cddfSDavid du Colombier 	char flags[10], *f, *p;
9897dd7cddfSDavid du Colombier 
9909a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
9917dd7cddfSDavid du Colombier 
9927dd7cddfSDavid du Colombier 	f = flags;
9935a354e27SDavid du Colombier 	pinginterval = 5000;		/* 5 seconds */
9947dd7cddfSDavid du Colombier 	ARGBEGIN{
9957dd7cddfSDavid du Colombier 	case 'i':
9967dd7cddfSDavid du Colombier 		p = ARGF();
9977dd7cddfSDavid du Colombier 		if(p == nil)
9987dd7cddfSDavid du Colombier 			usage();
9997dd7cddfSDavid du Colombier 		pinginterval = atoi(p);
10007dd7cddfSDavid du Colombier 		break;
10017dd7cddfSDavid du Colombier 	default:
10027dd7cddfSDavid du Colombier 		if(f - flags >= sizeof(flags)-1)
10037dd7cddfSDavid du Colombier 			usage();
10047dd7cddfSDavid du Colombier 		*f++ = ARGC();
10057dd7cddfSDavid du Colombier 		break;
10067dd7cddfSDavid du Colombier 	}ARGEND
10077dd7cddfSDavid du Colombier 	*f = 0;
10087dd7cddfSDavid du Colombier 
10097dd7cddfSDavid du Colombier 	for(i=0; i<argc; i++)
10107dd7cddfSDavid du Colombier 		addmachine(argv[i]);
10117dd7cddfSDavid du Colombier 
10127dd7cddfSDavid du Colombier 	for(f = flags; *f; f++)
10137dd7cddfSDavid du Colombier 		switch(*f){
10147dd7cddfSDavid du Colombier 		case 'l':
10157dd7cddfSDavid du Colombier 			addgraph(Mlost);
10167dd7cddfSDavid du Colombier 			break;
10177dd7cddfSDavid du Colombier 		case 'r':
10187dd7cddfSDavid du Colombier 			addgraph(Mrtt);
10197dd7cddfSDavid du Colombier 			break;
10207dd7cddfSDavid du Colombier 		}
10217dd7cddfSDavid du Colombier 
10227dd7cddfSDavid du Colombier 	if(nmach == 0)
10237dd7cddfSDavid du Colombier 		usage();
10247dd7cddfSDavid du Colombier 
10257dd7cddfSDavid du Colombier 	if(ngraph == 0)
10267dd7cddfSDavid du Colombier 		addgraph(Mrtt);
10277dd7cddfSDavid du Colombier 
10287dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++)
10297dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++)
10307dd7cddfSDavid du Colombier 			graph[i*ngraph+j].mach = &mach[i];
10317dd7cddfSDavid du Colombier 
10327dd7cddfSDavid du Colombier 	if(initdraw(nil, nil, argv0) < 0){
10337dd7cddfSDavid du Colombier 		fprint(2, "%s: initdraw failed: %r\n", argv0);
10347dd7cddfSDavid du Colombier 		exits("initdraw");
10357dd7cddfSDavid du Colombier 	}
10367dd7cddfSDavid du Colombier 	colinit();
10377dd7cddfSDavid du Colombier 	einit(Emouse);
10387dd7cddfSDavid du Colombier 	notify(nil);
10397dd7cddfSDavid du Colombier 	startproc(mouseproc, 0);
10407dd7cddfSDavid du Colombier 	display->locking = 1;	/* tell library we're using the display lock */
10417dd7cddfSDavid du Colombier 
10427dd7cddfSDavid du Colombier 	resize();
10437dd7cddfSDavid du Colombier 
10447dd7cddfSDavid du Colombier 	starttime = time(0);
10457dd7cddfSDavid du Colombier 
10467dd7cddfSDavid du Colombier 	unlockdisplay(display); /* display is still locked from initdraw() */
10477dd7cddfSDavid du Colombier 	for(j = 0; ; j++){
10487dd7cddfSDavid du Colombier 		lockdisplay(display);
10497dd7cddfSDavid du Colombier 		if(j == nmach){
10507dd7cddfSDavid du Colombier 			parity = 1-parity;
10517dd7cddfSDavid du Colombier 			j = 0;
10527dd7cddfSDavid du Colombier 			for(i=0; i<nmach*ngraph; i++){
10537dd7cddfSDavid du Colombier 				graph[i].newvalue(graph[i].mach, &v, &vmax, &mark);
10547dd7cddfSDavid du Colombier 				graph[i].update(&graph[i], v, vmax, mark);
10557dd7cddfSDavid du Colombier 			}
10567dd7cddfSDavid du Colombier 			starttime = time(0);
10577dd7cddfSDavid du Colombier 		}
10587dd7cddfSDavid du Colombier 		flushimage(display, 1);
10597dd7cddfSDavid du Colombier 		unlockdisplay(display);
10607dd7cddfSDavid du Colombier 		pingsend(&mach[j%nmach]);
10617dd7cddfSDavid du Colombier 		sleep(pinginterval/nmach);
10627dd7cddfSDavid du Colombier 	}
10637dd7cddfSDavid du Colombier }
1064