ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/cprof.b/
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 ... ]\n");
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;
}