Warning, /sdk/kcachegrind/converters/pprof2calltree is written in an unsupported language. File is not indexed.

0001 #!/usr/bin/env php
0002 # Redistribution and use in source and binary forms, with or without
0003 # modification, are permitted provided that the following conditions are met:
0004 #
0005 # - Redistributions of source code must retain the above copyright notice,
0006 # this list of conditions and the following disclaimer.
0007 #
0008 # - Redistributions in binary form must reproduce the above copyright
0009 # notice, this list of conditions and the following disclaimer in the
0010 # documentation and/or other materials provided with the distribution.
0011 #
0012 # - All advertising materials mentioning features or use of this software
0013 # must display the following acknowledgement: This product includes software
0014 # developed by OmniTI Computer Consulting.
0015 #
0016 # - Neither name of the company nor the names of its contributors may be
0017 # used to endorse or promote products derived from this software without
0018 # specific prior written permission.
0019 #
0020 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `AS IS'' AND ANY
0021 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0022 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0023 # DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
0024 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0025 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0026 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0027 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0028 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0029 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0030 #
0031 # Copyright (c) 2004 OmniTI Computer Consulting
0032 # All rights reserved
0033 # The following code was written by George Schlossnagle <george@omniti.com>
0034 # and is provided completely free and without any warranty.
0035 #
0036 # This script is designed to convert the pprof output from 
0037 # APD (https://pecl.php.net/apd/) to one readable by kcachegrind. To use
0038 # this script:
0039 #
0040 # 1) Install APD.
0041 # 2) Profile your script with APD accordingto the directions in it's
0042 #    README file.
0043 # 3) Take the pprof trace file for your script (pprof.XXXXX.Y) and run it 
0044 #    through this script as follows:
0045 #    > pprof2calltree -f pprof.12345.1 
0046 #    This creates a new file cachegrind.out.12345.1
0047 # 4) View your trace with pprof2calltree cachegrind.out.12345.1
0048 
0049 <?php
0050 
0051 require "Console/Getopt.php";
0052 
0053 $con = new Console_Getopt;
0054 $args = $con->readPHPArgv();
0055 array_shift($args);
0056 $shortoptions = 'f:';
0057 $retval = $con->getopt( $args, $shortoptions);
0058 if(is_object($retval)) {
0059         usage();
0060 }
0061 foreach ($retval[0] as $kv_array) {
0062     $opt[$kv_array[0]] = $kv_array[1];
0063 }
0064 if(!$opt['f']) {
0065         usage();
0066 }
0067 if(!file_exists($opt['f'])) {
0068         print "Trace file ${opt['f']} does not exist\n";
0069         exit;
0070 }
0071 $IN = fopen($opt['f'], "r");
0072 if(!$IN) {
0073         print "Trace file ${opt['f']} could not be opened\n";
0074         exit;
0075 }
0076 
0077 $path_parts = pathinfo($opt['f']);
0078 $outfile = "cachegrind.out.".$path_parts['basename'];
0079 $OUT = fopen($outfile, "w");
0080 if(!$OUT) {
0081         print "Destination file $outfile could not be opened.\n";
0082         exit;
0083 }
0084 
0085 while(($line = fgets($IN)) !== false) {
0086         $line = rtrim($line);
0087         if($line == "END_HEADER") {
0088                 break;
0089         }
0090 }
0091 $tree = array();
0092 $callstack = array();
0093 while(($line = fgets($IN)) !== false) {
0094         $line = rtrim($line);
0095         $args = explode(" ", $line);
0096         if($args[0] == '!') {
0097                 $file_lookup[$args[1]] = $args[2];
0098         }
0099         else if($args[0] == '&') {
0100                 $function_lookup[$args[1]] = $args[2];
0101                 $function_type[$args[1]] = ($args[3] == 2)?"USER":"INTERNAL";
0102         }
0103         else if($args[0] == '+') {
0104                 $val = array(function_id => $args[1], 
0105                              file_id => $args[2],
0106                                          line => $args[3], 
0107                                          cost => 0);
0108                 array_push($callstack, $val);
0109         }
0110         else if($args[0] == '-') {
0111                 // retrieve $called to discard
0112                 $called = array_pop($callstack);
0113                 // retrieve $caller for reference
0114                 $caller = array_pop($callstack);
0115                 $called_id = $called['function_id'];
0116                 
0117                 // Set meta data if not already set'
0118                 if(!array_key_exists($called_id, $tree)) {
0119                         $tree[$called_id] = $called;
0120                         // initialize these to 0
0121                         $tree[$called_id]['cost_per_line'] = array();
0122                 }
0123                 if($caller !== null) {
0124                         $caller['child_calls']++;
0125                         $caller_id = $caller['function_id'];
0126                         if(!array_key_exists($caller_id, $tree)) {
0127                                 $tree[$caller_id] = $caller;
0128                         }
0129                         $caller['cost'] += $called['cost'];
0130                         $tree[$caller_id]['called_funcs'][$tree[$caller_id]['call_counter']++][$called_id][$called['file_id']][$called['line']] += $called['cost'];
0131                         array_push($callstack, $caller);
0132                 }
0133                 if(is_array($called['cost_per_line'])) {
0134                         foreach($called[cost_per_line] as $file => $lines) {
0135                                 foreach($lines as $line => $cost) {
0136                                         $tree[$called_id]['cost_per_line'][$file][$line] += $cost;
0137                                 }
0138                         }
0139                 }
0140         }
0141         else if($args[0] == '@') {
0142                 $called = array_pop($callstack);
0143                 switch(count($args)) {
0144                         // support new and old-style pprof data
0145                         case 6:
0146                                 $file = $args[1];
0147                                 $line = $args[2];
0148                                 $real_tm = $args[5];
0149                                 break;
0150                         case 4:
0151                                 $file = $called['file_id'];
0152                                 $line = $called['line'];
0153                                 $real_tm = $args[3];
0154                                 break;
0155                                 
0156                 }
0157                 $called['cost_per_line'][$file][$line] += $real_tm;
0158                 $called['cost'] += $real_tm;
0159                 $total_cost += $real_tm;
0160                 array_push($callstack, $called);
0161         }
0162 }
0163 
0164 ob_start();
0165 print "events: Tick\n";
0166 print "summary: $total_cost\n";
0167 printf("cmd: %s\n", $file_lookup[1]);
0168 print "\n";
0169 
0170 foreach($tree as $caller => $data) {
0171         $filename = $file_lookup[$data['file_id']]?$file_lookup[$data['file_id']]:"???";
0172         printf("ob=%s\n", $function_type[$caller]);
0173         printf("fl=%s\n", $filename);
0174         printf("fn=%s\n", $function_lookup[$caller]);
0175         if(is_array($data['cost_per_line'])) {
0176                 foreach($data['cost_per_line'] as $file => $lines) {
0177                         foreach($lines as $line => $cost) {
0178                                 print "$line $cost\n";
0179                         }
0180                 }
0181         }
0182         else if ($data['cost']) {
0183                 printf("COST %s %s\n", $items['line'], $items['cost']);
0184         }
0185         else {
0186                 print_r($items);
0187         }
0188         if(is_array($data['called_funcs'])) {
0189                 foreach($data['called_funcs'] as $counter => $items) {
0190                         foreach($items as $called_id => $costs) {
0191                                 if(is_array($costs)) {
0192                                         printf("cfn=%s\n", $function_lookup[$called_id]);
0193                                         foreach($costs as $file => $lines) {
0194                                                 printf("cfi=%s\ncalls=1\n", $file_lookup[$file]);
0195                                                 foreach($lines as $line => $cost) {
0196                                                         print "$line $cost\n";
0197                                                 }
0198                                         }
0199                                 }
0200                         }
0201                 }
0202         }
0203         print "\n";
0204 }
0205 print "\ntotals=$total_cost\n";
0206 $buffer = ob_get_clean();
0207 print "Writing kcachegrind compatible output to $outfile\n";
0208 fwrite($OUT, $buffer);
0209 
0210 function usage()
0211 {
0212         print <<<EOD
0213 pprof2calltree -f <tracefile>
0214 
0215 EOD;
0216         exit(1);
0217 }
0218 ?>