Changeset 220
- Timestamp:
- 01/22/08 04:33:30 (10 months ago)
- Files:
-
- trunk/ptrace/ptrace.d (modified) (18 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/ptrace/ptrace.d
r48 r220 7 7 import tango.core.Array; 8 8 import tango.stdc.ctype; 9 import tango.util.Arg Parser;9 import tango.util.Arguments; 10 10 import tango.text.stream.LineIterator; 11 11 import tango.sys.Process; 12 import tango.sys.Environment; 13 import tango.stdc.stdio; 12 14 import Regex = tango.text.Regex; 13 15 import Util = tango.text.Util; … … 27 29 28 30 bool showHelp = false; 31 bool onePass = false; 29 32 30 33 enum ParseMode … … 35 38 36 39 ParseMode mode = ParseMode.QualifiedName; 37 char[] helpTxt = "ptrace translates dmd profiler output to a .d file for generating readable html with ddoc\n"38 " usage: ptrace [file] options\n"40 char[] helpTxt = 41 " usage: ptrace [file] [options]\n" 39 42 " -t=<target> write to target, must be with d extension for dmd\n" 40 43 " -s=<mode> specifies how to write symbols, <mode> can be of one:\n" … … 42 45 " SYM identifier only, not type information\n" 43 46 " SEP seperate columns for type and identifier\n" 44 45 " -h this help text\n\n" 46 " if no file has been given, trace.log is assumed\n"; 47 " -h this help text\n" 48 " -t=<target> write to target, must be with d extension for dmd\n" 49 " -f do not ask for permission to overwrite existing files\n" 50 " -x eXecute dmd and generate html instead of ddoc code\n\n" 51 " if no source file has been given, trace.log is assumed\n" 52 " if no target file has been given, -x is assumed\n"; 53 47 54 48 55 /* TODO: implement these options correctly … … 55 62 bool parseArgs(char[][] args) 56 63 { 57 ArgParser argParser = new ArgParser((char[] value, uint ordinal) 58 { 59 if (ordinal > 0) 60 { 61 Stdout("error: multiple source files have been given.").newline; 62 showHelp = true; 63 } 64 sourceFile = value; 65 }); 66 67 argParser.bind("-", "h", { showHelp = true ; }); 68 argParser.bind("-s=", "FQN", { graphMode = timingsMode = SymbolMode.FQN; }); 69 argParser.bind("-s=", "SYM", { graphMode = timingsMode = SymbolMode.SYM; }); 70 argParser.bind("-s=", "SEP", { graphMode = timingsMode = SymbolMode.SEP; }); 71 72 argParser.bindDefault("-t=", (char[] value, uint ordinal) 73 { 74 if (ordinal > 0) 75 { 76 Stdout("error: multiple target files have been given.").newline; 77 showHelp = true; 78 } 79 targetFile = value; 80 }); 81 82 argParser.bindDefault("-tt=", (char[] value, uint ordinal) 83 { 84 if (ordinal > 0) 85 { 86 Stdout("error: multiple target files have been given.").newline; 87 showHelp = true; 88 } 89 targetTimingsFile = value; 90 }); 91 92 argParser.bindDefault("-tg=", (char[] value, uint ordinal) 93 { 94 if (ordinal > 0) 95 { 96 Stdout("error: multiple target files have been given.").newline; 97 showHelp = true; 98 } 99 targetGraphFile = value; 100 }); 101 102 if (args.length < 2) 103 { 104 Stdout(helpTxt).newline; 105 return false; 106 } 107 108 argParser.parse(args[1..$]); 109 110 if (!targetFile.length) 64 bool force = false; 65 66 auto arguments = new Arguments(args, ["source"]); 67 if (arguments["source"].length == 1) 68 sourceFile = arguments["source"][0]; 69 else if (arguments["source"].length > 1) 70 { 71 Stdout("wrong number of source files").newline; 111 72 showHelp = true; 112 73 } 74 else 75 sourceFile = "trace.log"; 76 77 with(arguments) 78 { 79 addValidation("h", false, false); 80 addValidation("s", false, true); 81 addValidation("t", false, true); 82 addValidation("f", false, false); 83 addValidation("x", false, false); 84 } 85 86 if ("h" in arguments) 87 showHelp = true; 88 89 if ("x" in arguments) 90 onePass = true; 91 92 if ("f" in arguments) 93 force = true; 94 95 if ("s" in arguments) 96 { 97 switch(arguments["s"][0]) 98 { 99 case "FQN": graphMode = timingsMode = SymbolMode.FQN; break; 100 case "SYM": graphMode = timingsMode = SymbolMode.SYM; break; 101 case "SEP": graphMode = timingsMode = SymbolMode.SEP; break; 102 default: showHelp = true; break; 103 } 104 } 105 if (arguments["t"].length) 106 targetFile = arguments["t"][0]; 107 else 108 { 109 targetFile = "ddoc_" ~ sourceFile ~ ".d"; 110 onePass = true; 111 } 112 113 if( (new FilePath(targetFile)).exists() && !force) 114 { 115 char response; 116 while (true) 117 { 118 Stdout.format("Are you sure you want to overwrite {} (y/n)?", targetFile).newline; 119 response = getchar(); 120 if (response == 'n' || response == 'N') 121 return false; 122 else if (response == 'y' || response == 'Y') 123 break; 124 } 125 } 126 127 return true; 128 } 129 130 131 int main(char[][] args) 132 { 133 Stdout("Ptrace. Utility to prettify trace.log files. ptrace -h for help.\n"); 134 if (!parseArgs(args)) 135 return 0; 113 136 if (showHelp) 114 137 { 115 Stdout(helpTxt).newline; 116 return false; 117 } 118 119 if(!sourceFile.length) 120 sourceFile = "trace.log"; 121 return true; 122 } 123 124 125 void main(char[][] args) 126 { 127 if (!parseArgs(args)) 128 return; 129 130 Stdout.format("Reading from {0} and writing to {1}", sourceFile, targetFile).newline; 138 Stdout(helpTxt); 139 return 0; 140 } 141 142 //Stdout.format("Reading from {0} and writing to {1}", sourceFile, targetFile).newline; 131 143 132 144 auto reader = new TraceReader(sourceFile, new TraceParser); … … 147 159 } 148 160 149 output.output.write("Ddoc\n$(TIMINGS $(HEADER_CALLS Num calls) $(HEADER_TREE Tree Time)" 161 Stdout("writing output to " ~ targetFile ~ "...").newline; 162 output.output.write("Ddoc\n"); 163 164 if (onePass) 165 { 166 output.output.write(macros); 167 } 168 169 output.output.write("\n$(TIMINGS $(HEADER_CALLS Num calls) $(HEADER_TREE Tree Time)" 150 170 "$(HEADER_FUNC Func Time) $(HEADER_CALL Per Call)" ~ header() ); 151 171 … … 163 183 164 184 foreach(timing; reader.timings) 165 output.output.write( " $(TIMING $(CALLS " ~ to Utf8(timing.calls) ~ ")"166 " $(TREE " ~ to Utf8(timing.tree) ~ ") $(FUNC " ~ toUtf8(timing.func) ~ ")"167 " $(CALL " ~ to Utf8(timing.call) ~ ")" ~ functionName(timing.mangled) );185 output.output.write( " $(TIMING $(CALLS " ~ toString(timing.calls) ~ ")" 186 " $(TREE " ~ toString(timing.tree) ~ ") $(FUNC " ~ toString(timing.func) ~ ")" 187 " $(CALL " ~ toString(timing.call) ~ ")" ~ functionName(timing.mangled) ); 168 188 169 189 output.output.write(")\n $(CALL_GRAPH \n"); … … 179 199 output.output.write("$(CALL_SEP )\n"); 180 200 foreach(fun; node.fan_in) 181 output.output.write("$(FAN $(FAN_FUNC " ~ reader.getFQN(fun.mangled) ~ ") $(FAN_CALLS " ~ to Utf8(fun.numCalls) ~ "))\n");201 output.output.write("$(FAN $(FAN_FUNC " ~ reader.getFQN(fun.mangled) ~ ") $(FAN_CALLS " ~ toString(fun.numCalls) ~ "))\n"); 182 202 183 203 output.output.write("$(CALL_FUN $(CALL_FUN_NAME 2, " ~ reader.getFQN(node.mangled) ~ 184 ") $(CALL_FUN_TREE " ~ ConvertFloat.to Utf8(cast(real)node.tree / reader.freq, 2, false ) ~ ")"185 " $(CALL_FUN_FUNC " ~ ConvertFloat.to Utf8(cast(real)node.func / reader.freq, 2, false) ~ ")"186 " $(CALL_FUN_CALLS " ~ to Utf8(node.count) ~ ") )\n" );204 ") $(CALL_FUN_TREE " ~ ConvertFloat.toString(cast(real)node.tree / reader.freq, 2, false ) ~ ")" 205 " $(CALL_FUN_FUNC " ~ ConvertFloat.toString(cast(real)node.func / reader.freq, 2, false) ~ ")" 206 " $(CALL_FUN_CALLS " ~ toString(node.count) ~ ") )\n" ); 187 207 188 208 foreach(fun; node.fan_out) 189 output.output.write("$(FAN $(FAN_FUNC " ~ reader.demangleSymbol(fun.mangled) ~ ") $(FAN_CALLS " ~ to Utf8(fun.numCalls) ~ ") )\n");209 output.output.write("$(FAN $(FAN_FUNC " ~ reader.demangleSymbol(fun.mangled) ~ ") $(FAN_CALLS " ~ toString(fun.numCalls) ~ ") )\n"); 190 210 191 211 } 192 212 output.output.write(")\n"); 193 213 output.close; 214 215 if (onePass) 216 { 217 Stdout("generating html...").newline; 218 Process dmd = new Process(Environment.exePath("dmd").toString, "-D"[], targetFile, null); 219 dmd.execute(); 220 auto result = dmd.wait(); 221 Stdout("removing temporary files...").newline; 222 (new FilePath(targetFile)).remove(); 223 return result.status; 224 } 225 return 0; 194 226 } 195 227 … … 205 237 FuncCall[] fan_in; 206 238 FuncCall[] fan_out; 207 u intcount;208 u inttree;209 u intfunc;239 ulong count; 240 ulong tree; 241 ulong func; 210 242 } 211 243 … … 213 245 { 214 246 char[] mangled; 215 u intcalls;247 ulong calls; 216 248 // timings: 217 u inttree;218 u intfunc;219 u intcall;249 ulong tree; 250 ulong func; 251 ulong call; 220 252 } 221 253 … … 236 268 237 269 if (index > 0) 238 numcalls = to Int(line[0..index]);270 numcalls = toLong(line[0..index]); 239 271 240 272 index = rfindIf(line, isSpace); … … 257 289 func = Util.trim(func[index..$]); 258 290 index = findIf(func, isSpace); 291 259 292 if (index > 0) 260 nodes[$-1].count = to Int(func[0..index]);293 nodes[$-1].count = toLong(func[0..index]); 261 294 262 295 // function time … … 264 297 index = rfindIf(func, isSpace); 265 298 if (index > 0) 266 nodes[$-1].tree = to Int(func[0..index]);299 nodes[$-1].tree = toLong(func[0..index]); 267 300 268 301 // number of calls 269 nodes[$-1].func = to Int(Util.trim(func[index..$]));302 nodes[$-1].func = toLong(Util.trim(func[index..$])); 270 303 } 271 304 … … 371 404 bool pastCall = false; 372 405 uint count = 0; 406 373 407 374 408 while(lines.next && !pastGraph) … … 440 474 catch(Object error) 441 475 { 442 Stdout("demangle error (ignored): ")(error.to Utf8).newline;476 Stdout("demangle error (ignored): ")(error.toString).newline; 443 477 return mangledName; 444 478 } … … 450 484 451 485 452 //TODO: catch appropiate exception to not choke on invalid utf-8 symbols but instead ignore them486 //TODO: catch appropiate exception to not choke on invalid string-8 symbols but instead ignore them 453 487 char[] getFQN(char[] mangledName) 454 488 { … … 510 544 } 511 545 } 546 547 const char[] macros = 548 ` 549 macros: 550 TABLE = <table border="4" rules="none" cellpadding="6" cellspacing="6">$0</table> 551 TDR = <td align="right">$0</td> 552 TD_CSPAN = <td colspan="$1">$+</td> 553 554 TIMINGS = <h1> Timings (in microseconds) </h1>$(TABLE $0) 555 TIMING = <tr>$0</tr> 556 FUNCTION_NAME = <td>$0</td> 557 CALLS = <td align="right">$0</td> 558 TREE = <td align="right">$0</td> 559 FUNC = <td align="right">$0</td> 560 CALL = <td align="right">$0</td> 561 562 HEADER_FUNCTION_NAME = <th>$0</th> 563 HEADER_CALLS = <th>$0</th> 564 HEADER_TREE = <th>$0</th> 565 HEADER_FUNC = <th>$0</th> 566 HEADER_CALL = <th>$0</th> 567 568 CALL_GRAPH = 569 <br> 570 <br> 571 $(P <h1> Call Graph, times are in microseconds</h1> 572 $(TABLE 573 574 <tr><td>Functions that call <i>measured function</i> (fan in)</td> 575 <td>Num calls</td> 576 </tr> 577 <tr><td colspan="2"><b>Measured function symbol</b></td> 578 <td align="right">Tree Time</td> 579 <td align="right">Func Time</td> 580 <td align="right">Num Calls</td> 581 </tr> 582 <tr><td>Functions called by <i>measured function</i> (fan out)</td> 583 <td>Num calls</td> 584 </tr> 585 $(CALL_SEP) 586 $0) ) 587 CALL_SEP = <tr><td> </td></tr> 588 CALL_FUN = <tr>$0</tr> 589 CALL_FUN_NAME = $(TD_CSPAN $1, $(B $+)) 590 CALL_FUN_TREE = <td align="right">$0</td> 591 CALL_FUN_FUNC = <td align="right">$0</td> 592 CALL_FUN_CALLS = <td align="right">$0</td> 593 FAN = <tr>$0</tr> 594 FAN_FUNC = <td>$0</td> 595 FAN_CALLS = <td>$0</td> 596 597 DDOC = <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 598 <html><head> 599 <META http-equiv="content-type" content="text/html; charset=utf-8"> 600 <link rel="stylesheet" type="text/css" href="style.css"> 601 </head><body> 602 $(BODY) 603 </body></html> 604 `; 512 605 513 606 char[] demangle(char[] name) … … 811 904 p[i] = b; 812 905 } 813 result ~= ConvertFloat.to Utf8(r);906 result ~= ConvertFloat.toString(r); 814 907 ni += 10 * 2; 815 908 }
