1implement Prof; 2 3include "sys.m"; 4 sys: Sys; 5include "draw.m"; 6include "arg.m"; 7 arg: Arg; 8include "profile.m"; 9 profile: Profile; 10include "sh.m"; 11 12stderr: ref Sys->FD; 13 14Prof: module { 15 init: fn(nil: ref Draw->Context, argv: list of string); 16 init0: fn(nil: ref Draw->Context, argv: list of string): Profile->Coverage; 17}; 18 19exits(e: string) 20{ 21 if(profile != nil) 22 profile->end(); 23 raise "fail:" + e; 24} 25 26pfatal(s: string) 27{ 28 sys->fprint(stderr, "cprof: %s: %s\n", s, profile->lasterror()); 29 exits("error"); 30} 31 32badmodule(p: string) 33{ 34 sys->fprint(stderr, "cprof: cannot load %s: %r\n", p); 35 exits("bad module"); 36} 37 38usage(s: string) 39{ 40 sys->fprint(stderr, "cprof: %s\n", s); 41 sys->fprint(stderr, "usage: cprof [-fner] [-m modname]... cmd [arg ... ]\n"); 42 exits("usage"); 43} 44 45init(ctxt: ref Draw->Context, argv: list of string) 46{ 47 init0(ctxt, argv); 48} 49 50init0(ctxt: ref Draw->Context, argv: list of string): Profile->Coverage 51{ 52 sys = load Sys Sys->PATH; 53 stderr = sys->fildes(2); 54 arg = load Arg Arg->PATH; 55 if(arg == nil) 56 badmodule(Arg->PATH); 57 arg->init(argv); 58 profile = load Profile Profile->PATH; 59 if(profile == nil) 60 badmodule(Profile->PATH); 61 if(profile->init() < 0) 62 pfatal("cannot initialize profile device"); 63 64 v := 0; 65 ep := 0; 66 rec := 0; 67 wm := 0; 68 exec, mods: list of string; 69 while((c := arg->opt()) != 0){ 70 case c { 71 'n' => v |= profile->FULLHDR; 72 'f' => v |= profile->FREQUENCY; 73 'm' => 74 if((s := arg->arg()) == nil) 75 usage("missing module/file"); 76 mods = s :: mods; 77 'e' => 78 ep = 1; 79 'r' => 80 rec = 1; 81 'g' => 82 wm = 1; 83 * => 84 usage(sys->sprint("unknown option -%c", c)); 85 } 86 } 87 exec = arg->argv(); 88 # if(exec == nil) 89 # usage("nothing to execute"); 90 for( ; mods != nil; mods = tl mods) 91 profile->profile(hd mods); 92 if(ep && exec != nil) 93 profile->profile(disname(hd exec)); 94 if(exec != nil){ 95 wfd := openwait(sys->pctl(0, nil)); 96 ci := chan of int; 97 spawn execute(ctxt, hd exec, exec, ci); 98 epid := <- ci; 99 if(profile->cpstart(epid) < 0){ 100 ci <-= 0; 101 pfatal("cannot start profiling"); 102 } 103 ci <-= 1; 104 wait(wfd, epid); 105 if(profile->stop() < 0) 106 pfatal("cannot stop profiling"); 107 } 108 if(exec == nil) 109 modl := profile->cpfstats(v); 110 else 111 modl = profile->cpstats(rec, v); 112 if(modl.mods == nil) 113 pfatal("no profile information"); 114 if(wm){ 115 cvr := profile->coverage(modl, v); 116 profile->end(); 117 return cvr; 118 } 119 if(!rec && profile->cpshow(modl, v) < 0) 120 pfatal("cannot show profile"); 121 profile->end(); 122 return nil; 123} 124 125disname(cmd: string): string 126{ 127 file := cmd; 128 if(len file<4 || file[len file-4:]!=".dis") 129 file += ".dis"; 130 if(exists(file)) 131 return file; 132 if(file[0]!='/' && file[0:2]!="./") 133 file = "/dis/"+file; 134 # if(exists(file)) 135 # return file; 136 return file; 137} 138 139execute(ctxt: ref Draw->Context, cmd : string, argl : list of string, ci: chan of int) 140{ 141 ci <-= sys->pctl(Sys->FORKNS|Sys->NEWFD|Sys->NEWPGRP, 0 :: 1 :: 2 :: stderr.fd :: nil); 142 file := cmd; 143 err := ""; 144 if(len file<4 || file[len file-4:]!=".dis") 145 file += ".dis"; 146 c := load Command file; 147 if(c == nil) { 148 err = sys->sprint("%r"); 149 if(file[0]!='/' && file[0:2]!="./"){ 150 c = load Command "/dis/"+file; 151 if(c == nil) 152 err = sys->sprint("%r"); 153 } 154 } 155 if(<- ci){ 156 if(c == nil) 157 sys->fprint(stderr, "cprof: %s: %s\n", cmd, err); 158 else 159 c->init(ctxt, argl); 160 } 161} 162 163openwait(pid : int) : ref Sys->FD 164{ 165 w := sys->sprint("#p/%d/wait", pid); 166 fd := sys->open(w, Sys->OREAD); 167 if (fd == nil) 168 pfatal("fd == nil in wait"); 169 return fd; 170} 171 172wait(wfd : ref Sys->FD, wpid : int) 173{ 174 n : int; 175 176 buf := array[Sys->WAITLEN] of byte; 177 status := ""; 178 for(;;) { 179 if ((n = sys->read(wfd, buf, len buf)) < 0) 180 pfatal("bad read in wait"); 181 status = string buf[0:n]; 182 if (int status == wpid) 183 break; 184 } 185} 186 187exists(f: string): int 188{ 189 return sys->open(f, Sys->OREAD) != nil; 190} 191