summaryrefslogtreecommitdiff
path: root/appl/cmd/cprof.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/cprof.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/cprof.b')
-rw-r--r--appl/cmd/cprof.b190
1 files changed, 190 insertions, 0 deletions
diff --git a/appl/cmd/cprof.b b/appl/cmd/cprof.b
new file mode 100644
index 00000000..846a75bd
--- /dev/null
+++ b/appl/cmd/cprof.b
@@ -0,0 +1,190 @@
+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;
+}