implement Prof; include "sys.m"; sys: Sys;include "draw.m";include "arg.m"; arg: Arg;include "profile.m"; profile: Profile;include "sh.m"; stderr: ref Sys->FD; Prof: module { init: fn(nil: ref Draw->Context, argv: list of string); init0: fn(nil: ref Draw->Context, argv: list of string): Profile->Coverage;}; exits(e: string){ if(profile != nil) profile->end(); raise "fail:" + e;} pfatal(s: string){ sys->fprint(stderr, "cprof: %s: %s\n", s, profile->lasterror()); exits("error");} badmodule(p: string){ sys->fprint(stderr, "cprof: cannot load %s: %r\n", p); exits("bad module");} usage(s: string){ sys->fprint(stderr, "cprof: %s\n", s); sys->fprint(stderr, "usage: cprof [-fner] [-m modname]... cmd [arg ... ]"); exits("usage");} init(ctxt: ref Draw->Context, argv: list of string){ init0(ctxt, argv);} init0(ctxt: ref Draw->Context, argv: list of string): Profile->Coverage{ sys = load Sys Sys->PATH; stderr = sys->fildes(2); arg = load Arg Arg->PATH; if(arg == nil) badmodule(Arg->PATH); arg->init(argv); profile = load Profile Profile->PATH; if(profile == nil) badmodule(Profile->PATH); if(profile->init() < 0) pfatal("cannot initialize profile device"); v := 0; ep := 0; rec := 0; wm := 0; exec, mods: list of string; while((c := arg->opt()) != 0){ case c { 'n' => v |= profile->FULLHDR; 'f' => v |= profile->FREQUENCY; 'm' => if((s := arg->arg()) == nil) usage("missing module/file"); mods = s :: mods; 'e' => ep = 1; 'r' => rec = 1; 'g' => wm = 1; * => usage(sys->sprint("unknown option -%c", c)); } } exec = arg->argv(); # if(exec == nil) # usage("nothing to execute"); for( ; mods != nil; mods = tl mods) profile->profile(hd mods); if(ep && exec != nil) profile->profile(disname(hd exec)); if(exec != nil){ wfd := openwait(sys->pctl(0, nil)); ci := chan of int; spawn execute(ctxt, hd exec, exec, ci); epid := <- ci; if(profile->cpstart(epid) < 0){ ci <-= 0; pfatal("cannot start profiling"); } ci <-= 1; wait(wfd, epid); if(profile->stop() < 0) pfatal("cannot stop profiling"); } if(exec == nil) modl := profile->cpfstats(v); else modl = profile->cpstats(rec, v); if(modl.mods == nil) pfatal("no profile information"); if(wm){ cvr := profile->coverage(modl, v); profile->end(); return cvr; } if(!rec && profile->cpshow(modl, v) < 0) pfatal("cannot show profile"); profile->end(); return nil;} disname(cmd: string): string{ file := cmd; if(len file<4 || file[len file-4:]!=".dis") file += ".dis"; if(exists(file)) return file; if(file[0]!='/' && file[0:2]!="./") file = "/dis/"+file; # if(exists(file)) # return file; return file;} execute(ctxt: ref Draw->Context, cmd : string, argl : list of string, ci: chan of int){ ci <-= sys->pctl(Sys->FORKNS|Sys->NEWFD|Sys->NEWPGRP, 0 :: 1 :: 2 :: stderr.fd :: nil); file := cmd; err := ""; if(len file<4 || file[len file-4:]!=".dis") file += ".dis"; c := load Command file; if(c == nil) { err = sys->sprint("%r"); if(file[0]!='/' && file[0:2]!="./"){ c = load Command "/dis/"+file; if(c == nil) err = sys->sprint("%r"); } } if(<- ci){ if(c == nil) sys->fprint(stderr, "cprof: %s: %s\n", cmd, err); else c->init(ctxt, argl); }} openwait(pid : int) : ref Sys->FD{ w := sys->sprint("#p/%d/wait", pid); fd := sys->open(w, Sys->OREAD); if (fd == nil) pfatal("fd == nil in wait"); return fd;} wait(wfd : ref Sys->FD, wpid : int){ n : int; buf := array[Sys->WAITLEN] of byte; status := ""; for(;;) { if ((n = sys->read(wfd, buf, len buf)) < 0) pfatal("bad read in wait"); status = string buf[0:n]; if (int status == wpid) break; }} exists(f: string): int{ return sys->open(f, Sys->OREAD) != nil;}
implement Prof;
include "sys.m";
sys: Sys;
include "draw.m";
include "arg.m";
arg: Arg;
include "profile.m";
profile: Profile;
include "sh.m";
stderr: ref Sys->FD;
Prof: module {
init: fn(nil: ref Draw->Context, argv: list of string);
init0: fn(nil: ref Draw->Context, argv: list of string): Profile->Coverage;
};
exits(e: string)
{
if(profile != nil)
profile->end();
raise "fail:" + e;
}
pfatal(s: string)
{
sys->fprint(stderr, "cprof: %s: %s\n", s, profile->lasterror());
exits("error");
}
badmodule(p: string)
{
sys->fprint(stderr, "cprof: cannot load %s: %r\n", p);
exits("bad module");
}
usage(s: string)
{
sys->fprint(stderr, "cprof: %s\n", s);
sys->fprint(stderr, "usage: cprof [-fner] [-m modname]... cmd [arg ... ]");
exits("usage");
}
init(ctxt: ref Draw->Context, argv: list of string)
{
init0(ctxt, argv);
}
init0(ctxt: ref Draw->Context, argv: list of string): Profile->Coverage
{
sys = load Sys Sys->PATH;
stderr = sys->fildes(2);
arg = load Arg Arg->PATH;
if(arg == nil)
badmodule(Arg->PATH);
arg->init(argv);
profile = load Profile Profile->PATH;
if(profile == nil)
badmodule(Profile->PATH);
if(profile->init() < 0)
pfatal("cannot initialize profile device");
v := 0;
ep := 0;
rec := 0;
wm := 0;
exec, mods: list of string;
while((c := arg->opt()) != 0){
case c {
'n' => v |= profile->FULLHDR;
'f' => v |= profile->FREQUENCY;
'm' =>
if((s := arg->arg()) == nil)
usage("missing module/file");
mods = s :: mods;
'e' =>
ep = 1;
'r' =>
rec = 1;
'g' =>
wm = 1;
* =>
usage(sys->sprint("unknown option -%c", c));
}
}
exec = arg->argv();
# if(exec == nil)
# usage("nothing to execute");
for( ; mods != nil; mods = tl mods)
profile->profile(hd mods);
if(ep && exec != nil)
profile->profile(disname(hd exec));
if(exec != nil){
wfd := openwait(sys->pctl(0, nil));
ci := chan of int;
spawn execute(ctxt, hd exec, exec, ci);
epid := <- ci;
if(profile->cpstart(epid) < 0){
ci <-= 0;
pfatal("cannot start profiling");
}
ci <-= 1;
wait(wfd, epid);
if(profile->stop() < 0)
pfatal("cannot stop profiling");
}
if(exec == nil)
modl := profile->cpfstats(v);
else
modl = profile->cpstats(rec, v);
if(modl.mods == nil)
pfatal("no profile information");
if(wm){
cvr := profile->coverage(modl, v);
profile->end();
return cvr;
}
if(!rec && profile->cpshow(modl, v) < 0)
pfatal("cannot show profile");
profile->end();
return nil;
}
disname(cmd: string): string
{
file := cmd;
if(len file<4 || file[len file-4:]!=".dis")
file += ".dis";
if(exists(file))
return file;
if(file[0]!='/' && file[0:2]!="./")
file = "/dis/"+file;
# if(exists(file))
# return file;
return file;
}
execute(ctxt: ref Draw->Context, cmd : string, argl : list of string, ci: chan of int)
{
ci <-= sys->pctl(Sys->FORKNS|Sys->NEWFD|Sys->NEWPGRP, 0 :: 1 :: 2 :: stderr.fd :: nil);
file := cmd;
err := "";
if(len file<4 || file[len file-4:]!=".dis")
file += ".dis";
c := load Command file;
if(c == nil) {
err = sys->sprint("%r");
if(file[0]!='/' && file[0:2]!="./"){
c = load Command "/dis/"+file;
if(c == nil)
err = sys->sprint("%r");
}
}
if(<- ci){
if(c == nil)
sys->fprint(stderr, "cprof: %s: %s\n", cmd, err);
else
c->init(ctxt, argl);
}
}
openwait(pid : int) : ref Sys->FD
{
w := sys->sprint("#p/%d/wait", pid);
fd := sys->open(w, Sys->OREAD);
if (fd == nil)
pfatal("fd == nil in wait");
return fd;
}
wait(wfd : ref Sys->FD, wpid : int)
{
n : int;
buf := array[Sys->WAITLEN] of byte;
status := "";
for(;;) {
if ((n = sys->read(wfd, buf, len buf)) < 0)
pfatal("bad read in wait");
status = string buf[0:n];
if (int status == wpid)
break;
}
}
exists(f: string): int
{
return sys->open(f, Sys->OREAD) != nil;
}