code: purgatorio

ref: 82a3f55c5fb7b9f7a82449e4eb943c535ec3e491
dir: /appl/wm/memory.b/

View raw version
implement WmMemory;

include "sys.m";
	sys: Sys;

include "draw.m";
	draw: Draw;
	Display, Image, Rect: import draw;

include "tk.m";
	tk: Tk;
	t: ref Tk->Toplevel;

include	"tkclient.m";
	tkclient: Tkclient;

WmMemory: module
{
	init:	fn(ctxt: ref Draw->Context, argv: list of string);
};

Arena: adt
{
	name:	string;
	limit:	int;
	size:	int;
	hw:	int;
	allocs: int;
	frees: int;
	exts: int;
	chunk: int;
	y:	int;
	tag:	string;
	tagsz: string;
	taghw:	string;
	tagiu:	string;
};
a := array[10] of Arena;

mem_cfg := array[] of {
	"canvas .c -width 240 -height 45",
	"pack .c",
	"update",
};

init(ctxt: ref Draw->Context, nil: list of string)
{
	spawn realinit(ctxt);
}

realinit(ctxt: ref Draw->Context)
{
	sys = load Sys Sys->PATH;
	if (ctxt == nil) {
		sys->fprint(sys->fildes(2), "memory: no window context\n");
		raise "fail:bad context";
	}
	draw = load Draw Draw->PATH;
	tk = load Tk Tk->PATH;
	tkclient = load Tkclient Tkclient->PATH;
	sys->pctl(Sys->NEWPGRP, nil);
	tkclient->init();

	menubut := chan of string;
	(t, menubut) = tkclient->toplevel(ctxt, "", "Memory", 0);
	for(j := 0; j < len mem_cfg; j++)
		cmd(t, mem_cfg[j]);
	tkclient->startinput(t, "ptr"::nil);
	tkclient->onscreen(t, nil);

	tick := chan of int;
	spawn ticker(tick);

	mfd := sys->open("/dev/memory", sys->OREAD);

	n := getmem(mfd);
	maxx := initdraw(n);

	pid: int;
	for(;;) alt {
	s := <-t.ctxt.ptr =>
		tk->pointer(t, *s);
	s := <-t.ctxt.ctl or
	s = <-t.wreq or
	s = <-menubut =>
		if(s == "exit"){
			kill(pid);
			return;
		}
		tkclient->wmctl(t, s);
	pid = <-tick =>
		update(mfd);
		for(i := 0; i < n; i++) {
			if(a[i].limit <= 0)
				continue;
			x := int ((big a[i].size * big (230-maxx)) / big a[i].limit);
			s := sys->sprint(".c coords %s %d %d %d %d",
				a[i].tag,
				maxx,
				a[i].y + 4,
				maxx + x,
				a[i].y + 8);
			cmd(t, s);
			x = int ((big a[i].hw * big (230-maxx)) / big a[i].limit);
			s = sys->sprint(".c coords %s %d %d %d %d",
				a[i].taghw,
				maxx,
				a[i].y + 4,
				maxx+x,
				a[i].y + 8);
			cmd(t, s);
			s = sys->sprint(".c itemconfigure %s -text '%s", a[i].tagsz, string a[i].size);
			cmd(t, s);
			s = sys->sprint(".c itemconfigure %s -text '%d", a[i].tagiu, a[i].allocs-a[i].frees);
			cmd(t, s);
		}
		cmd(t, "update");
	}
}

ticker(c: chan of int)
{
	pid := sys->pctl(0, nil);
	for(;;) {
		c <-= pid;
		sys->sleep(1000);
	}
}

initdraw(n: int): int
{
	y := 15;
	maxx := 0;
	for (i := 0; i < n; i++) {
		id := cmd(t, ".c create text 5 "+string y+" -anchor w -text "+a[i].name);
		r := s2r(cmd(t, ".c bbox " + id));
		if (r.max.x > maxx)
			maxx = r.max.x;
		y += 20;
	}
	maxx += 5;
	y = 15;
	for(i = 0; i < n; i++) {
		s := sys->sprint(".c create rectangle %d %d 230 %d -fill white", maxx, y+4, y+8);
		cmd(t, s);
		s = sys->sprint(".c create rectangle %d %d 230 %d -fill white", maxx, y+4, y+8);
		a[i].taghw = cmd(t, s);
		s = sys->sprint(".c create rectangle %d %d 230 %d -fill red", maxx, y+4, y+8);
		a[i].tag = cmd(t, s);
		s = sys->sprint(".c create text 230 %d -anchor e -text '%s", y - 2, sizestr(a[i].limit));
		cmd(t, s);
		s = sys->sprint(".c create text %d %d -anchor w -text '%s", maxx, y - 2, string a[i].size);
		a[i].tagsz = cmd(t, s);
		s = sys->sprint(".c create text 120 %d -fill red -anchor w -text '%d", y - 2, a[i].allocs-a[i].frees);
		a[i].tagiu = cmd(t, s);
		a[i].y = y;
		y += 20;
	}
	cmd(t, ".c configure -height "+string y);
	cmd(t, "update");
	return maxx;
}

sizestr(n: int): string
{
	if ((n / 1024) % 1024 == 0)
		return string (n / (1024 * 1024)) + "M";
	return string (n / 1024) + "K";
}

buf := array[8192] of byte;

update(mfd: ref Sys->FD): int
{
	sys->seek(mfd, big 0, Sys->SEEKSTART);
	n := sys->read(mfd, buf, len buf);
	if(n <= 0)
		exit;
	(nil, l) := sys->tokenize(string buf[0:n], "\n");
	i := 0;
	while(l != nil) {
		s := hd l;
		a[i].size = int s[0:];
		a[i].hw = int s[24:];
		a[i].allocs = int s[3*12:];
		a[i].frees = int s[4*12:];
		a[i].exts = int s[5*12:];
		a[i++].chunk = int s[6*12:];
		l = tl l;
	}
	return i;
}

getmem(mfd: ref Sys->FD): int
{
	n := sys->read(mfd, buf, len buf);
	if(n <= 0)
		exit;
	(nil, l) := sys->tokenize(string buf[0:n], "\n");
	i := 0;
	while(l != nil) {
		s := hd l;
		a[i].size = int s[0:];
		a[i].limit = int s[12:];
		a[i].hw = int s[2*12:];
		a[i].allocs = int s[3*12:];
		a[i].frees = int s[4*12:];
		a[i].exts = int s[5*12:];
		a[i].chunk = int s[6*12:];
		a[i].name = s[7*12:];
		i++;
		l = tl l;
	}
	return i;
}

s2r(s: string): Rect
{
	(n, toks) := sys->tokenize(s, " ");
	if (n != 4) {
		sys->print("'%s' is not a rectangle!\n", s);
		raise "bad conversion";
	}
	r: Rect;
	(r.min.x, toks) = (int hd toks, tl toks);
	(r.min.y, toks) = (int hd toks, tl toks);
	(r.max.x, toks) = (int hd toks, tl toks);
	(r.max.y, toks) = (int hd toks, tl toks);
	return r;
}

kill(pid: int)
{
	fd := sys->open("#p/"+string pid+"/ctl", sys->OWRITE);
	if(fd != nil)
		sys->fprint(fd, "kill");
}


cmd(top: ref Tk->Toplevel, s: string): string
{
	e := tk->cmd(top, s);
	if (e != nil && e[0] == '!')
		sys->print("memory: tk error on '%s': %s\n", s, e);
	return e;
}