xref: /plan9/sys/src/cmd/trace.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
137aecfafSDavid du Colombier #include <u.h>
237aecfafSDavid du Colombier #include <tos.h>
337aecfafSDavid du Colombier #include <libc.h>
437aecfafSDavid du Colombier #include <thread.h>
537aecfafSDavid du Colombier #include <ip.h>
637aecfafSDavid du Colombier #include <bio.h>
737aecfafSDavid du Colombier #include <draw.h>
837aecfafSDavid du Colombier #include <mouse.h>
937aecfafSDavid du Colombier #include <cursor.h>
1037aecfafSDavid du Colombier #include <keyboard.h>
1137aecfafSDavid du Colombier #include "trace.h"
1237aecfafSDavid du Colombier 
1337aecfafSDavid du Colombier #pragma	varargck	type	"t"		vlong
1437aecfafSDavid du Colombier #pragma	varargck	type	"U"		uvlong
1537aecfafSDavid du Colombier 
1637aecfafSDavid du Colombier #define NS(x)	((vlong)x)
1737aecfafSDavid du Colombier #define US(x)	(NS(x) * 1000ULL)
1837aecfafSDavid du Colombier #define MS(x)	(US(x) * 1000ULL)
1937aecfafSDavid du Colombier #define S(x)	(MS(x) * 1000ULL)
2037aecfafSDavid du Colombier 
2137aecfafSDavid du Colombier #define numblocks(a, b)	(((a) + (b) - 1) / (b))
2237aecfafSDavid du Colombier #define roundup(a, b)	(numblocks((a), (b)) * (b))
2337aecfafSDavid du Colombier 
2437aecfafSDavid du Colombier enum {
2537aecfafSDavid du Colombier 	OneRound = MS(1)/2LL,
2637aecfafSDavid du Colombier 	MilliRound = US(1)/2LL,
2737aecfafSDavid du Colombier };
2837aecfafSDavid du Colombier 
2937aecfafSDavid du Colombier typedef struct Event	Event;
3037aecfafSDavid du Colombier typedef struct Task	Task;
3137aecfafSDavid du Colombier struct Event {
3237aecfafSDavid du Colombier 	Traceevent;
3337aecfafSDavid du Colombier 	vlong	etime;	/* length of block to draw */
3437aecfafSDavid du Colombier };
3537aecfafSDavid du Colombier 
3637aecfafSDavid du Colombier struct Task {
3737aecfafSDavid du Colombier 	int	pid;
3837aecfafSDavid du Colombier 	char	*name;
3937aecfafSDavid du Colombier 	int	nevents;
4037aecfafSDavid du Colombier 	Event	*events;
4137aecfafSDavid du Colombier 	vlong	tstart;
4237aecfafSDavid du Colombier 	vlong	total;
4337aecfafSDavid du Colombier 	vlong	runtime;
4437aecfafSDavid du Colombier 	vlong	runmax;
4537aecfafSDavid du Colombier 	vlong	runthis;
4637aecfafSDavid du Colombier 	long	runs;
4737aecfafSDavid du Colombier 	ulong	tevents[Nevent];
4837aecfafSDavid du Colombier };
4937aecfafSDavid du Colombier 
5037aecfafSDavid du Colombier enum {
5137aecfafSDavid du Colombier 	Nevents = 1024,
5237aecfafSDavid du Colombier 	Ncolor = 6,
5337aecfafSDavid du Colombier 	K = 1024,
5437aecfafSDavid du Colombier };
5537aecfafSDavid du Colombier 
5637aecfafSDavid du Colombier vlong	now, prevts;
5737aecfafSDavid du Colombier 
5837aecfafSDavid du Colombier int	newwin;
5937aecfafSDavid du Colombier int	Width = 1000;
6037aecfafSDavid du Colombier int	Height = 100;		// Per task
6137aecfafSDavid du Colombier int	topmargin = 8;
6237aecfafSDavid du Colombier int	bottommargin = 4;
6337aecfafSDavid du Colombier int	lineht = 12;
6437aecfafSDavid du Colombier int	wctlfd;
6537aecfafSDavid du Colombier int	nevents;
6637aecfafSDavid du Colombier Traceevent *eventbuf;
6737aecfafSDavid du Colombier Event	*event;
6837aecfafSDavid du Colombier 
6937aecfafSDavid du Colombier void drawtrace(void);
7037aecfafSDavid du Colombier int schedparse(char*, char*, char*);
7137aecfafSDavid du Colombier int timeconv(Fmt*);
7237aecfafSDavid du Colombier 
7337aecfafSDavid du Colombier char *schedstatename[] = {
7437aecfafSDavid du Colombier 	[SAdmit] =	"Admit",
7537aecfafSDavid du Colombier 	[SSleep] =	"Sleep",
7637aecfafSDavid du Colombier 	[SDead] =	"Dead",
7737aecfafSDavid du Colombier 	[SDeadline] =	"Deadline",
7837aecfafSDavid du Colombier 	[SEdf] =	"Edf",
7937aecfafSDavid du Colombier 	[SExpel] =	"Expel",
8037aecfafSDavid du Colombier 	[SReady] =	"Ready",
8137aecfafSDavid du Colombier 	[SRelease] =	"Release",
8237aecfafSDavid du Colombier 	[SRun] =	"Run",
8337aecfafSDavid du Colombier 	[SSlice] =	"Slice",
8437aecfafSDavid du Colombier 	[SInts] =	"Ints",
8537aecfafSDavid du Colombier 	[SInte] =	"Inte",
8637aecfafSDavid du Colombier 	[SUser] = 	"User",
8737aecfafSDavid du Colombier 	[SYield] =	"Yield",
8837aecfafSDavid du Colombier };
8937aecfafSDavid du Colombier 
9037aecfafSDavid du Colombier struct {
9137aecfafSDavid du Colombier 	vlong	scale;
9237aecfafSDavid du Colombier 	vlong	bigtics;
9337aecfafSDavid du Colombier 	vlong	littletics;
9437aecfafSDavid du Colombier 	int	sleep;
9537aecfafSDavid du Colombier } scales[] = {
9637aecfafSDavid du Colombier 	{	US(500),	US(100),	US(50),		  0},
9737aecfafSDavid du Colombier 	{	US(1000),	US(500),	US(100),	  0},
9837aecfafSDavid du Colombier 	{	US(2000),	US(1000),	US(200),	  0},
9937aecfafSDavid du Colombier 	{	US(5000),	US(1000),	US(500),	  0},
10037aecfafSDavid du Colombier 	{	MS(10),		MS(5),		MS(1),		 20},
10137aecfafSDavid du Colombier 	{	MS(20),		MS(10),		MS(2),		 20},
10237aecfafSDavid du Colombier 	{	MS(50),		MS(10),		MS(5),		 20},
10337aecfafSDavid du Colombier 	{	MS(100),	MS(50),		MS(10),		 20},	/* starting scaleno */
10437aecfafSDavid du Colombier 	{	MS(200),	MS(100),	MS(20),		 20},
10537aecfafSDavid du Colombier 	{	MS(500),	MS(100),	MS(50),		 50},
10637aecfafSDavid du Colombier 	{	MS(1000),	MS(500),	MS(100),	100},
10737aecfafSDavid du Colombier 	{	MS(2000),	MS(1000),	MS(200),	100},
10837aecfafSDavid du Colombier 	{	MS(5000),	MS(1000),	MS(500),	100},
10937aecfafSDavid du Colombier 	{	S(10),		S(50),		S(1),		100},
11037aecfafSDavid du Colombier 	{	S(20),		S(10),		S(2),		100},
11137aecfafSDavid du Colombier 	{	S(50),		S(10),		S(5),		100},
11237aecfafSDavid du Colombier 	{	S(100),		S(50),		S(10),		100},
11337aecfafSDavid du Colombier 	{	S(200),		S(100),		S(20),		100},
11437aecfafSDavid du Colombier 	{	S(500),		S(100),		S(50),		100},
11537aecfafSDavid du Colombier 	{	S(1000),	S(500),		S(100),		100},
11637aecfafSDavid du Colombier };
11737aecfafSDavid du Colombier 
11815174232SDavid du Colombier int ntasks, verbose, triggerproc, paused;
11937aecfafSDavid du Colombier Task *tasks;
12037aecfafSDavid du Colombier Image *cols[Ncolor][4];
12137aecfafSDavid du Colombier Font *mediumfont, *tinyfont;
12237aecfafSDavid du Colombier Image *grey, *red, *green, *blue, *bg, *fg;
12337aecfafSDavid du Colombier char*profdev = "/proc/trace";
12437aecfafSDavid du Colombier 
12537aecfafSDavid du Colombier static void
usage(void)12637aecfafSDavid du Colombier usage(void)
12737aecfafSDavid du Colombier {
12815174232SDavid du Colombier 	fprint(2, "Usage: %s [-d profdev] [-w] [-v] [-t triggerproc] [processes]\n", argv0);
12937aecfafSDavid du Colombier 	exits(nil);
13037aecfafSDavid du Colombier }
13137aecfafSDavid du Colombier 
13237aecfafSDavid du Colombier void
threadmain(int argc,char ** argv)13337aecfafSDavid du Colombier threadmain(int argc, char **argv)
13437aecfafSDavid du Colombier {
13537aecfafSDavid du Colombier 	int fd, i;
13637aecfafSDavid du Colombier 	char fname[80];
13737aecfafSDavid du Colombier 
13837aecfafSDavid du Colombier 	fmtinstall('t', timeconv);
13937aecfafSDavid du Colombier 	ARGBEGIN {
14037aecfafSDavid du Colombier 	case 'd':
14137aecfafSDavid du Colombier 		profdev = EARGF(usage());
14237aecfafSDavid du Colombier 		break;
14337aecfafSDavid du Colombier 	case 'v':
14437aecfafSDavid du Colombier 		verbose = 1;
14537aecfafSDavid du Colombier 		break;
14637aecfafSDavid du Colombier 	case 'w':
14737aecfafSDavid du Colombier 		newwin++;
14837aecfafSDavid du Colombier 		break;
14915174232SDavid du Colombier 	case 't':
15015174232SDavid du Colombier 		triggerproc = (int)strtol(EARGF(usage()), nil, 0);
15115174232SDavid du Colombier 		break;
15237aecfafSDavid du Colombier 	default:
15337aecfafSDavid du Colombier 		usage();
15437aecfafSDavid du Colombier 	}
15537aecfafSDavid du Colombier 	ARGEND;
15637aecfafSDavid du Colombier 
15737aecfafSDavid du Colombier 	fname[sizeof fname - 1] = 0;
15837aecfafSDavid du Colombier 	for(i = 0; i < argc; i++){
15937aecfafSDavid du Colombier 		snprint(fname, sizeof fname - 2, "/proc/%s/ctl",
16037aecfafSDavid du Colombier 					argv[i]);
16137aecfafSDavid du Colombier 		if((fd = open(fname, OWRITE)) < 0){
16237aecfafSDavid du Colombier 			fprint(2, "%s: cannot open %s: %r\n",
16337aecfafSDavid du Colombier 						argv[0], fname);
16437aecfafSDavid du Colombier 			continue;
16537aecfafSDavid du Colombier 		}
16637aecfafSDavid du Colombier 
167375daca8SDavid du Colombier 		if(fprint(fd, "trace 1") < 0)
16837aecfafSDavid du Colombier 			fprint(2, "%s: cannot enable tracing on %s: %r\n",
16937aecfafSDavid du Colombier 						argv[0], fname);
17037aecfafSDavid du Colombier 		close(fd);
17137aecfafSDavid du Colombier 	}
17237aecfafSDavid du Colombier 
17337aecfafSDavid du Colombier 	drawtrace();
17437aecfafSDavid du Colombier }
17537aecfafSDavid du Colombier 
17637aecfafSDavid du Colombier static void
mkcol(int i,int c0,int c1,int c2)17737aecfafSDavid du Colombier mkcol(int i, int c0, int c1, int c2)
17837aecfafSDavid du Colombier {
17937aecfafSDavid du Colombier 	cols[i][0] = allocimagemix(display, c0, DWhite);
18037aecfafSDavid du Colombier 	cols[i][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c1);
18137aecfafSDavid du Colombier 	cols[i][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c2);
18237aecfafSDavid du Colombier 	cols[i][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c0);
18337aecfafSDavid du Colombier }
18437aecfafSDavid du Colombier 
18537aecfafSDavid du Colombier static void
colinit(void)18637aecfafSDavid du Colombier colinit(void)
18737aecfafSDavid du Colombier {
18837aecfafSDavid du Colombier 	mediumfont = openfont(display, "/lib/font/bit/lucidasans/unicode.10.font");
18937aecfafSDavid du Colombier 	if(mediumfont == nil)
19037aecfafSDavid du Colombier 		mediumfont = font;
19137aecfafSDavid du Colombier 	tinyfont = openfont(display, "/lib/font/bit/lucidasans/unicode.7.font");
19237aecfafSDavid du Colombier 	if(tinyfont == nil)
19337aecfafSDavid du Colombier 		tinyfont = font;
19437aecfafSDavid du Colombier 	topmargin = mediumfont->height+2;
19537aecfafSDavid du Colombier 	bottommargin = tinyfont->height+2;
19637aecfafSDavid du Colombier 
19737aecfafSDavid du Colombier 	/* Peach */
19837aecfafSDavid du Colombier 	mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
19937aecfafSDavid du Colombier 	/* Aqua */
20037aecfafSDavid du Colombier 	mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
20137aecfafSDavid du Colombier 	/* Yellow */
20237aecfafSDavid du Colombier 	mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
20337aecfafSDavid du Colombier 	/* Green */
20437aecfafSDavid du Colombier 	mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
20537aecfafSDavid du Colombier 	/* Blue */
20637aecfafSDavid du Colombier 	mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
20737aecfafSDavid du Colombier 	/* Grey */
20837aecfafSDavid du Colombier 	cols[5][0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEEEEEEFF);
20937aecfafSDavid du Colombier 	cols[5][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF);
21037aecfafSDavid du Colombier 	cols[5][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x888888FF);
21137aecfafSDavid du Colombier 	cols[5][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAAAAAAFF);
21237aecfafSDavid du Colombier 	grey = cols[5][2];
21337aecfafSDavid du Colombier 	red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFF0000FF);
21437aecfafSDavid du Colombier 	green = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x00FF00FF);
21537aecfafSDavid du Colombier 	blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x0000FFFF);
21637aecfafSDavid du Colombier 	bg = display->white;
21737aecfafSDavid du Colombier 	fg = display->black;
21837aecfafSDavid du Colombier }
21937aecfafSDavid du Colombier 
22037aecfafSDavid du Colombier static void
redraw(int scaleno)22137aecfafSDavid du Colombier redraw(int scaleno)
22237aecfafSDavid du Colombier {
22337aecfafSDavid du Colombier 	int n, i, j, x;
22437aecfafSDavid du Colombier 	char buf[256];
22537aecfafSDavid du Colombier 	Point p, q;
22637aecfafSDavid du Colombier 	Rectangle r, rtime;
22737aecfafSDavid du Colombier 	Task *t;
228375daca8SDavid du Colombier 	vlong ts, oldestts, newestts, period, ppp, scale, s, ss;
22937aecfafSDavid du Colombier 
23037aecfafSDavid du Colombier #	define time2x(t)	((int)(((t) - oldestts) / ppp))
23137aecfafSDavid du Colombier 
23237aecfafSDavid du Colombier 	scale = scales[scaleno].scale;
23337aecfafSDavid du Colombier 	period = scale + scales[scaleno].littletics;
23437aecfafSDavid du Colombier 	ppp = period / Width;	// period per pixel.
23537aecfafSDavid du Colombier 
23637aecfafSDavid du Colombier 	/* Round `now' to a nice number */
23737aecfafSDavid du Colombier 	newestts = now - (now % scales[scaleno].bigtics) +
23837aecfafSDavid du Colombier 			(scales[scaleno].littletics>>1);
23937aecfafSDavid du Colombier 
24037aecfafSDavid du Colombier 	oldestts = newestts - period;
24137aecfafSDavid du Colombier 
24237aecfafSDavid du Colombier //print("newestts %t, period %t, %d-%d\n", newestts, period, time2x(oldestts), time2x(newestts));
24337aecfafSDavid du Colombier 	if (prevts < oldestts){
24437aecfafSDavid du Colombier 		oldestts = newestts - period;
24537aecfafSDavid du Colombier 
24637aecfafSDavid du Colombier 		prevts = oldestts;
24737aecfafSDavid du Colombier 		draw(screen, screen->r, bg, nil, ZP);
24837aecfafSDavid du Colombier 	}else{
24937aecfafSDavid du Colombier 		/* just white out time */
25037aecfafSDavid du Colombier 		rtime = screen->r;
25137aecfafSDavid du Colombier 		rtime.min.x = rtime.max.x - stringwidth(mediumfont, "00000000000.000s");
25237aecfafSDavid du Colombier 		rtime.max.y = rtime.min.y + mediumfont->height;
25337aecfafSDavid du Colombier 		draw(screen, rtime, bg, nil, ZP);
25437aecfafSDavid du Colombier 	}
25537aecfafSDavid du Colombier 	p = screen->r.min;
25637aecfafSDavid du Colombier 	for (n = 0; n != ntasks; n++) {
25737aecfafSDavid du Colombier 		t = &tasks[n];
25837aecfafSDavid du Colombier 		/* p is upper left corner for this task */
25937aecfafSDavid du Colombier 		rtime = Rpt(p, addpt(p, Pt(500, mediumfont->height)));
26037aecfafSDavid du Colombier 		draw(screen, rtime, bg, nil, ZP);
26137aecfafSDavid du Colombier 		snprint(buf, sizeof(buf), "%d %s", t->pid, t->name);
26237aecfafSDavid du Colombier 		q = string(screen, p, fg, ZP, mediumfont, buf);
26337aecfafSDavid du Colombier 		s = now - t->tstart;
26437aecfafSDavid du Colombier 		if(t->tevents[SRelease])
26537aecfafSDavid du Colombier 			snprint(buf, sizeof(buf), " per %t — avg: %t max: %t",
26637aecfafSDavid du Colombier 				(vlong)(s/t->tevents[SRelease]),
26737aecfafSDavid du Colombier 				(vlong)(t->runtime/t->tevents[SRelease]),
26837aecfafSDavid du Colombier 				t->runmax);
26937aecfafSDavid du Colombier 		else if((s /=1000000000LL) != 0)
27037aecfafSDavid du Colombier 			snprint(buf, sizeof(buf), " per 1s — avg: %t total: %t",
27137aecfafSDavid du Colombier 				t->total/s,
27237aecfafSDavid du Colombier 				t->total);
27337aecfafSDavid du Colombier 		else
27437aecfafSDavid du Colombier 			snprint(buf, sizeof(buf), " total: %t", t->total);
27537aecfafSDavid du Colombier 		string(screen, q, fg, ZP, tinyfont, buf);
27637aecfafSDavid du Colombier 		p.y += Height;
27737aecfafSDavid du Colombier 	}
27837aecfafSDavid du Colombier 	x = time2x(prevts);
27937aecfafSDavid du Colombier 
28037aecfafSDavid du Colombier 	p = screen->r.min;
28137aecfafSDavid du Colombier 	for (n = 0; n != ntasks; n++) {
28237aecfafSDavid du Colombier 		t = &tasks[n];
28337aecfafSDavid du Colombier 
28437aecfafSDavid du Colombier 		/* p is upper left corner for this task */
28537aecfafSDavid du Colombier 
28637aecfafSDavid du Colombier 		/* Move part already drawn */
28737aecfafSDavid du Colombier 		r = Rect(p.x, p.y + topmargin, p.x + x, p.y+Height);
288375daca8SDavid du Colombier 		draw(screen, r, screen, nil, Pt(p.x + Width - x, p.y + topmargin));
28937aecfafSDavid du Colombier 
29037aecfafSDavid du Colombier 		r.max.x = screen->r.max.x;
29137aecfafSDavid du Colombier 		r.min.x += x;
29237aecfafSDavid du Colombier 		draw(screen, r, bg, nil, ZP);
29337aecfafSDavid du Colombier 
294375daca8SDavid du Colombier 		line(screen, addpt(p, Pt(x, Height - lineht)), Pt(screen->r.max.x, p.y + Height - lineht),
295375daca8SDavid du Colombier 			Endsquare, Endsquare, 0, cols[n % Ncolor][1], ZP);
29637aecfafSDavid du Colombier 
29737aecfafSDavid du Colombier 		for (i = 0; i < t->nevents-1; i++)
29837aecfafSDavid du Colombier 			if (prevts < t->events[i + 1].time)
29937aecfafSDavid du Colombier 				break;
30037aecfafSDavid du Colombier 
30137aecfafSDavid du Colombier 		if (i > 0) {
302375daca8SDavid du Colombier 			memmove(t->events, t->events + i, (t->nevents - i) * sizeof(Event));
30337aecfafSDavid du Colombier 			t->nevents -= i;
30437aecfafSDavid du Colombier 		}
30537aecfafSDavid du Colombier 
30637aecfafSDavid du Colombier 		for (i = 0; i != t->nevents; i++) {
30737aecfafSDavid du Colombier 			Event *e = &t->events[i], *_e;
30837aecfafSDavid du Colombier 			int sx, ex;
30937aecfafSDavid du Colombier 
31037aecfafSDavid du Colombier 			switch (e->etype & 0xffff) {
31137aecfafSDavid du Colombier 			case SAdmit:
31237aecfafSDavid du Colombier 				if (e->time > prevts && e->time <= newestts) {
31337aecfafSDavid du Colombier 					sx = time2x(e->time);
31437aecfafSDavid du Colombier 					line(screen, addpt(p, Pt(sx, topmargin)),
31537aecfafSDavid du Colombier 						addpt(p, Pt(sx, Height - bottommargin)),
31637aecfafSDavid du Colombier 						Endarrow, Endsquare, 1, green, ZP);
31737aecfafSDavid du Colombier 				}
31837aecfafSDavid du Colombier 				break;
31937aecfafSDavid du Colombier 			case SExpel:
32037aecfafSDavid du Colombier 				if (e->time > prevts && e->time <= newestts) {
32137aecfafSDavid du Colombier 					sx = time2x(e->time);
32237aecfafSDavid du Colombier 					line(screen, addpt(p, Pt(sx, topmargin)),
32337aecfafSDavid du Colombier 						addpt(p, Pt(sx, Height - bottommargin)),
32437aecfafSDavid du Colombier 						Endsquare, Endarrow, 1, red, ZP);
32537aecfafSDavid du Colombier 				}
32637aecfafSDavid du Colombier 				break;
32737aecfafSDavid du Colombier 			case SRelease:
32837aecfafSDavid du Colombier 				if (e->time > prevts && e->time <= newestts) {
32937aecfafSDavid du Colombier 					sx = time2x(e->time);
33037aecfafSDavid du Colombier 					line(screen, addpt(p, Pt(sx, topmargin)),
33137aecfafSDavid du Colombier 						addpt(p, Pt(sx, Height - bottommargin)),
33237aecfafSDavid du Colombier 						Endarrow, Endsquare, 1, fg, ZP);
33337aecfafSDavid du Colombier 				}
33437aecfafSDavid du Colombier 				break;
33537aecfafSDavid du Colombier 			case SDeadline:
33637aecfafSDavid du Colombier 				if (e->time > prevts && e->time <= newestts) {
33737aecfafSDavid du Colombier 					sx = time2x(e->time);
33837aecfafSDavid du Colombier 					line(screen, addpt(p, Pt(sx, topmargin)),
33937aecfafSDavid du Colombier 						addpt(p, Pt(sx, Height - bottommargin)),
34037aecfafSDavid du Colombier 						Endsquare, Endarrow, 1, fg, ZP);
34137aecfafSDavid du Colombier 				}
34237aecfafSDavid du Colombier 				break;
34337aecfafSDavid du Colombier 
34437aecfafSDavid du Colombier 			case SYield:
34537aecfafSDavid du Colombier 			case SUser:
34637aecfafSDavid du Colombier 				if (e->time > prevts && e->time <= newestts) {
34737aecfafSDavid du Colombier 					sx = time2x(e->time);
34837aecfafSDavid du Colombier 					line(screen, addpt(p, Pt(sx, topmargin)),
34937aecfafSDavid du Colombier 						addpt(p, Pt(sx, Height - bottommargin)),
35037aecfafSDavid du Colombier 						Endsquare, Endarrow, 0,
35137aecfafSDavid du Colombier 						(e->etype == SYield)? green: blue, ZP);
35237aecfafSDavid du Colombier 				}
35337aecfafSDavid du Colombier 				break;
35437aecfafSDavid du Colombier 			case SSlice:
35537aecfafSDavid du Colombier 				if (e->time > prevts && e->time <= newestts) {
35637aecfafSDavid du Colombier 					sx = time2x(e->time);
35737aecfafSDavid du Colombier 					line(screen, addpt(p, Pt(sx, topmargin)),
35837aecfafSDavid du Colombier 						addpt(p, Pt(sx, Height - bottommargin)),
35937aecfafSDavid du Colombier 						Endsquare, Endarrow, 0, red, ZP);
36037aecfafSDavid du Colombier 				}
36137aecfafSDavid du Colombier 				break;
36237aecfafSDavid du Colombier 
36337aecfafSDavid du Colombier 			case SRun:
36437aecfafSDavid du Colombier 			case SEdf:
36537aecfafSDavid du Colombier 				sx = time2x(e->time);
36637aecfafSDavid du Colombier 				ex = time2x(e->etime);
36715174232SDavid du Colombier 				if(ex == sx)
36815174232SDavid du Colombier 					ex++;
36937aecfafSDavid du Colombier 
37037aecfafSDavid du Colombier 				r = Rect(sx, topmargin + 8, ex, Height - lineht);
37137aecfafSDavid du Colombier 				r = rectaddpt(r, p);
37237aecfafSDavid du Colombier 
37337aecfafSDavid du Colombier 				draw(screen, r, cols[n % Ncolor][e->etype==SRun?1:3], nil, ZP);
37437aecfafSDavid du Colombier 
37515174232SDavid du Colombier 				if(t->pid == triggerproc && ex < Width)
37615174232SDavid du Colombier 					paused ^= 1;
37715174232SDavid du Colombier 
37837aecfafSDavid du Colombier 				for(j = 0; j < t->nevents; j++){
37937aecfafSDavid du Colombier 					_e = &t->events[j];
38037aecfafSDavid du Colombier 					switch(_e->etype & 0xffff){
38137aecfafSDavid du Colombier 					case SInts:
38237aecfafSDavid du Colombier 						if (_e->time > prevts && _e->time <= newestts){
38337aecfafSDavid du Colombier 							sx = time2x(_e->time);
38437aecfafSDavid du Colombier 							line(screen, addpt(p, Pt(sx, topmargin)),
38537aecfafSDavid du Colombier 												addpt(p, Pt(sx, Height / 2 - bottommargin)),
38637aecfafSDavid du Colombier 												Endsquare, Endsquare, 0,
38737aecfafSDavid du Colombier 												green, ZP);
38837aecfafSDavid du Colombier 						}
38937aecfafSDavid du Colombier 						break;
39037aecfafSDavid du Colombier 					case SInte:
39137aecfafSDavid du Colombier 						if (_e->time > prevts && _e->time <= newestts) {
39237aecfafSDavid du Colombier 							sx = time2x(_e->time);
39337aecfafSDavid du Colombier 							line(screen, addpt(p, Pt(sx, Height / 2 - bottommargin)),
39437aecfafSDavid du Colombier 												addpt(p, Pt(sx, Height - bottommargin)),
39537aecfafSDavid du Colombier 												Endsquare, Endsquare, 0,
39637aecfafSDavid du Colombier 												blue, ZP);
39737aecfafSDavid du Colombier 						}
39837aecfafSDavid du Colombier 						break;
39937aecfafSDavid du Colombier 					}
40037aecfafSDavid du Colombier 				}
40137aecfafSDavid du Colombier 				break;
40237aecfafSDavid du Colombier 			}
40337aecfafSDavid du Colombier 		}
40437aecfafSDavid du Colombier 		p.y += Height;
40537aecfafSDavid du Colombier 	}
40637aecfafSDavid du Colombier 
40737aecfafSDavid du Colombier 	ts = prevts + scales[scaleno].littletics - (prevts % scales[scaleno].littletics);
40837aecfafSDavid du Colombier 	x = time2x(ts);
40937aecfafSDavid du Colombier 
41037aecfafSDavid du Colombier 	while(x < Width){
41137aecfafSDavid du Colombier 		p = screen->r.min;
41237aecfafSDavid du Colombier 		for(n = 0; n < ntasks; n++){
41337aecfafSDavid du Colombier 			int height, width;
41437aecfafSDavid du Colombier 
41537aecfafSDavid du Colombier 			/* p is upper left corner for this task */
41637aecfafSDavid du Colombier 			if ((ts % scales[scaleno].scale) == 0){
41737aecfafSDavid du Colombier 				height = 10 * Height;
41837aecfafSDavid du Colombier 				width = 1;
41937aecfafSDavid du Colombier 			}else if ((ts % scales[scaleno].bigtics) == 0){
42037aecfafSDavid du Colombier 				height = 12 * Height;
42137aecfafSDavid du Colombier 				width = 0;
42237aecfafSDavid du Colombier 			}else{
42337aecfafSDavid du Colombier 				height = 13 * Height;
42437aecfafSDavid du Colombier 				width = 0;
42537aecfafSDavid du Colombier 			}
42637aecfafSDavid du Colombier 			height >>= 4;
42737aecfafSDavid du Colombier 
42837aecfafSDavid du Colombier 			line(screen, addpt(p, Pt(x, height)), addpt(p, Pt(x, Height - lineht)),
42937aecfafSDavid du Colombier 				Endsquare, Endsquare, width, cols[n % Ncolor][2], ZP);
43037aecfafSDavid du Colombier 
43137aecfafSDavid du Colombier 			p.y += Height;
43237aecfafSDavid du Colombier 		}
43337aecfafSDavid du Colombier 		ts += scales[scaleno].littletics;
43437aecfafSDavid du Colombier 		x = time2x(ts);
43537aecfafSDavid du Colombier 	}
43637aecfafSDavid du Colombier 
43737aecfafSDavid du Colombier 	rtime = screen->r;
43837aecfafSDavid du Colombier 	rtime.min.y = rtime.max.y - tinyfont->height + 2;
43937aecfafSDavid du Colombier 	draw(screen, rtime, bg, nil, ZP);
44037aecfafSDavid du Colombier 	ts = oldestts + scales[scaleno].bigtics - (oldestts % scales[scaleno].bigtics);
44137aecfafSDavid du Colombier 	x = time2x(ts);
442375daca8SDavid du Colombier 	ss = 0;
44337aecfafSDavid du Colombier 	while(x < Width){
444375daca8SDavid du Colombier 		snprint(buf, sizeof(buf), "%t", ss);
44537aecfafSDavid du Colombier 		string(screen, addpt(p, Pt(x - stringwidth(tinyfont, buf)/2, - tinyfont->height - 1)),
44637aecfafSDavid du Colombier 			fg, ZP, tinyfont, buf);
44737aecfafSDavid du Colombier 		ts += scales[scaleno].bigtics;
448375daca8SDavid du Colombier 		ss += scales[scaleno].bigtics;
44937aecfafSDavid du Colombier 		x = time2x(ts);
45037aecfafSDavid du Colombier 	}
45137aecfafSDavid du Colombier 
45237aecfafSDavid du Colombier 	snprint(buf, sizeof(buf), "%t", now);
45337aecfafSDavid du Colombier 	string(screen, Pt(screen->r.max.x - stringwidth(mediumfont, buf), screen->r.min.y),
45437aecfafSDavid du Colombier 		fg, ZP, mediumfont, buf);
45537aecfafSDavid du Colombier 
45637aecfafSDavid du Colombier 	flushimage(display, 1);
45737aecfafSDavid du Colombier 	prevts = newestts;
45837aecfafSDavid du Colombier }
45937aecfafSDavid du Colombier 
46037aecfafSDavid du Colombier Task*
newtask(ulong pid)46137aecfafSDavid du Colombier newtask(ulong pid)
46237aecfafSDavid du Colombier {
46337aecfafSDavid du Colombier 	Task *t;
46437aecfafSDavid du Colombier 	char buf[64], *p;
46537aecfafSDavid du Colombier 	int fd,n;
46637aecfafSDavid du Colombier 
46737aecfafSDavid du Colombier 	tasks = realloc(tasks, (ntasks + 1) * sizeof(Task));
46837aecfafSDavid du Colombier 	assert(tasks);
46937aecfafSDavid du Colombier 
47037aecfafSDavid du Colombier 	t = &tasks[ntasks++];
47137aecfafSDavid du Colombier 	memset(t, 0, sizeof(Task));
47237aecfafSDavid du Colombier 	t->events = nil;
47337aecfafSDavid du Colombier 	snprint(buf, sizeof buf, "/proc/%ld/status", pid);
47437aecfafSDavid du Colombier 	t->name = nil;
47537aecfafSDavid du Colombier 	fd = open(buf, OREAD);
47637aecfafSDavid du Colombier 	if (fd >= 0){
47737aecfafSDavid du Colombier 		n = read(fd, buf, sizeof buf);
47837aecfafSDavid du Colombier 		if(n > 0){
47937aecfafSDavid du Colombier 			p = buf + sizeof buf - 1;
48037aecfafSDavid du Colombier 			*p = 0;
48137aecfafSDavid du Colombier 			p = strchr(buf, ' ');
48237aecfafSDavid du Colombier 			if (p) *p = 0;
48337aecfafSDavid du Colombier 			t->name = strdup(buf);
48437aecfafSDavid du Colombier 		}else
48537aecfafSDavid du Colombier 			print("%s: %r\n", buf);
48637aecfafSDavid du Colombier 		close(fd);
48737aecfafSDavid du Colombier 	}else
48837aecfafSDavid du Colombier 		print("%s: %r\n", buf);
48937aecfafSDavid du Colombier 	t->pid = pid;
49037aecfafSDavid du Colombier 	prevts = 0;
49137aecfafSDavid du Colombier 	if (newwin){
49237aecfafSDavid du Colombier 		fprint(wctlfd, "resize -dx %d -dy %d\n",
49337aecfafSDavid du Colombier 			Width + 20, (ntasks * Height) + 5);
49437aecfafSDavid du Colombier 	}else
49537aecfafSDavid du Colombier 		Height = ntasks ? Dy(screen->r)/ntasks : Dy(screen->r);
49637aecfafSDavid du Colombier 	return t;
49737aecfafSDavid du Colombier }
49837aecfafSDavid du Colombier 
49937aecfafSDavid du Colombier void
doevent(Task * t,Traceevent * ep)50037aecfafSDavid du Colombier doevent(Task *t, Traceevent *ep)
50137aecfafSDavid du Colombier {
50237aecfafSDavid du Colombier 	int i, n;
50337aecfafSDavid du Colombier 	Event *event;
50437aecfafSDavid du Colombier 	vlong runt;
50537aecfafSDavid du Colombier 
50637aecfafSDavid du Colombier 	t->tevents[ep->etype & 0xffff]++;
50737aecfafSDavid du Colombier 	n = t->nevents++;
50837aecfafSDavid du Colombier 	t->events = realloc(t->events, t->nevents*sizeof(Event));
50937aecfafSDavid du Colombier 	assert(t->events);
51037aecfafSDavid du Colombier 	event = &t->events[n];
51137aecfafSDavid du Colombier 	memmove(event, ep, sizeof(Traceevent));
51237aecfafSDavid du Colombier 	event->etime = 0;
51337aecfafSDavid du Colombier 
51437aecfafSDavid du Colombier 	switch(event->etype & 0xffff){
51537aecfafSDavid du Colombier 	case SRelease:
51637aecfafSDavid du Colombier 		if (t->runthis > t->runmax)
51737aecfafSDavid du Colombier 			t->runmax = t->runthis;
51837aecfafSDavid du Colombier 		t->runthis = 0;
51937aecfafSDavid du Colombier 		break;
52037aecfafSDavid du Colombier 
52137aecfafSDavid du Colombier 	case SSleep:
52237aecfafSDavid du Colombier 	case SYield:
52337aecfafSDavid du Colombier 	case SReady:
52437aecfafSDavid du Colombier 	case SSlice:
52537aecfafSDavid du Colombier 		for(i = n-1; i >= 0; i--)
52637aecfafSDavid du Colombier 			if (t->events[i].etype == SRun ||
52737aecfafSDavid du Colombier 				t->events[i].etype == SEdf)
52837aecfafSDavid du Colombier 				break;
52937aecfafSDavid du Colombier 		if(i < 0 || t->events[i].etime != 0)
53037aecfafSDavid du Colombier 			break;
53137aecfafSDavid du Colombier 		runt = event->time - t->events[i].time;
53237aecfafSDavid du Colombier 		if(runt > 0){
53337aecfafSDavid du Colombier 			t->events[i].etime = event->time;
53437aecfafSDavid du Colombier 			t->runtime += runt;
53537aecfafSDavid du Colombier 			t->total += runt;
53637aecfafSDavid du Colombier 			t->runthis += runt;
53737aecfafSDavid du Colombier 			t->runs++;
53837aecfafSDavid du Colombier 		}
53937aecfafSDavid du Colombier 		break;
54037aecfafSDavid du Colombier 	case SDead:
54137aecfafSDavid du Colombier print("task died %ld %t %s\n", event->pid, event->time, schedstatename[event->etype & 0xffff]);
54237aecfafSDavid du Colombier 		free(t->events);
54337aecfafSDavid du Colombier 		free(t->name);
54437aecfafSDavid du Colombier 		ntasks--;
54537aecfafSDavid du Colombier 		memmove(t, t+1, sizeof(Task)*(&tasks[ntasks]-t));
54637aecfafSDavid du Colombier 		if (newwin)
54737aecfafSDavid du Colombier 			fprint(wctlfd, "resize -dx %d -dy %d\n",
54837aecfafSDavid du Colombier 				Width + 20, (ntasks * Height) + 5);
54937aecfafSDavid du Colombier 		else
55037aecfafSDavid du Colombier 			Height = ntasks ? Dy(screen->r)/ntasks : Dy(screen->r);
55137aecfafSDavid du Colombier 		prevts = 0;
55237aecfafSDavid du Colombier 	}
55337aecfafSDavid du Colombier }
55437aecfafSDavid du Colombier 
55537aecfafSDavid du Colombier void
drawtrace(void)55637aecfafSDavid du Colombier drawtrace(void)
55737aecfafSDavid du Colombier {
55837aecfafSDavid du Colombier 	char *wsys, line[256];
55937aecfafSDavid du Colombier 	int wfd, logfd;
56037aecfafSDavid du Colombier 	Mousectl *mousectl;
56137aecfafSDavid du Colombier 	Keyboardctl *keyboardctl;
56237aecfafSDavid du Colombier 	int scaleno;
56337aecfafSDavid du Colombier 	Rune r;
56437aecfafSDavid du Colombier 	int i, n;
56537aecfafSDavid du Colombier 	Task *t;
56637aecfafSDavid du Colombier 	Traceevent *ep;
56737aecfafSDavid du Colombier 
56837aecfafSDavid du Colombier 	eventbuf = malloc(Nevents*sizeof(Traceevent));
56937aecfafSDavid du Colombier 	assert(eventbuf);
57037aecfafSDavid du Colombier 
57137aecfafSDavid du Colombier 	if((logfd = open(profdev, OREAD)) < 0)
572*14cc0f53SDavid du Colombier 		sysfatal("%s: Cannot open %s: %r", argv0, profdev);
57337aecfafSDavid du Colombier 
57437aecfafSDavid du Colombier 	if(newwin){
57537aecfafSDavid du Colombier 		if((wsys = getenv("wsys")) == nil)
576*14cc0f53SDavid du Colombier 			sysfatal("%s: Cannot find windowing system: %r",
57737aecfafSDavid du Colombier 						argv0);
57837aecfafSDavid du Colombier 
57937aecfafSDavid du Colombier 		if((wfd = open(wsys, ORDWR)) < 0)
580*14cc0f53SDavid du Colombier 			sysfatal("%s: Cannot open windowing system: %r",
58137aecfafSDavid du Colombier 						argv0);
58237aecfafSDavid du Colombier 
58337aecfafSDavid du Colombier 		snprint(line, sizeof(line), "new -pid %d -dx %d -dy %d",
58437aecfafSDavid du Colombier 				getpid(), Width + 20, Height + 5);
58537aecfafSDavid du Colombier 		line[sizeof(line) - 1] = '\0';
58637aecfafSDavid du Colombier 		rfork(RFNAMEG);
58737aecfafSDavid du Colombier 
58837aecfafSDavid du Colombier 		if(mount(wfd, -1, "/mnt/wsys", MREPL, line) < 0)
589*14cc0f53SDavid du Colombier 			sysfatal("%s: Cannot mount %s under /mnt/wsys: %r",
59037aecfafSDavid du Colombier 						argv0, line);
59137aecfafSDavid du Colombier 
59237aecfafSDavid du Colombier 		if(bind("/mnt/wsys", "/dev", MBEFORE) < 0)
593*14cc0f53SDavid du Colombier 			sysfatal("%s: Cannot bind /mnt/wsys in /dev: %r",
59437aecfafSDavid du Colombier 						argv0);
59537aecfafSDavid du Colombier 
59637aecfafSDavid du Colombier 	}
59737aecfafSDavid du Colombier 	if((wctlfd = open("/dev/wctl", OWRITE)) < 0)
598*14cc0f53SDavid du Colombier 		sysfatal("%s: Cannot open /dev/wctl: %r", argv0);
59937aecfafSDavid du Colombier 	if(initdraw(nil, nil, "trace") < 0)
600*14cc0f53SDavid du Colombier 		sysfatal("%s: initdraw failure: %r", argv0);
60137aecfafSDavid du Colombier 
60237aecfafSDavid du Colombier 	Width = Dx(screen->r);
60337aecfafSDavid du Colombier 	Height = Dy(screen->r);
60437aecfafSDavid du Colombier 
60537aecfafSDavid du Colombier 	if((mousectl = initmouse(nil, screen)) == nil)
606*14cc0f53SDavid du Colombier 		sysfatal("%s: cannot initialize mouse: %r", argv0);
60737aecfafSDavid du Colombier 
60837aecfafSDavid du Colombier 	if((keyboardctl = initkeyboard(nil)) == nil)
609*14cc0f53SDavid du Colombier 		sysfatal("%s: cannot initialize keyboard: %r", argv0);
61037aecfafSDavid du Colombier 
61137aecfafSDavid du Colombier 	colinit();
61237aecfafSDavid du Colombier 
61337aecfafSDavid du Colombier 	paused = 0;
61437aecfafSDavid du Colombier 	scaleno = 7;	/* 100 milliseconds */
61537aecfafSDavid du Colombier 	now = nsec();
616ec46fab0SDavid du Colombier 	for(;;) {
61737aecfafSDavid du Colombier 		Alt a[] = {
61837aecfafSDavid du Colombier 			{ mousectl->c,			nil,		CHANRCV		},
61937aecfafSDavid du Colombier 			{ mousectl->resizec,	nil,		CHANRCV		},
62037aecfafSDavid du Colombier 			{ keyboardctl->c,		&r,			CHANRCV		},
62137aecfafSDavid du Colombier 			{ nil,					nil,		CHANNOBLK	},
62237aecfafSDavid du Colombier 		};
62337aecfafSDavid du Colombier 
62437aecfafSDavid du Colombier 		switch (alt(a)) {
62537aecfafSDavid du Colombier 		case 0:
62637aecfafSDavid du Colombier 			continue;
62737aecfafSDavid du Colombier 
62837aecfafSDavid du Colombier 		case 1:
62937aecfafSDavid du Colombier 			if(getwindow(display, Refnone) < 0)
630*14cc0f53SDavid du Colombier 				sysfatal("drawrt: Cannot re-attach window");
63137aecfafSDavid du Colombier 			if(newwin){
63237aecfafSDavid du Colombier 				if(Dx(screen->r) != Width ||
63337aecfafSDavid du Colombier 					Dy(screen->r) != (ntasks * Height)){
63437aecfafSDavid du Colombier 					fprint(2, "resize: x: have %d, need %d; y: have %d, need %d\n",
63537aecfafSDavid du Colombier 							Dx(screen->r), Width + 8, Dy(screen->r), (ntasks * Height) + 8);
63637aecfafSDavid du Colombier 					fprint(wctlfd, "resize -dx %d -dy %d\n",
63737aecfafSDavid du Colombier 							Width + 8, (ntasks * Height) + 8);
63837aecfafSDavid du Colombier 				}
63937aecfafSDavid du Colombier 			}
64037aecfafSDavid du Colombier 			else{
64137aecfafSDavid du Colombier 				Width = Dx(screen->r);
64237aecfafSDavid du Colombier 				Height = ntasks? Dy(screen->r)/ntasks:
64337aecfafSDavid du Colombier 							Dy(screen->r);
64437aecfafSDavid du Colombier 			}
64537aecfafSDavid du Colombier 			break;
64637aecfafSDavid du Colombier 
64737aecfafSDavid du Colombier 		case 2:
64837aecfafSDavid du Colombier 
64937aecfafSDavid du Colombier 			switch(r){
65037aecfafSDavid du Colombier 			case 'r':
65137aecfafSDavid du Colombier 				for(i = 0; i < ntasks; i++){
65237aecfafSDavid du Colombier 					tasks[i].tstart = now;
65337aecfafSDavid du Colombier 					tasks[i].total = 0;
65437aecfafSDavid du Colombier 					tasks[i].runtime = 0;
65537aecfafSDavid du Colombier 					tasks[i].runmax = 0;
65637aecfafSDavid du Colombier 					tasks[i].runthis = 0;
65737aecfafSDavid du Colombier 					tasks[i].runs = 0;
65837aecfafSDavid du Colombier 					memset(tasks[i].tevents, 0, Nevent*sizeof(ulong));
65937aecfafSDavid du Colombier 
66037aecfafSDavid du Colombier 				}
66137aecfafSDavid du Colombier 				break;
66237aecfafSDavid du Colombier 
66337aecfafSDavid du Colombier 			case 'p':
66415174232SDavid du Colombier 				paused ^= 1;
66537aecfafSDavid du Colombier 				prevts = 0;
66637aecfafSDavid du Colombier 				break;
66737aecfafSDavid du Colombier 
66837aecfafSDavid du Colombier 			case '-':
66937aecfafSDavid du Colombier 				if (scaleno < nelem(scales) - 1)
67037aecfafSDavid du Colombier 					scaleno++;
67137aecfafSDavid du Colombier 				prevts = 0;
67237aecfafSDavid du Colombier 				break;
67337aecfafSDavid du Colombier 
67437aecfafSDavid du Colombier 			case '+':
67537aecfafSDavid du Colombier 				if (scaleno > 0)
67637aecfafSDavid du Colombier 					scaleno--;
67737aecfafSDavid du Colombier 				prevts = 0;
67837aecfafSDavid du Colombier 				break;
67937aecfafSDavid du Colombier 
68037aecfafSDavid du Colombier 			case 'q':
68137aecfafSDavid du Colombier 				threadexitsall(nil);
68237aecfafSDavid du Colombier 
68337aecfafSDavid du Colombier 			case 'v':
68437aecfafSDavid du Colombier 				verbose ^= 1;
68537aecfafSDavid du Colombier 
68637aecfafSDavid du Colombier 			default:
68737aecfafSDavid du Colombier 				break;
68837aecfafSDavid du Colombier 			}
68937aecfafSDavid du Colombier 			break;
69037aecfafSDavid du Colombier 
69137aecfafSDavid du Colombier 		case 3:
69237aecfafSDavid du Colombier 			now = nsec();
69337aecfafSDavid du Colombier 			while((n = read(logfd, eventbuf, Nevents*sizeof(Traceevent))) > 0){
69437aecfafSDavid du Colombier 				assert((n % sizeof(Traceevent)) == 0);
69537aecfafSDavid du Colombier 				nevents = n / sizeof(Traceevent);
69637aecfafSDavid du Colombier 				for (ep = eventbuf; ep < eventbuf + nevents; ep++){
69737aecfafSDavid du Colombier 					if ((ep->etype & 0xffff) >= Nevent){
69837aecfafSDavid du Colombier 						print("%ld %t Illegal event %ld\n",
69937aecfafSDavid du Colombier 							ep->pid, ep->time, ep->etype & 0xffff);
70037aecfafSDavid du Colombier 						continue;
70137aecfafSDavid du Colombier 					}
70237aecfafSDavid du Colombier 					if (verbose)
70337aecfafSDavid du Colombier 						print("%ld %t %s\n",
70437aecfafSDavid du Colombier 							ep->pid, ep->time, schedstatename[ep->etype & 0xffff]);
70537aecfafSDavid du Colombier 
70637aecfafSDavid du Colombier 					for(i = 0; i < ntasks; i++)
70737aecfafSDavid du Colombier 						if(tasks[i].pid == ep->pid)
70837aecfafSDavid du Colombier 							break;
70937aecfafSDavid du Colombier 
71037aecfafSDavid du Colombier 					if(i == ntasks){
71137aecfafSDavid du Colombier 						t = newtask(ep->pid);
71237aecfafSDavid du Colombier 						t->tstart = ep->time;
71337aecfafSDavid du Colombier 					}else
71437aecfafSDavid du Colombier 						t = &tasks[i];
71537aecfafSDavid du Colombier 
71637aecfafSDavid du Colombier 					doevent(t, ep);
71737aecfafSDavid du Colombier 				}
71837aecfafSDavid du Colombier 			}
71937aecfafSDavid du Colombier 			if(!paused)
72037aecfafSDavid du Colombier 				redraw(scaleno);
72137aecfafSDavid du Colombier 		}
72237aecfafSDavid du Colombier 		sleep(scales[scaleno].sleep);
72337aecfafSDavid du Colombier 	}
72437aecfafSDavid du Colombier }
72537aecfafSDavid du Colombier 
72637aecfafSDavid du Colombier int
timeconv(Fmt * f)72737aecfafSDavid du Colombier timeconv(Fmt *f)
72837aecfafSDavid du Colombier {
72937aecfafSDavid du Colombier 	char buf[128], *sign;
73037aecfafSDavid du Colombier 	vlong t;
73137aecfafSDavid du Colombier 
73237aecfafSDavid du Colombier 	buf[0] = 0;
73337aecfafSDavid du Colombier 	switch(f->r) {
73437aecfafSDavid du Colombier 	case 'U':
73537aecfafSDavid du Colombier 		t = va_arg(f->args, vlong);
73637aecfafSDavid du Colombier 		break;
73737aecfafSDavid du Colombier 	case 't':		// vlong in nanoseconds
73837aecfafSDavid du Colombier 		t = va_arg(f->args, vlong);
73937aecfafSDavid du Colombier 		break;
74037aecfafSDavid du Colombier 	default:
74137aecfafSDavid du Colombier 		return fmtstrcpy(f, "(timeconv)");
74237aecfafSDavid du Colombier 	}
74337aecfafSDavid du Colombier 	if (t < 0) {
74437aecfafSDavid du Colombier 		sign = "-";
74537aecfafSDavid du Colombier 		t = -t;
74637aecfafSDavid du Colombier 	}else
74737aecfafSDavid du Colombier 		sign = "";
74837aecfafSDavid du Colombier 	if (t > S(1)){
74937aecfafSDavid du Colombier 		t += OneRound;
75037aecfafSDavid du Colombier 		sprint(buf, "%s%d.%.3ds", sign, (int)(t / S(1)), (int)(t % S(1))/1000000);
75137aecfafSDavid du Colombier 	}else if (t > MS(1)){
75237aecfafSDavid du Colombier 		t += MilliRound;
75337aecfafSDavid du Colombier 		sprint(buf, "%s%d.%.3dms", sign, (int)(t / MS(1)), (int)(t % MS(1))/1000);
75437aecfafSDavid du Colombier 	}else if (t > US(1))
75537aecfafSDavid du Colombier 		sprint(buf, "%s%d.%.3dµs", sign, (int)(t / US(1)), (int)(t % US(1)));
75637aecfafSDavid du Colombier 	else
75737aecfafSDavid du Colombier 		sprint(buf, "%s%dns", sign, (int)t);
75837aecfafSDavid du Colombier 	return fmtstrcpy(f, buf);
75937aecfafSDavid du Colombier }
760