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