xref: /plan9/sys/src/cmd/venti/srv/graph.c (revision 368c31ab13393dea083228fdd1c3445076f83a4b)
1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 
5 enum
6 {
7 	Top = 1,
8 	Bottom = 1,
9 	Left = 40,
10 	Right = 0,
11 	MinWidth = Left+Right+2,
12 	MinHeight = Top+Bottom+2,
13 	DefaultWidth = Left+Right+500,
14 	DefaultHeight = Top+Bottom+40
15 };
16 
17 QLock memdrawlock;
18 static Memsubfont *smallfont;
19 static Memimage *black;
20 static Memimage *blue;
21 static Memimage *red;
22 static Memimage *lofill[6];
23 static Memimage *hifill[6];
24 static Memimage *grid;
25 
26 static ulong fill[] = {
27 	0xFFAAAAFF,	0xBB5D5DFF,	/* peach */
28 	DPalegreygreen, DPurpleblue,	/* aqua */
29 	DDarkyellow, DYellowgreen,	/* yellow */
30 	DMedgreen, DDarkgreen,		/* green */
31 	0x00AAFFFF, 0x0088CCFF,	/* blue */
32 	0xCCCCCCFF, 0x888888FF,	/* grey */
33 };
34 
35 Memimage*
allocrepl(ulong color)36 allocrepl(ulong color)
37 {
38 	Memimage *m;
39 
40 	m = allocmemimage(Rect(0,0,1,1), RGB24);
41 	memfillcolor(m, color);
42 	m->flags |= Frepl;
43 	m->clipr = Rect(-1000000, -1000000, 1000000, 1000000);
44 	return m;
45 }
46 
47 static void
ginit(void)48 ginit(void)
49 {
50 	static int first = 1;
51 	int i;
52 
53 	if(!first)
54 		return;
55 
56 	first = 0;
57 	memimageinit();
58 #ifdef PLAN9PORT
59 	smallfont = openmemsubfont(unsharp("#9/font/lucsans/lstr.10"));
60 #else
61 	smallfont = openmemsubfont("/lib/font/bit/lucidasans/lstr.10");
62 #endif
63 	black = memblack;
64 	blue = allocrepl(DBlue);
65 	red = allocrepl(DRed);
66 	grid = allocrepl(0x77777777);
67 	for(i=0; i<nelem(fill)/2 && i<nelem(lofill) && i<nelem(hifill); i++){
68 		lofill[i] = allocrepl(fill[2*i]);
69 		hifill[i] = allocrepl(fill[2*i+1]);
70 	}
71 }
72 
73 static void
mklabel(char * str,int v)74 mklabel(char *str, int v)
75 {
76 	if(v < 0){
77 		v = -v;
78 		*str++ = '-';
79 	}
80 	if(v < 10000)
81 		sprint(str, "%d", v);
82 	else if(v < 10000000)
83 		sprint(str, "%dk", v/1000);
84 	else
85 		sprint(str, "%dM", v/1000000);
86 }
87 
88 static void
drawlabel(Memimage * m,Point p,int n)89 drawlabel(Memimage *m, Point p, int n)
90 {
91 	char buf[30];
92 	Point w;
93 
94 	mklabel(buf, n);
95 	w = memsubfontwidth(smallfont, buf);
96 	memimagestring(m, Pt(p.x-5-w.x, p.y), memblack, ZP, smallfont, buf);
97 }
98 
99 static int
scalept(int val,int valmin,int valmax,int ptmin,int ptmax)100 scalept(int val, int valmin, int valmax, int ptmin, int ptmax)
101 {
102 	if(val <= valmin)
103 		val = valmin;
104 	if(val >= valmax)
105 		val = valmax;
106 	if(valmax == valmin)
107 		valmax++;
108 	return ptmin + (vlong)(val-valmin)*(ptmax-ptmin)/(valmax-valmin);
109 }
110 
111 Memimage*
statgraph(Graph * g)112 statgraph(Graph *g)
113 {
114 	int i, nbin, x, lo, hi, min, max, first;
115 	Memimage *m;
116 	Rectangle r;
117 	Statbin *b, bin[2000];	/* 32 kB, but whack is worse */
118 
119 	needstack(8192);	/* double check that bin didn't kill us */
120 
121 	if(g->wid <= MinWidth)
122 		g->wid = DefaultWidth;
123 	if(g->ht <= MinHeight)
124 		g->ht = DefaultHeight;
125 	if(g->wid > nelem(bin))
126 		g->wid = nelem(bin);
127 	if(g->fill < 0)
128 		g->fill = ((uint)(uintptr)g->arg>>8)%nelem(lofill);
129 	if(g->fill > nelem(lofill))
130 		g->fill %= nelem(lofill);
131 
132 	nbin = g->wid - (Left+Right);
133 	binstats(g->fn, g->arg, g->t0, g->t1, bin, nbin);
134 
135 	/*
136 	 * compute bounds
137 	 */
138 	min = g->min;
139 	max = g->max;
140 	if(min < 0 || max <= min){
141 		min = max = 0;
142 		first = 1;
143 		for(i=0; i<nbin; i++){
144 			b = &bin[i];
145 			if(b->nsamp == 0)
146 				continue;
147 			if(first || b->min < min)
148 				min = b->min;
149 			if(first || b->max > max)
150 				max = b->max;
151 			first = 0;
152 		}
153 	}
154 
155 	qlock(&memdrawlock);
156 	ginit();
157 	if(smallfont==nil || black==nil || blue==nil || red==nil || hifill==nil || lofill==nil){
158 		werrstr("graphics initialization failed: %r");
159 		qunlock(&memdrawlock);
160 		return nil;
161 	}
162 
163 	/* fresh image */
164 	m = allocmemimage(Rect(0,0,g->wid,g->ht), ABGR32);
165 	if(m == nil){
166 		qunlock(&memdrawlock);
167 		return nil;
168 	}
169 	r = Rect(Left, Top, g->wid-Right, g->ht-Bottom);
170 	memfillcolor(m, DTransparent);
171 
172 	/* x axis */
173 	memimagedraw(m, Rect(r.min.x, r.max.y, r.max.x, r.max.y+1), black, ZP, memopaque, ZP, S);
174 
175 	/* y labels */
176 	drawlabel(m, r.min, max);
177 	if(min != 0)
178 		drawlabel(m, Pt(r.min.x, r.max.y-smallfont->height), min);
179 
180 	/* actual data */
181 	for(i=0; i<nbin; i++){
182 		b = &bin[i];
183 		if(b->nsamp == 0)
184 			continue;
185 		lo = scalept(b->min, min, max, r.max.y, r.min.y);
186 		hi = scalept(b->max, min, max, r.max.y, r.min.y);
187 		x = r.min.x+i;
188 		hi-=2;
189 		memimagedraw(m, Rect(x, hi, x+1,lo), hifill[g->fill%nelem(hifill)], ZP, memopaque, ZP, S);
190 		memimagedraw(m, Rect(x, lo, x+1, r.max.y), lofill[g->fill%nelem(lofill)], ZP, memopaque, ZP, S);
191 	}
192 
193 	if(bin[nbin-1].nsamp)
194 		drawlabel(m, Pt(r.max.x, r.min.y+(Dy(r)-smallfont->height)/2), bin[nbin-1].avg);
195 	qunlock(&memdrawlock);
196 	return m;
197 }
198