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 ?>