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->Prof; 17}; 18 19ignored(s: string) 20{ 21 sys->fprint(stderr, "mprof: warning: %s ignored\n", s); 22} 23 24exits(e: string) 25{ 26 if(profile != nil) 27 profile->end(); 28 raise "fail:" + e; 29} 30 31pfatal(s: string) 32{ 33 sys->fprint(stderr, "mprof: %s: %s\n", s, profile->lasterror()); 34 exits("error"); 35} 36 37badmodule(p: string) 38{ 39 sys->fprint(stderr, "mprof: cannot load %s: %r\n", p); 40 exits("bad module"); 41} 42 43usage(s: string) 44{ 45 sys->fprint(stderr, "mprof: %s\n", s); 46 sys->fprint(stderr, "usage: mprof [-bcMflnve] [-m modname]... [cmd arg ...]\n"); 47 exits("usage"); 48} 49 50init(ctxt: ref Draw->Context, argv: list of string) 51{ 52 init0(ctxt, argv); 53} 54 55init0(ctxt: ref Draw->Context, argv: list of string): Profile->Prof 56{ 57 sys = load Sys Sys->PATH; 58 stderr = sys->fildes(2); 59 arg = load Arg Arg->PATH; 60 if(arg == nil) 61 badmodule(Arg->PATH); 62 arg->init(argv); 63 profile = load Profile Profile->PATH; 64 if(profile == nil) 65 badmodule(Profile->PATH); 66 if(profile->init() < 0) 67 pfatal("cannot initialize profile device"); 68 69 v := 0; 70 begin := end := 0; 71 ep := 0; 72 wm := 0; 73 mem := 0; 74 exec, mods: list of string; 75 while((c := arg->opt()) != 0){ 76 case c { 77 'b' => begin = 1; 78 'c' => end = 1; 79 'M' => v |= profile->MODULE; 80 'f' => v |= profile->FUNCTION; 81 'l' => v |= profile->LINE; 82 'n' => v |= profile->FULLHDR; 83 'v' => v |= profile->VERBOSE; 84 'm' => 85 if((s := arg->arg()) == nil) 86 usage("missing module name"); 87 mods = s :: mods; 88 'e' => 89 ep = 1; 90 'g' => 91 wm = 1; 92 '1' => 93 mem |= Profile->MAIN; 94 '2' => 95 mem |= Profile->HEAP; 96 '3' => 97 mem |= Profile->IMAGE; 98 * => 99 usage(sys->sprint("unknown option -%c", c)); 100 } 101 } 102 103 exec = arg->argv(); 104 105 if(begin && end) 106 ignored("-e option"); 107 if((begin || end) && v != 0) 108 ignored("output format"); 109 if(begin && exec != nil) 110 begin = 0; 111 if(begin == 0 && exec == nil){ 112 if(mods != nil) 113 ignored("-m option"); 114 mods = nil; 115 } 116 if(end){ 117 if(mods != nil) 118 ignored("-m option"); 119 if(ep || exec != nil) 120 ignored("command"); 121 profile->end(); 122 exit; 123 } 124 125 for( ; mods != nil; mods = tl mods) 126 profile->profile(hd mods); 127 128 if(begin){ 129 if(profile->memstart(mem) < 0) 130 pfatal("cannot start profiling"); 131 exit; 132 } 133 r := 0; 134 if(exec != nil){ 135 if(ep) 136 profile->profile(disname(hd exec)); 137 if(profile->memstart(mem) < 0) 138 pfatal("cannot start profiling"); 139 # r = run(ctxt, hd exec, exec); 140 wfd := openwait(sys->pctl(0, nil)); 141 ci := chan of int; 142 spawn execute(ctxt, hd exec, exec, ci); 143 epid := <- ci; 144 wait(wfd, epid); 145 } 146 if(profile->stop() < 0) 147 pfatal("cannot stop profiling"); 148 if(exec == nil || r >= 0){ 149 modl := profile->memstats(); 150 if(modl.mods == nil) 151 pfatal("no profile information"); 152 if(wm){ 153 if(exec == nil){ 154 if(profile->memstart(mem) < 0) 155 pfatal("cannot restart profiling"); 156 } 157 else 158 profile->end(); 159 return modl; 160 } 161 if(!(v&(profile->MODULE|profile->FUNCTION|profile->LINE))) 162 v |= profile->MODULE|profile->LINE; 163 if(profile->memshow(modl, v) < 0) 164 pfatal("cannot show profile"); 165 if(exec == nil){ 166 if(profile->memstart(mem) < 0) 167 pfatal("cannot restart profiling"); 168 exit; 169 } 170 } 171 profile->end(); 172 return (nil, 0, nil); 173} 174 175disname(cmd: string): string 176{ 177 file := cmd; 178 if(len file<4 || file[len file-4:]!=".dis") 179 file += ".dis"; 180 if(exists(file)) 181 return file; 182 if(file[0]!='/' && file[0:2]!="./") 183 file = "/dis/"+file; 184 # if(exists(file)) 185 # return file; 186 return file; 187} 188 189execute(ctxt: ref Draw->Context, cmd : string, argl : list of string, ci: chan of int) 190{ 191 ci <-= sys->pctl(Sys->FORKNS|Sys->NEWFD|Sys->NEWPGRP, 0 :: 1 :: 2 :: stderr.fd :: nil); 192 file := cmd; 193 if(len file<4 || file[len file-4:]!=".dis") 194 file += ".dis"; 195 c := load Command file; 196 if(c == nil) { 197 err := sys->sprint("%r"); 198 if(file[0]!='/' && file[0:2]!="./"){ 199 c = load Command "/dis/"+file; 200 if(c == nil) 201 err = sys->sprint("%r"); 202 } 203 if(c == nil){ 204 sys->fprint(stderr, "mprof: %s: %s\n", cmd, err); 205 return; 206 } 207 } 208 c->init(ctxt, argl); 209} 210 211# run(ctxt: ref Draw->Context, cmd : string, argl : list of string): int 212# { 213# file := cmd; 214# if(len file<4 || file[len file-4:]!=".dis") 215# file += ".dis"; 216# c := load Command file; 217# if(c == nil) { 218# err := sys->sprint("%r"); 219# if(file[0]!='/' && file[0:2]!="./"){ 220# c = load Command "/dis/"+file; 221# if(c == nil) 222# err = sys->sprint("%r"); 223# } 224# if(c == nil){ 225# sys->fprint(stderr, "mprof: %s: %s\n", cmd, err); 226# return -1; 227# } 228# } 229# c->init(ctxt, argl); 230# return 0; 231# } 232 233openwait(pid : int) : ref Sys->FD 234{ 235 w := sys->sprint("#p/%d/wait", pid); 236 fd := sys->open(w, Sys->OREAD); 237 if (fd == nil) 238 pfatal("fd == nil in wait"); 239 return fd; 240} 241 242wait(wfd : ref Sys->FD, wpid : int) 243{ 244 n : int; 245 246 buf := array[Sys->WAITLEN] of byte; 247 status := ""; 248 for(;;) { 249 if ((n = sys->read(wfd, buf, len buf)) < 0) 250 pfatal("bad read in wait"); 251 status = string buf[0:n]; 252 if (int status == wpid) 253 break; 254 } 255} 256 257exists(f: string): int 258{ 259 return sys->open(f, Sys->OREAD) != nil; 260} 261