Changeset 220

Show
Ignore:
Timestamp:
01/22/08 04:33:30 (10 months ago)
Author:
Lutger
Message:

fixed to work with recent tango. Added option to directly generate html. bugfix: integer overflow in counters.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/ptrace/ptrace.d

    r48 r220  
    77import tango.core.Array; 
    88import tango.stdc.ctype; 
    9 import tango.util.ArgParser
     9import tango.util.Arguments
    1010import tango.text.stream.LineIterator; 
    11  
     11import tango.sys.Process; 
     12import tango.sys.Environment; 
     13import tango.stdc.stdio; 
    1214import Regex        = tango.text.Regex; 
    1315import Util         = tango.text.Util; 
     
    2729 
    2830bool    showHelp = false; 
     31bool    onePass = false; 
    2932 
    3033enum ParseMode 
     
    3538 
    3639ParseMode 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" 
     40char[]  helpTxt = 
     41                 "  usage: ptrace [file] [options]\n" 
    3942                 "    -t=<target>      write to target, must be with d extension for dmd\n" 
    4043                 "    -s=<mode>        specifies how to write symbols, <mode> can be of one:\n" 
     
    4245                 "                       SYM    identifier only, not type information\n" 
    4346                 "                       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 
    4754 
    4855/* TODO: implement these options correctly 
     
    5562bool parseArgs(char[][] args) 
    5663{ 
    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; 
    11172        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 
     131int 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; 
    113136    if (showHelp) 
    114137    { 
    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; 
    131143 
    132144    auto reader = new TraceReader(sourceFile, new TraceParser); 
     
    147159    } 
    148160 
    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)" 
    150170                        "$(HEADER_FUNC  Func Time) $(HEADER_CALL Per Call)" ~ header() ); 
    151171 
     
    163183 
    164184    foreach(timing; reader.timings) 
    165         output.output.write( " $(TIMING  $(CALLS " ~ toUtf8(timing.calls) ~ ")" 
    166                              " $(TREE  " ~ toUtf8(timing.tree) ~ ") $(FUNC  " ~ toUtf8(timing.func) ~ ")" 
    167                              " $(CALL  " ~ toUtf8(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) ); 
    168188 
    169189    output.output.write(")\n $(CALL_GRAPH \n"); 
     
    179199        output.output.write("$(CALL_SEP )\n"); 
    180200        foreach(fun; node.fan_in) 
    181             output.output.write("$(FAN $(FAN_FUNC " ~ reader.getFQN(fun.mangled) ~ ") $(FAN_CALLS " ~ toUtf8(fun.numCalls) ~ "))\n"); 
     201            output.output.write("$(FAN $(FAN_FUNC " ~ reader.getFQN(fun.mangled) ~ ") $(FAN_CALLS " ~ toString(fun.numCalls) ~ "))\n"); 
    182202 
    183203        output.output.write("$(CALL_FUN $(CALL_FUN_NAME 2, " ~ reader.getFQN(node.mangled) ~ 
    184                             ") $(CALL_FUN_TREE  " ~ ConvertFloat.toUtf8(cast(real)node.tree / reader.freq, 2, false ) ~ ")" 
    185                             " $(CALL_FUN_FUNC " ~ ConvertFloat.toUtf8(cast(real)node.func / reader.freq, 2, false) ~ ")" 
    186                             " $(CALL_FUN_CALLS " ~ toUtf8(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" ); 
    187207 
    188208        foreach(fun; node.fan_out) 
    189             output.output.write("$(FAN $(FAN_FUNC " ~ reader.demangleSymbol(fun.mangled) ~ ") $(FAN_CALLS  " ~ toUtf8(fun.numCalls) ~ ") )\n"); 
     209            output.output.write("$(FAN $(FAN_FUNC " ~ reader.demangleSymbol(fun.mangled) ~ ") $(FAN_CALLS  " ~ toString(fun.numCalls) ~ ") )\n"); 
    190210 
    191211    } 
    192212    output.output.write(")\n"); 
    193213    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; 
    194226} 
    195227 
     
    205237    FuncCall[] fan_in; 
    206238    FuncCall[] fan_out; 
    207     uint count; 
    208     uint tree; 
    209     uint func; 
     239    ulong count; 
     240    ulong tree; 
     241    ulong func; 
    210242} 
    211243 
     
    213245{ 
    214246    char[] mangled; 
    215     uint calls; 
     247    ulong calls; 
    216248    // timings: 
    217     uint tree; 
    218     uint func; 
    219     uint call; 
     249    ulong tree; 
     250    ulong func; 
     251    ulong call; 
    220252} 
    221253 
     
    236268 
    237269                if (index > 0) 
    238                     numcalls = toInt(line[0..index]); 
     270                    numcalls = toLong(line[0..index]); 
    239271 
    240272                index = rfindIf(line, isSpace); 
     
    257289        func = Util.trim(func[index..$]); 
    258290        index = findIf(func, isSpace); 
     291 
    259292        if (index > 0) 
    260             nodes[$-1].count = toInt(func[0..index]); 
     293            nodes[$-1].count = toLong(func[0..index]); 
    261294 
    262295        // function time 
     
    264297        index = rfindIf(func, isSpace); 
    265298        if (index > 0) 
    266             nodes[$-1].tree = toInt(func[0..index]); 
     299            nodes[$-1].tree = toLong(func[0..index]); 
    267300 
    268301        // number of calls 
    269         nodes[$-1].func = toInt(Util.trim(func[index..$])); 
     302        nodes[$-1].func = toLong(Util.trim(func[index..$])); 
    270303    } 
    271304 
     
    371404        bool        pastCall = false; 
    372405        uint        count = 0; 
     406 
    373407 
    374408        while(lines.next && !pastGraph) 
     
    440474        catch(Object error) 
    441475        { 
    442             Stdout("demangle error (ignored): ")(error.toUtf8).newline; 
     476            Stdout("demangle error (ignored): ")(error.toString).newline; 
    443477            return mangledName; 
    444478        } 
     
    450484 
    451485 
    452      //TODO: catch appropiate exception to not choke on invalid utf-8 symbols but instead ignore them 
     486     //TODO: catch appropiate exception to not choke on invalid string-8 symbols but instead ignore them 
    453487    char[] getFQN(char[] mangledName) 
    454488    { 
     
    510544    } 
    511545} 
     546 
     547const char[] macros = 
     548` 
     549macros: 
     550TABLE = <table border="4" rules="none" cellpadding="6" cellspacing="6">$0</table> 
     551TDR = <td align="right">$0</td> 
     552TD_CSPAN = <td colspan="$1">$+</td> 
     553 
     554TIMINGS = <h1> Timings (in microseconds) </h1>$(TABLE $0) 
     555TIMING = <tr>$0</tr> 
     556FUNCTION_NAME = <td>$0</td> 
     557CALLS = <td align="right">$0</td> 
     558TREE = <td align="right">$0</td> 
     559FUNC = <td align="right">$0</td> 
     560CALL = <td align="right">$0</td> 
     561 
     562HEADER_FUNCTION_NAME = <th>$0</th> 
     563HEADER_CALLS = <th>$0</th> 
     564HEADER_TREE = <th>$0</th> 
     565HEADER_FUNC = <th>$0</th> 
     566HEADER_CALL = <th>$0</th> 
     567 
     568CALL_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) ) 
     587CALL_SEP = <tr><td>&nbsp;</td></tr> 
     588CALL_FUN = <tr>$0</tr> 
     589CALL_FUN_NAME = $(TD_CSPAN $1, $(B $+)) 
     590CALL_FUN_TREE = <td align="right">$0</td> 
     591CALL_FUN_FUNC = <td align="right">$0</td> 
     592CALL_FUN_CALLS = <td align="right">$0</td> 
     593FAN =  <tr>$0</tr> 
     594FAN_FUNC = <td>$0</td> 
     595FAN_CALLS = <td>$0</td> 
     596 
     597DDOC =  <!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`; 
    512605 
    513606char[] demangle(char[] name) 
     
    811904                            p[i] = b; 
    812905                        } 
    813                     result ~= ConvertFloat.toUtf8(r); 
     906                    result ~= ConvertFloat.toString(r); 
    814907                    ni += 10 * 2; 
    815908                    }