1 #include <all.h>
2
3 /*
4 * See st.c for a description of the data structures.
5 *
6 * Pos is the time and pixel slice into the time window shown
7 * and the rectangle plotted.
8 */
9 typedef struct Pos Pos;
10
11 struct Pos
12 {
13 vlong t0;
14 vlong ival;
15 int p0;
16 int pend;
17 vlong npp; /* ns per pix at this scale */
18 };
19
20 static char *plumbfname = "ptrace.out";
21 static char *infname;
22 int what, verb, newwin;
23 Biobuf *bout;
24 static St *(*readst)(Biobuf*);
25
26 int mainstacksize = Stack;
27
28 static int piddx, graphdy;
29 static Rectangle plotr;
30 static Image *im, *bgcol, *rdycol, *waitcol, *runcol;
31 // These are aliases:
32 static Image *setcol, *sccol, *pfcol, *faultcol;
33
34 static Channel *eventc;
35 static Mousectl *mousectl;
36 static Keyboardctl *keyboardctl;
37 static Proc *current;
38
39 static Cursor crosscursor = {
40 {-7, -7},
41 {0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
42 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF,
43 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0x03, 0xC0,
44 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, },
45 {0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
46 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x7F, 0xFE,
47 0x7F, 0xFE, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
48 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, }
49 };
50
51 Cursor busycursor ={
52 {-1, -1},
53 {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00,
54 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0,
55 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0,
56 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, },
57 {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00,
58 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0,
59 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40,
60 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, }
61 };
62
63 Cursor leftcursor = {
64 {-8, -7},
65 {0x07, 0xc0, 0x04, 0x40, 0x04, 0x40, 0x04, 0x58,
66 0x04, 0x68, 0x04, 0x6c, 0x04, 0x06, 0x04, 0x02,
67 0x04, 0x06, 0x04, 0x6c, 0x04, 0x68, 0x04, 0x58,
68 0x04, 0x40, 0x04, 0x40, 0x04, 0x40, 0x07, 0xc0, },
69 {0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
70 0x03, 0x90, 0x03, 0x90, 0x03, 0xf8, 0x03, 0xfc,
71 0x03, 0xf8, 0x03, 0x90, 0x03, 0x90, 0x03, 0x80,
72 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, }
73 };
74
75 Cursor rightcursor = {
76 {-7, -7},
77 {0x03, 0xe0, 0x02, 0x20, 0x02, 0x20, 0x1a, 0x20,
78 0x16, 0x20, 0x36, 0x20, 0x60, 0x20, 0x40, 0x20,
79 0x60, 0x20, 0x36, 0x20, 0x16, 0x20, 0x1a, 0x20,
80 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x03, 0xe0, },
81 {0x00, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
82 0x09, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x3f, 0xc0,
83 0x1f, 0xc0, 0x09, 0xc0, 0x09, 0xc0, 0x01, 0xc0,
84 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, }
85 };
86
87 static void
busy(void)88 busy(void)
89 {
90 setcursor(mousectl, &busycursor);
91 }
92
93 enum{Browsing, Paused};
94 static void
ready(int state)95 ready(int state)
96 {
97 if(state == Paused)
98 setcursor(mousectl, nil);
99 else
100 setcursor(mousectl, &crosscursor);
101 }
102
103 static void
clear(void)104 clear(void)
105 {
106 if(im != nil)
107 if(Dx(screen->r) != Dx(im->r) || Dy(screen->r) != Dy(im->r)){
108 freeimage(im);
109 im = nil;
110 }
111 if(im == nil)
112 im = allocimage(display, screen->r, screen->chan, 0, -1);
113 if(im == nil)
114 sysfatal("allocimage: %r");
115 draw(im, im->r, bgcol, nil, ZP);
116 plotr = im->r;
117 plotr.min.x += piddx;
118 plotr.min.y += font->height+1;
119 }
120
121 enum{ All, TimeAndPids, JustTime };
122 static void
flush(int justtime)123 flush(int justtime)
124 {
125 Rectangle r;
126
127 r = screen->r;
128 if(justtime)
129 r.max.y = r.min.y + font->height;
130 draw(screen, r, im, nil, im->r.min);
131 if(justtime == TimeAndPids){
132 r = screen->r;
133 r.min.y += font->height;
134 r.max.x = r.min.x + piddx;
135 draw(screen, r, im, nil, r.min);
136 }
137 flushimage(display, 1);
138 }
139
140 static int
proclocate(Proc * p,vlong t,int * ip)141 proclocate(Proc *p, vlong t, int *ip)
142 {
143 int i, id;
144
145 for(i = 0; i < p->nstate; i++){
146 id = p->state[i];
147 if(graph[id]->time > t)
148 break;
149 }
150 if(i == 0)
151 *ip = i;
152 else
153 *ip = --i;
154 return p->state[i];
155 }
156
157 /*
158 * Fill up pp, after the user changes Pos.t0 and/or Pos.ival.
159 * Locate sets [s0:send] in procs, used later to plot them.
160 */
161 static void
locate(Pos * pp)162 locate(Pos *pp)
163 {
164 int i, pmin, pmax, x;
165
166 pmin = 0;
167 pmax = ngraph;
168 for(i = 0; i < nproc; i++){
169 Proc *p = &proc[i];
170 x = proclocate(p, pp->t0, &p->s0);
171 if(x < pmin)
172 pmin = x;
173 x = proclocate(p, pp->t0+pp->ival, &p->send);
174 p->send++;
175 if(x > pmax)
176 pmax = x;
177 }
178 pp->p0 = pmin;
179 pp->pend = pmax+1;
180 if(Dx(plotr) > 0)
181 pp->npp = pp->ival / (vlong)Dx(plotr);
182 }
183
184 static int infominx, infomaxx;
185
186 static void
drawtime(vlong t,vlong ival)187 drawtime(vlong t, vlong ival)
188 {
189 Rectangle r;
190 char s[80];
191 Point p;
192
193 r = im->r;
194 r.max.y = r.min.y + font->height;
195 draw(im, r, bgcol, nil, ZP);
196 seprint(s, s+sizeof s, "t: %#T", t);
197 p = Pt(im->r.max.x - stringwidth(font, s) - 1, r.min.y);
198 string(im, p, display->black, ZP, font, s);
199 infomaxx = p.x-1;
200 infominx = im->r.min.x;
201 if(ival > 0){
202 seprint(s, s+sizeof s, "ival: %#T", ival);
203 infominx = im->r.min.x+1 + stringwidth(font, s)+1;
204 if(infomaxx < infominx)
205 return;
206 p = Pt(im->r.min.x+1, r.min.y);
207 string(im, p, display->black, ZP, font, s);
208 }
209 }
210
211 static void
drawpid(Proc * pp)212 drawpid(Proc *pp)
213 {
214 Point p;
215 St *g;
216 char spid[80];
217
218 p.x = im->r.min.x;
219 p.y = im->r.min.y + graphdy * (pp->row+1);
220 if(p.y >= im->r.max.y)
221 return;
222 g = pgraph(pp, pp->s0);
223 draw(im, Rpt(p, addpt(p, Pt(piddx, font->height))), bgcol, nil, ZP);
224 if(g->pid > 0){
225 seprint(spid, spid+sizeof spid, "%-4.4s% udm%ud", g->name, g->pid, g->machno);
226 if(pp == current)
227 string(im, p, setcol, ZP, font, spid);
228 else
229 string(im, p, display->black, ZP, font, spid);
230 }
231 }
232
233 static void
drawnotice(char * s)234 drawnotice(char *s)
235 {
236 Point p;
237 int dx, w, n;
238 char buf[80];
239 Rectangle r;
240
241 dx = infomaxx - infominx;
242 r = Rect(infominx, im->r.min.y, infomaxx, im->r.min.y+graphdy);
243 draw(im, r, bgcol, nil, ZP);
244 w = stringwidth(font, s);
245 if(w + 2 > dx){
246 seprint(buf, buf+sizeof buf, s);
247 s = buf;
248 for(n = strlen(s); n > 0; n--){
249 w = stringwidth(font, s);
250 if(dx > w+2)
251 break;
252 s[n-1] = 0;
253 }
254 if(n == 0)
255 return;
256 }
257 p = Pt(infominx + dx/2 - w/2, im->r.min.y);
258 string(im, p, setcol, ZP, font, s);
259 }
260
261 static void
drawinfo(St * g)262 drawinfo(St *g)
263 {
264 char s[80];
265
266 seprint(s, s+sizeof s, "%#G", g);
267 drawnotice(s);
268 }
269
270 static int
dtwidth(vlong dt,vlong nsperpix)271 dtwidth(vlong dt, vlong nsperpix)
272 {
273 if(dt < 0)
274 return 0;
275 if(nsperpix <= 0)
276 return Dx(plotr);
277 return (int)(dt / nsperpix);
278 }
279
280 /*
281 * Try to draw events within the state represented by g
282 * ending in eg, if the scale permits.
283 */
284 static void
drawgraphs(St * g,St * eg,Point pt,Pos p)285 drawgraphs(St *g, St *eg, Point pt, Pos p)
286 {
287 int x, faults, scs, pfs;
288 vlong t, t0, dt;
289 Rectangle r;
290
291 x = pt.x;
292 t0 = g->time;
293 t = t0;
294 pfs = faults = scs = 0;
295 while(g->pnext != 0 && graph[g->pnext] != eg){
296 g = graph[g->pnext];
297 g->x = x;
298 if(g->etype == STrap)
299 if(g->arg&(STrapRPF|STrapWPF))
300 pfs++;
301 else if(g->arg&STrapSC)
302 scs++;
303 else
304 faults++;
305 dt = g->time - t;
306 if(dt < p.npp)
307 continue;
308 if(scs){
309 r = Rect(x, pt.y-3*Wid/2, x+Wid, pt.y-Wid/2);
310 draw(im, r, sccol, nil, ZP);
311 }
312 if(faults || pfs){
313 r = Rect(x, pt.y+3*Wid/2, x+Wid, pt.y+5*Wid/2);
314 draw(im, r, pfs?pfcol:faultcol, nil, ZP);
315 }
316 faults = pfs = scs = 0;
317 t = g->time;
318 x = plotr.min.x + dtwidth(t-p.t0, p.npp);
319 }
320 }
321
322 static void
drawproc(Proc * pp,Pos p)323 drawproc(Proc *pp, Pos p)
324 {
325 St *g, *ng;
326 int s;
327 Image *c;
328 vlong t0, tn, frac;
329 int x0, xn;
330 Rectangle r;
331
332 frac = 0;
333 r = plotr;
334 r.min.y += graphdy * pp->row + graphdy/2;
335 r.max.y = r.min.y + Wid;
336 for(s = pp->s0; s < pp->send; s++){
337 g = pgraph(pp, s);
338 switch(g->state){
339 case SRun:
340 c = runcol;
341 break;
342 case SDead:
343 c = bgcol;
344 break;
345 case SReady:
346 c = rdycol;
347 break;
348 default:
349 c = waitcol;
350 }
351 t0 = g->time - p.t0;
352 if(s < pp->nstate-1){
353 ng = pgraph(pp, s+1);
354 tn = ng->time - p.t0;
355 }else
356 break;
357 x0 = dtwidth(t0, p.npp);
358 xn = dtwidth(tn+frac, p.npp);
359 g->x = plotr.min.x + x0;
360 r.min.x = g->x;
361 if(xn == x0){
362 frac += tn-t0;
363 continue;
364 }
365 frac = 0;
366 if(xn - x0 < Wid)
367 xn = x0 + Wid;
368 r.max.x = plotr.min.x + xn;
369 draw(im, r, c, nil, ZP);
370 drawgraphs(g, ng, r.min, p);
371 }
372 if(s < pp->nstate)
373 pgraph(pp, s)->x = r.max.x;
374 }
375
376 /*
377 * Plot for the range indicated in pos.
378 * Processes must be located before.
379 * This updates St.x in the states shown for procs.
380 */
381 static void
plotallat(Pos p)382 plotallat(Pos p)
383 {
384 int i;
385
386 clear();
387 for(i = 0; i < nproc; i++){
388 drawpid(&proc[i]);
389 drawproc(&proc[i], p);
390 }
391 drawtime(p.t0, p.ival);
392 }
393
394 static Point
ptinplot(Point pt)395 ptinplot(Point pt)
396 {
397 if(pt.y < plotr.min.y)
398 pt.y = plotr.min.y;
399 if(pt.y > plotr.max.y-1)
400 pt.y = plotr.max.y-1;
401 if(pt.x < plotr.min.x)
402 pt.x = plotr.min.x;
403 if(pt.x > plotr.max.x-1)
404 pt.x = plotr.max.x-1;
405 return pt;
406 }
407
408 static int
ptrow(Point pt)409 ptrow(Point pt)
410 {
411 return (pt.y - plotr.min.y) / graphdy;
412 }
413
414 static Proc*
procat(Point pt)415 procat(Point pt)
416 {
417 int row, i;
418 Proc *pp;
419
420 row = ptrow(pt);
421 for(i = 0; i < nproc; i++){
422 pp = &proc[i];
423 if(pp->s0 < pp->send && pp->row == row)
424 return pp;
425 }
426 return nil;
427 }
428
429 static int
stateat(Proc * pp,Point pt)430 stateat(Proc *pp, Point pt)
431 {
432 int s, last;
433 St *g;
434
435 last = pp->s0;
436 for(s = pp->s0; s < pp->send; s++){
437 g = pgraph(pp, s);
438 if(pt.x < g->x)
439 break;
440 last = s;
441 }
442 return last;
443 }
444
445 static St*
graphat(Proc * pp,int s,Point pt,vlong npp)446 graphat(Proc *pp, int s, Point pt, vlong npp)
447 {
448 St *g0, *g, *ng, *eg;
449
450 g0 = pgraph(pp, s);
451
452 /* If all's in a pixel, don't bother */
453 if(s < pp->send-1){
454 eg = pgraph(pp, s+1);
455 if(eg->time - g0->time < npp)
456 return g0;
457 }else
458 eg = nil;
459 for(g = g0; g->pnext != 0 && graph[g->pnext] != eg; g = ng){
460 ng = graph[g->pnext];
461 if(ng->x > pt.x)
462 break;
463 }
464 return g;
465 }
466
467 static void
tplumb(vlong t)468 tplumb(vlong t)
469 {
470 static int fd = -1;
471 Plumbmsg *pm;
472 static char wd[128];
473 Plumbattr *attr;
474
475 if(fd < 0)
476 fd = plumbopen("send", OWRITE);
477 if(fd < 0){
478 fprint(2, "%s: plumbopen: %r\n", argv0);
479 return;
480 }
481 if(wd[0] == 0)
482 getwd(wd, sizeof wd);
483
484 pm = mallocz(sizeof *pm, 1);
485 attr = mallocz(sizeof *attr, 1);
486 if(pm == nil || attr == nil){
487 free(pm);
488 fprint(2, "%s: no memory\n", argv0);
489 return;
490 }
491 pm->src = strdup(argv0);
492 pm->dst = strdup("edit");
493 pm->wdir = strdup(wd);
494 pm->type = strdup("text");
495 pm->data = strdup(plumbfname);
496 pm->ndata = strlen(pm->data);
497 attr->name = strdup("addr");
498 attr->value = smprint("/^%T .*\\n", t);
499
500 pm->attr = plumbaddattr(pm->attr, attr);
501 plumbsend(fd, pm);
502 }
503
504 static void
cursorat(Point pt,int doplumb,Pos p)505 cursorat(Point pt, int doplumb, Pos p)
506 {
507 Proc *pp, *old;
508 St *g;
509 int gi, dx;
510
511 pt = ptinplot(pt);
512 pp = procat(pt);
513 if(pp == nil)
514 return;
515 gi = stateat(pp, pt);
516 g = graphat(pp, gi, pt, p.npp);
517
518 dx = pt.x - plotr.min.x;
519 drawtime(p.t0 + dx * p.npp, p.ival);
520 drawinfo(g);
521 old = current;
522 current = pp;
523 if(old != nil)
524 drawpid(old);
525 drawpid(current);
526 flush(TimeAndPids);
527 if(doplumb)
528 tplumb(g->time);
529 }
530
531 static void
printproc(Biobuf * b,Proc * pp,vlong t0,vlong ival)532 printproc(Biobuf *b, Proc *pp, vlong t0, vlong ival)
533 {
534 St *g0, *ge, *g;
535 vlong tend;
536
537 if(t0 < 0 || ival < 0){
538 t0 = 0;
539 tend = graph[ngraph-1]->time + 1;
540 }else
541 tend = t0+ival;
542 ge = pgraph(pp, pp->send-1);
543 g0 = pgraph(pp, pp->s0);
544
545 for(g = g0; g != ge; g = graph[g->pnext])
546 if(g->time >= t0 && g->time < tend)
547 Bprint(b, "%G\n", g);
548 }
549
550 static void
printallat(Biobuf * b,vlong t0,vlong ival,int rmin,int rend)551 printallat(Biobuf *b, vlong t0, vlong ival, int rmin, int rend)
552 {
553 Biobuf *bout;
554 int i;
555
556 if(rmin < 0 || rend < 0){
557 rmin = 0;
558 rend = nproc;
559 }else if(rend > nproc)
560 rend = nproc;
561
562 if(b != nil)
563 bout = b;
564 else{
565 bout = Bopen("ptrace.out", OWRITE);
566 if(bout == nil){
567 drawnotice("write failed");
568 flush(JustTime);
569 return;
570 }
571 }
572 for(i = rmin; i < rend; i++)
573 printproc(bout, &proc[i], t0, ival);
574
575 Bprint(bout, "\n");
576
577 if(b == nil){
578 drawnotice("written ptrace.out");
579 flush(JustTime);
580 Bterm(bout);
581 }else
582 Bflush(b);
583 }
584
585 static void
flagsweep(Point p0)586 flagsweep(Point p0)
587 {
588 line(screen, Pt(p0.x, p0.y-8), Pt(p0.x, p0.y+8),
589 ARROW(4, 4, 2), ARROW(4, 4, 2), 1, display->black, ZP);
590 line(screen, Pt(p0.x-10, p0.y), Pt(p0.x+10, p0.y),
591 ARROW(4, 4, 2), ARROW(4, 4, 2), 1, display->black, ZP);
592 flushimage(display, 1);
593 }
594
595 static void
sweep(int b,Point p0,Pos * p)596 sweep(int b, Point p0, Pos *p)
597 {
598 enum{None, Left, Right};
599 int where, rmin, rend;
600 Point pt;
601 Rectangle r;
602 Mouse m;
603 Pos np;
604
605 p0 = ptinplot(p0);
606 flagsweep(p0);
607 where = None;
608 do{
609 recv(mousectl->c, &m);
610 pt = ptinplot(m.xy);
611 if(pt.x > p0.x && where != Right){
612 setcursor(mousectl, &rightcursor);
613 where = Right;
614 }else if(pt.x <= p0.x && where != Left){
615 setcursor(mousectl, &leftcursor);
616 where = Left;
617 }
618 r = canonrect(Rpt(p0, pt));
619 }while(m.buttons);
620
621 np = *p;
622 np.t0 += (r.min.x-plotr.min.x) * np.npp;
623 if(np.t0 > graph[ngraph-1]->time)
624 np.t0 = graph[ngraph-1]->time;
625
626 np.ival = np.npp * Dx(r);
627 if(np.ival < US(1))
628 np.ival = US(1);
629 if(np.ival > graph[ngraph-1]->time + US(1))
630 np.ival = graph[ngraph-1]->time + US(1);
631
632 rmin = ptrow(r.min);
633 rend = ptrow(r.max) + 1;
634 switch(b){
635 case 1:
636 *p = np;
637 locate(p);
638 break;
639 case 2:
640 printallat(nil, np.t0, np.ival, rmin, rend);
641 break;
642 case 4:
643 printallat(bout, np.t0, np.ival, rmin, rend);
644 break;
645 }
646 }
647
648 static void
setrows(void)649 setrows(void)
650 {
651 int i;
652
653 for(i = 0; i < nproc; i++)
654 proc[i].row = i;
655 }
656
657 static void
debugdump(Pos p)658 debugdump(Pos p)
659 {
660 Proc *pp;
661 int i;
662
663 Bprint(bout, "pos p0 %d pend %d t0 %T ival %T\n",
664 p.p0, p.pend, p.t0, p.ival);
665 for(i = 0; i < nproc; i++){
666 pp = &proc[i];
667 Bprint(bout, "proc %d pid %d s0 %d send %d ns %d\n",
668 i, pp->pid, pp->s0, pp->send, pp->nstate);
669 }
670 // XXX
671 pp = &proc[13];
672 Bprint(bout, "%R\n", plotr);
673 for(i = pp->s0; i < pp->send; i++)
674 Bprint(bout, "x %d %G\n", pgraph(pp, i)->x, pgraph(pp, i));
675 Bflush(bout);
676 }
677
678 static void
browse(void)679 browse(void)
680 {
681 Rune r;
682 Mouse m;
683 Pos p;
684 vlong tmax;
685 int paused, b;
686 Point lastxy;
687 enum{Ptr, Rsz, Kbd};
688 Alt a[] = {
689 {mousectl->c, &m, CHANRCV},
690 {mousectl->resizec, nil, CHANRCV},
691 {keyboardctl->c, &r, CHANRCV},
692 {nil, nil, CHANEND}
693 };
694
695
696 setrows();
697 restart:
698 p.p0 = 0;
699 p.pend = ngraph;
700 p.ival = graph[ngraph-1]->time + US(1);
701 p.t0 = 0;
702 busy();
703 clear(); /* set plotr; locate uses that */
704 locate(&p);
705 tmax = p.ival;
706 paused = Browsing;
707 plotallat(p);
708 flush(All);
709 for(;;){
710 ready(paused);
711 switch(alt(a)){
712 case Rsz:
713 if(getwindow(display, Refnone) < 0)
714 sysfatal("getwindow: %r");
715 if(im != nil)
716 freeimage(im);
717 im = nil;
718 redraw:
719 busy();
720 plotallat(p);
721 flush(All);
722 while(nbrecv(keyboardctl->c, &r) != 0)
723 ;
724 break;
725 case Ptr:
726 b = 0;
727 if(m.buttons){
728 b = m.buttons;
729 lastxy = m.xy;
730 recv(mousectl->c, &m);
731 if(m.buttons == 0){
732 if(b == 1 && lastxy.y < plotr.min.y)
733 if(lastxy.x < plotr.min.x + Dx(plotr))
734 goto right;
735 else
736 goto left;
737 }else {
738 busy();
739 sweep(b, lastxy, &p);
740 goto redraw;
741 }
742 }else
743 while(nbrecv(mousectl->c, &m) != 0)
744 ;
745 if(paused)
746 break;
747
748 if(ptinrect(m.xy, plotr) && (b==4 || !eqpt(lastxy, m.xy))){
749 cursorat(m.xy, b==4, p);
750 lastxy = m.xy;
751 }
752 break;
753 case Kbd:
754 switch(r){
755 case 'D':
756 debugdump(p);
757 break;
758 case Kesc:
759 busy();
760 goto restart;
761 case ' ':
762 paused = !paused;
763 break;
764 case 'q':
765 Bterm(bout);
766 threadexitsall(nil);
767 case '+':
768 case Kup:
769 busy();
770 p.ival /= 2;
771 if(p.ival < US(1))
772 p.ival = US(1);
773 locate(&p);
774 goto redraw;
775 case '-':
776 case Kdown:
777 if(p.ival > tmax)
778 break;
779 busy();
780 p.ival *= 2;
781 locate(&p);
782 goto redraw;
783 case Kright:
784 right:
785 busy();
786 p.t0 += p.ival/Scroll;
787 if(p.t0 > graph[ngraph-1]->time)
788 p.t0 = graph[ngraph-1]->time;
789 locate(&p);
790 goto redraw;
791 break;
792 case Kleft:
793 left:
794 if(p.t0 < p.ival/Scroll)
795 break;
796 busy();
797 p.t0 -= p.ival/Scroll;
798 locate(&p);
799 goto redraw;
800 break;
801 case 's':
802 busy();
803 printallat(nil, -1, -1, -1, -1);
804 break;
805 case 'p':
806 busy();
807 printallat(bout, -1, -1, -1, -1);
808 break;
809 }
810 break;
811 default:
812 sysfatal("alt: %r");
813 }
814 }
815 }
816
817 static void
mkwin(int dx,int dy)818 mkwin(int dx, int dy)
819 {
820 char *wsys, line[256];
821 int wfd;
822
823 if((wsys = getenv("wsys")) == nil)
824 sysfatal("no wsys: %r");
825 if((wfd = open(wsys, ORDWR)) < 0)
826 sysfatal("open wsys: %r");
827 snprint(line, sizeof(line), "new -pid %d -dx %d -dy %d",
828 getpid(), dx, dy);
829 line[sizeof(line) - 1] = '\0';
830 rfork(RFNAMEG);
831 if(mount(wfd, -1, "/mnt/wsys", MREPL, line) < 0)
832 sysfatal("mount wsys: %r");
833 if(bind("/mnt/wsys", "/dev", MBEFORE) < 0)
834 sysfatal("mount wsys: %r");
835 }
836
837 static void
colors(void)838 colors(void)
839 {
840 piddx = stringwidth(font, "XXXXX" "XXXXXmXX"); /* 5 for name, 5 for pid */
841 graphdy = font->height + 1;
842 bgcol = allocimagemix(display, DPalebluegreen, DWhite);
843 rdycol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreen);
844 waitcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DRed);
845 runcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DBlue);
846 if(bgcol == nil || rdycol == nil || waitcol == nil || runcol == nil)
847 sysfatal("color: %r");
848 setcol = runcol;
849 sccol = runcol;
850 pfcol = waitcol;
851 faultcol = display->black;
852 }
853
854 static void
usage(void)855 usage(void)
856 {
857 fprint(2, "Usage: %s [-dgpw] file\n", argv0);
858 exits(nil);
859 }
860
861 void
threadmain(int argc,char ** argv)862 threadmain(int argc, char **argv)
863 {
864 int isdev, i;
865
866 isdev = 0;
867
868 ARGBEGIN {
869 case 'd':
870 isdev = 1;
871 break;
872 case 'g':
873 what |= Plot;
874 break;
875 case 'p':
876 what |= Dump;
877 break;
878 case 'v':
879 verb++;
880 break;
881 case 'w':
882 newwin++;
883 break;
884 default:
885 usage();
886 }
887 ARGEND;
888
889 if(argc != 1)
890 usage();
891 infname = argv[0];
892 if(!isdev)
893 plumbfname = argv[0];
894 if(what == 0)
895 what = Dump;
896
897 bout = Bopen("/fd/1", OWRITE);
898 if(bout == nil)
899 sysfatal("stdout: Bopen: %r");
900
901 fmtinstall('T', Tfmt);
902 fmtinstall('G', Gfmt);
903
904 readall(infname, isdev);
905 if(ngraph == 0)
906 sysfatal("nothing to plot");
907
908 makeprocs();
909
910 if(what&Dump)
911 for(i = 0; i < ngraph; i++)
912 if(Bprint(bout, "%G\n", graph[i]) < 0)
913 sysfatal("out: %r");
914
915 if((what&Plot) == 0){
916 Bterm(bout);
917 exits(nil);
918 }
919
920 if(Bflush(bout) < 0)
921 sysfatal("out: %r");
922 eventc = chancreate(sizeof(ulong), 10);
923 if(eventc == nil)
924 sysfatal("no memory");
925 if(newwin)
926 mkwin(Wx, Wy);
927 if(initdraw(nil, "/lib/font/bit/pelm/unicode.8.font", argv0) < 0)
928 if(initdraw(nil, nil, argv0) < 0)
929 sysfatal("initdraw: %r");
930 colors();
931 if((mousectl = initmouse(nil, screen)) == nil)
932 sysfatal("mouse: %r");
933 if((keyboardctl = initkeyboard(nil)) == nil)
934 sysfatal("keyboard: %r");
935 browse();
936 Bterm(bout);
937 }
938