759 lines · 17.5 KB · C
RawDownload
#include <u.h>#include <tos.h>#include <libc.h>#include <thread.h>#include <ip.h>#include <bio.h>#include <draw.h>#include <mouse.h>#include <cursor.h>#include <keyboard.h>#include "trace.h" #pragma	varargck	type	"t"		vlong#pragma	varargck	type	"U"		uvlong #define NS(x)	((vlong)x)#define US(x)	(NS(x) * 1000ULL)#define MS(x)	(US(x) * 1000ULL)#define S(x)	(MS(x) * 1000ULL) #define numblocks(a, b)	(((a) + (b) - 1) / (b))#define roundup(a, b)	(numblocks((a), (b)) * (b)) enum {	OneRound = MS(1)/2LL,	MilliRound = US(1)/2LL,}; typedef struct Event	Event;typedef struct Task	Task;struct Event {	Traceevent;	vlong	etime;	/* length of block to draw */}; struct Task {	int	pid;	char	*name;	int	nevents;		Event	*events;	vlong	tstart;	vlong	total;	vlong	runtime;	vlong	runmax;	vlong	runthis;	long	runs;	ulong	tevents[Nevent];}; enum {	Nevents = 1024,	Ncolor = 6,	K = 1024,}; vlong	now, prevts; int	newwin;int	Width = 1000;		int	Height = 100;		// Per taskint	topmargin = 8;int	bottommargin = 4;int	lineht = 12;int	wctlfd;int	nevents;Traceevent *eventbuf;Event	*event; void drawtrace(void);int schedparse(char*, char*, char*);int timeconv(Fmt*); char *schedstatename[] = {	[SAdmit] =	"Admit",	[SSleep] =	"Sleep",	[SDead] =	"Dead",	[SDeadline] =	"Deadline",	[SEdf] =	"Edf",	[SExpel] =	"Expel",	[SReady] =	"Ready",	[SRelease] =	"Release",	[SRun] =	"Run",	[SSlice] =	"Slice",	[SInts] =	"Ints",	[SInte] =	"Inte",	[SUser] = 	"User",	[SYield] =	"Yield",}; struct {	vlong	scale;	vlong	bigtics;	vlong	littletics;	int	sleep;} scales[] = {	{	US(500),	US(100),	US(50),		  0},	{	US(1000),	US(500),	US(100),	  0},	{	US(2000),	US(1000),	US(200),	  0},	{	US(5000),	US(1000),	US(500),	  0},	{	MS(10),		MS(5),		MS(1),		 20},	{	MS(20),		MS(10),		MS(2),		 20},	{	MS(50),		MS(10),		MS(5),		 20},	{	MS(100),	MS(50),		MS(10),		 20},	/* starting scaleno */	{	MS(200),	MS(100),	MS(20),		 20},	{	MS(500),	MS(100),	MS(50),		 50},	{	MS(1000),	MS(500),	MS(100),	100},	{	MS(2000),	MS(1000),	MS(200),	100},	{	MS(5000),	MS(1000),	MS(500),	100},	{	S(10),		S(50),		S(1),		100},	{	S(20),		S(10),		S(2),		100},	{	S(50),		S(10),		S(5),		100},	{	S(100),		S(50),		S(10),		100},	{	S(200),		S(100),		S(20),		100},	{	S(500),		S(100),		S(50),		100},	{	S(1000),	S(500),		S(100),		100},}; int ntasks, verbose, triggerproc, paused;Task *tasks;Image *cols[Ncolor][4];Font *mediumfont, *tinyfont;Image *grey, *red, *green, *blue, *bg, *fg;char*profdev = "/proc/trace"; static voidusage(void){	fprint(2, "Usage: %s [-d profdev] [-w] [-v] [-t triggerproc] [processes]\n", argv0);	exits(nil);} voidthreadmain(int argc, char **argv){	int fd, i;	char fname[80]; 	fmtinstall('t', timeconv);	ARGBEGIN {	case 'd':		profdev = EARGF(usage());		break;	case 'v':		verbose = 1;		break;	case 'w':		newwin++;		break;	case 't':		triggerproc = (int)strtol(EARGF(usage()), nil, 0);		break;	default:		usage();	}	ARGEND; 	fname[sizeof fname - 1] = 0;	for(i = 0; i < argc; i++){		snprint(fname, sizeof fname - 2, "/proc/%s/ctl", 					argv[i]);		if((fd = open(fname, OWRITE)) < 0){			fprint(2, "%s: cannot open %s: %r\n",						argv[0], fname);			continue;		} 		if(fprint(fd, "trace 1") < 0)			fprint(2, "%s: cannot enable tracing on %s: %r\n",						argv[0], fname);		close(fd);	} 	drawtrace();} static 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), screen->chan, 1, c1);	cols[i][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c2);	cols[i][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c0);} static voidcolinit(void){	mediumfont = openfont(display, "/lib/font/bit/lucidasans/unicode.10.font");	if(mediumfont == nil)		mediumfont = font;	tinyfont = openfont(display, "/lib/font/bit/lucidasans/unicode.7.font");	if(tinyfont == nil)		tinyfont = font;	topmargin = mediumfont->height+2;	bottommargin = tinyfont->height+2; 	/* 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), screen->chan, 1, 0xEEEEEEFF);	cols[5][1] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF);	cols[5][2] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x888888FF);	cols[5][3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAAAAAAFF);	grey = cols[5][2];	red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFF0000FF);	green = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x00FF00FF);	blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x0000FFFF);	bg = display->white;	fg = display->black;} static voidredraw(int scaleno){	int n, i, j, x;	char buf[256];	Point p, q;	Rectangle r, rtime;	Task *t;	vlong ts, oldestts, newestts, period, ppp, scale, s, ss; #	define time2x(t)	((int)(((t) - oldestts) / ppp)) 	scale = scales[scaleno].scale;	period = scale + scales[scaleno].littletics;	ppp = period / Width;	// period per pixel. 	/* Round `now' to a nice number */	newestts = now - (now % scales[scaleno].bigtics) + 			(scales[scaleno].littletics>>1); 	oldestts = newestts - period; //print("newestts %t, period %t, %d-%d\n", newestts, period, time2x(oldestts), time2x(newestts));	if (prevts < oldestts){		oldestts = newestts - period; 		prevts = oldestts;		draw(screen, screen->r, bg, nil, ZP);	}else{		/* just white out time */		rtime = screen->r;		rtime.min.x = rtime.max.x - stringwidth(mediumfont, "00000000000.000s");		rtime.max.y = rtime.min.y + mediumfont->height;		draw(screen, rtime, bg, nil, ZP);	}	p = screen->r.min;	for (n = 0; n != ntasks; n++) {		t = &tasks[n];		/* p is upper left corner for this task */		rtime = Rpt(p, addpt(p, Pt(500, mediumfont->height)));		draw(screen, rtime, bg, nil, ZP);		snprint(buf, sizeof(buf), "%d %s", t->pid, t->name);		q = string(screen, p, fg, ZP, mediumfont, buf);		s = now - t->tstart;		if(t->tevents[SRelease])			snprint(buf, sizeof(buf), " per %t — avg: %t max: %t",				(vlong)(s/t->tevents[SRelease]),				(vlong)(t->runtime/t->tevents[SRelease]),				t->runmax);		else if((s /=1000000000LL) != 0)			snprint(buf, sizeof(buf), " per 1s — avg: %t total: %t",				t->total/s,				t->total);		else			snprint(buf, sizeof(buf), " total: %t", t->total);		string(screen, q, fg, ZP, tinyfont, buf);		p.y += Height;	}	x = time2x(prevts); 	p = screen->r.min;	for (n = 0; n != ntasks; n++) {		t = &tasks[n]; 		/* p is upper left corner for this task */ 		/* Move part already drawn */		r = Rect(p.x, p.y + topmargin, p.x + x, p.y+Height);		draw(screen, r, screen, nil, Pt(p.x + Width - x, p.y + topmargin)); 		r.max.x = screen->r.max.x;		r.min.x += x;		draw(screen, r, bg, nil, ZP); 		line(screen, addpt(p, Pt(x, Height - lineht)), Pt(screen->r.max.x, p.y + Height - lineht),			Endsquare, Endsquare, 0, cols[n % Ncolor][1], ZP); 		for (i = 0; i < t->nevents-1; i++)			if (prevts < t->events[i + 1].time)				break;					if (i > 0) {			memmove(t->events, t->events + i, (t->nevents - i) * sizeof(Event));			t->nevents -= i;		} 		for (i = 0; i != t->nevents; i++) {			Event *e = &t->events[i], *_e;			int sx, ex; 			switch (e->etype & 0xffff) {			case SAdmit:				if (e->time > prevts && e->time <= newestts) {					sx = time2x(e->time);					line(screen, addpt(p, Pt(sx, topmargin)), 						addpt(p, Pt(sx, Height - bottommargin)), 						Endarrow, Endsquare, 1, green, ZP);				}				break;			case SExpel:				if (e->time > prevts && e->time <= newestts) {					sx = time2x(e->time);					line(screen, addpt(p, Pt(sx, topmargin)), 						addpt(p, Pt(sx, Height - bottommargin)), 						Endsquare, Endarrow, 1, red, ZP);				}				break;			case SRelease:				if (e->time > prevts && e->time <= newestts) {					sx = time2x(e->time);					line(screen, addpt(p, Pt(sx, topmargin)), 						addpt(p, Pt(sx, Height - bottommargin)), 						Endarrow, Endsquare, 1, fg, ZP);				}				break;			case SDeadline:				if (e->time > prevts && e->time <= newestts) {					sx = time2x(e->time);					line(screen, addpt(p, Pt(sx, topmargin)), 						addpt(p, Pt(sx, Height - bottommargin)), 						Endsquare, Endarrow, 1, fg, ZP);				}				break; 			case SYield:			case SUser:				if (e->time > prevts && e->time <= newestts) {					sx = time2x(e->time);					line(screen, addpt(p, Pt(sx, topmargin)), 						addpt(p, Pt(sx, Height - bottommargin)), 						Endsquare, Endarrow, 0, 						(e->etype == SYield)? green: blue, ZP);				}				break;			case SSlice:				if (e->time > prevts && e->time <= newestts) {					sx = time2x(e->time);					line(screen, addpt(p, Pt(sx, topmargin)), 						addpt(p, Pt(sx, Height - bottommargin)), 						Endsquare, Endarrow, 0, red, ZP);				}				break; 			case SRun:			case SEdf:				sx = time2x(e->time);				ex = time2x(e->etime);				if(ex == sx)					ex++; 				r = Rect(sx, topmargin + 8, ex, Height - lineht);				r = rectaddpt(r, p); 				draw(screen, r, cols[n % Ncolor][e->etype==SRun?1:3], nil, ZP); 				if(t->pid == triggerproc && ex < Width)					paused ^= 1; 				for(j = 0; j < t->nevents; j++){					_e = &t->events[j];					switch(_e->etype & 0xffff){					case SInts:						if (_e->time > prevts && _e->time <= newestts){							sx = time2x(_e->time);							line(screen, addpt(p, Pt(sx, topmargin)), 												addpt(p, Pt(sx, Height / 2 - bottommargin)), 													Endsquare, Endsquare, 0, 												green, ZP);						}						break;					case SInte:						if (_e->time > prevts && _e->time <= newestts) {							sx = time2x(_e->time);							line(screen, addpt(p, Pt(sx, Height / 2 - bottommargin)), 												addpt(p, Pt(sx, Height - bottommargin)), 												Endsquare, Endsquare, 0, 												blue, ZP);						}						break;					}				}				break;			}		}		p.y += Height;	} 	ts = prevts + scales[scaleno].littletics - (prevts % scales[scaleno].littletics);	x = time2x(ts); 	while(x < Width){		p = screen->r.min;		for(n = 0; n < ntasks; n++){			int height, width; 			/* p is upper left corner for this task */			if ((ts % scales[scaleno].scale) == 0){				height = 10 * Height;				width = 1;			}else if ((ts % scales[scaleno].bigtics) == 0){				height = 12 * Height;				width = 0;			}else{				height = 13 * Height;				width = 0;			}			height >>= 4; 			line(screen, addpt(p, Pt(x, height)), addpt(p, Pt(x, Height - lineht)),				Endsquare, Endsquare, width, cols[n % Ncolor][2], ZP); 			p.y += Height;		}		ts += scales[scaleno].littletics;		x = time2x(ts);	} 	rtime = screen->r;	rtime.min.y = rtime.max.y - tinyfont->height + 2;	draw(screen, rtime, bg, nil, ZP);	ts = oldestts + scales[scaleno].bigtics - (oldestts % scales[scaleno].bigtics);	x = time2x(ts);	ss = 0;	while(x < Width){		snprint(buf, sizeof(buf), "%t", ss);		string(screen, addpt(p, Pt(x - stringwidth(tinyfont, buf)/2, - tinyfont->height - 1)), 			fg, ZP, tinyfont, buf);		ts += scales[scaleno].bigtics;		ss += scales[scaleno].bigtics;		x = time2x(ts);	} 	snprint(buf, sizeof(buf), "%t", now);	string(screen, Pt(screen->r.max.x - stringwidth(mediumfont, buf), screen->r.min.y), 		fg, ZP, mediumfont, buf);		flushimage(display, 1);	prevts = newestts;} Task*newtask(ulong pid){	Task *t;	char buf[64], *p;	int fd,n; 	tasks = realloc(tasks, (ntasks + 1) * sizeof(Task));	assert(tasks); 	t = &tasks[ntasks++];	memset(t, 0, sizeof(Task));	t->events = nil;	snprint(buf, sizeof buf, "/proc/%ld/status", pid);	t->name = nil;	fd = open(buf, OREAD);	if (fd >= 0){		n = read(fd, buf, sizeof buf);		if(n > 0){			p = buf + sizeof buf - 1;			*p = 0;			p = strchr(buf, ' ');			if (p) *p = 0;			t->name = strdup(buf);		}else			print("%s: %r\n", buf);		close(fd);	}else		print("%s: %r\n", buf);	t->pid = pid;	prevts = 0;	if (newwin){		fprint(wctlfd, "resize -dx %d -dy %d\n",			Width + 20, (ntasks * Height) + 5);	}else		Height = ntasks ? Dy(screen->r)/ntasks : Dy(screen->r);	return t;} voiddoevent(Task *t, Traceevent *ep)

Lines 1–500 of 759.