931 lines · 18.0 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <ctype.h>#include <auth.h>#include <fcall.h>#include <draw.h>#include <thread.h>#include <mouse.h>#include <keyboard.h> typedef struct Graph		Graph;typedef struct Machine	Machine; 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 */ 	STACK	= 8192,	XSTACK	= 32768}; enum{	V80211,	Vbattery,	Vcontext,	Vcpu,	Vether,	Vethererr,	Vetherin,	Vetherout,	Vfault,	Vfork,	Vidle,	Vintr,	Vload,	Vmem,	Vswap,	Vsys,	Vsyscall,	Vuser,	Nvalue}; char*labels[Nvalue] = {	"802.11",	"battery",	"context",	"cpu",	"ether",	"ethererr",	"etherin",	"etherout",	"fault",	"fork",	"idle",	"intr",	"load",	"mem",	"swap",	"sys",	"syscall",	"user"};	 struct Graph{	int		colindex;	Rectangle	r;	int		*data;	int		ndata;	char		*label;	int		value;	void		(*update)(Graph*, long, ulong);	Machine	*mach;	int		overflow;	Image	*overtmp;	ulong	vmax;}; struct Machine{	char		*name;	int		fd;	int		pid;	int		dead;	int		absolute[Nvalue];	ulong	last[Nvalue];	ulong	val[Nvalue][2];	ulong	load;	ulong	nload;}; char	*menu2str[Nvalue+1];char xmenu2str[Nvalue+1][40]; Menu	menu2 = {menu2str, 0};int		present[Nvalue];Image	*cols[Ncolor][3];Graph	*graph;Machine	*mach;Font		*mediumfont;char		*fontname;char		*mysysname;char		argchars[] = "8bcCeEfiIlmnsw";int		pids[1024];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;int		changedvmax; Mousectl *mc;Keyboardctl *kc; voidkillall(char *s){	int i; 	for(i=0; i<nmach; i++)		if(mach[i].pid)			postnote(PNPROC, mach[i].pid, "kill");	threadexitsall(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){	if(fontname)		mediumfont = openfont(display, fontname);	if(mediumfont == nil)		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);} 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, int vmax){	int i, c; 	if(vmax != g->vmax){		g->vmax = vmax;		changedvmax = 1;	}	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, long v, ulong vmax){	char buf[32];	int overflow; 	if(v < 0)		v = 0;	if(vmax != g->vmax){		g->vmax = vmax;		changedvmax = 1;	}	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, "%ld", v);		string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, buf);	}} voidusage(void){	fprint(2, "usage: stats [-LY] [-F font] [-O] [-S scale] [-W winsize] [-%s] [machine...]\n", argchars);	threadexitsall("usage");} voidaddgraph(int n){	Graph *g, *ograph;	int i, j;	static int nadd; 	if(n > Nvalue)		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->value = n;		g->label = menu2str[n]+Opwid;		g->update = update1;	/* no other update functions yet */		g->mach = &mach[i];		g->colindex = nadd%Ncolor;	}	present[n] = 1;	nadd++;} voiddropgraph(int which){	Graph *ograph;	int i, j, n; 	if(which > nelem(menu2str))		abort();	/* convert n to index in graph table */	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, "stats: internal error can't drop graph\n");		killall("error");	}	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;} int initmach(Machine*, char*); intaddmachine(char *name){	if(ngraph > 0){		fprint(2, "stats: internal error: ngraph>0 in addmachine()\n");		usage();	}	if(mach == nil)		nmach = 0;	/* a little dance to get us started with local machine by default */	mach = erealloc(mach, (nmach+1)*sizeof(Machine));	memset(mach+nmach, 0, sizeof(Machine));	if (initmach(mach+nmach, name)){		nmach++;		return 1;	} else		return 0;} voidnewvalue(Machine *m, int i, ulong *v, ulong *vmax){	ulong now; 	if(m->last[i] == 0)		m->last[i] = m->val[i][0];			if(i == Vload){		/*		 * Invert the ewma to obtain the 5s load statistics.		 * Ewma is load' = (1884/2048)*load + (164/2048)*last5s, so we do		 * last5s = (load' - (1884/2048)*load) / (164/2048).		 */		if(++m->nload%5 == 0){			now = m->val[i][0];			m->load = (now - (((vlong)m->last[i]*1884)/2048)) * 2048 / 164;			m->last[i] = now;		}		*v = m->load;		*vmax = m->val[i][1];	}else if(m->absolute[i]){		*v = m->val[i][0];		*vmax = m->val[i][1];	}else{		now = m->val[i][0];		*v = (vlong)((now - m->last[i])*sleeptime)/1000;		m->last[i] = now;		*vmax = m->val[i][1];	}	if(*vmax == 0)		*vmax = 1;} voidlabelstrs(Graph *g, char strs[Nlab][Lablen], int *np){	int j;	ulong vmax; 	vmax = g->vmax;	if(logscale){		for(j=1; j<=2; j++)			sprint(strs[j-1], "%g", scale*pow(10., j)*(double)vmax/100.);		*np = 2;	}else{		for(j=1; j<=3; j++)			sprint(strs[j-1], "%g", scale*(double)j*(double)vmax/4.0);		*np = 3;	}} intlabelwidth(void){	int i, j, n, w, maxw;	char strs[Nlab][Lablen]; 	maxw = 0;	for(i=0; i<ngraph; i++){		/* choose value for rightmost graph */		labelstrs(&graph[ngraph*(nmach-1)+i], strs, &n);		for(j=0; j<n; j++){			w = stringwidth(mediumfont, strs[j]);			if(w > maxw)				maxw = w;		}	}	return maxw;}

Lines 1–500 of 931.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t