diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-01-30 20:20:24 -0600 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-01-30 20:20:24 -0600 |
commit | cfccedd9c8db3af36d7c5635ca212fa170bb6ff5 (patch) | |
tree | c80df038c9b6e40b4e28c26203de0dd9b1cd1593 /tdecachegrind/converters/pprof2calltree | |
parent | 2020f146a7175288d0aaf15cd91b95e545bbb915 (diff) | |
download | tdesdk-cfccedd9c8db3af36d7c5635ca212fa170bb6ff5.tar.gz tdesdk-cfccedd9c8db3af36d7c5635ca212fa170bb6ff5.zip |
Part 2 of prior commit
Diffstat (limited to 'tdecachegrind/converters/pprof2calltree')
-rw-r--r-- | tdecachegrind/converters/pprof2calltree | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/tdecachegrind/converters/pprof2calltree b/tdecachegrind/converters/pprof2calltree new file mode 100644 index 00000000..0e70e1c2 --- /dev/null +++ b/tdecachegrind/converters/pprof2calltree @@ -0,0 +1,218 @@ +#!/usr/bin/env php +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# - Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - All advertising materials mentioning features or use of this software +# must display the following acknowledgement: This product includes software +# developed by OmniTI Computer Consulting. +# +# - Neither name of the company nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Copyright (c) 2004 OmniTI Computer Consulting +# All rights reserved +# The following code was written by George Schlossnagle <george@omniti.com> +# and is provided completely free and without any warranty. +# +# This script is designed to convert the pprof output from +# APD (http://pecl.php.net/apd/) to one readable by tdecachegrind. To use +# this script: +# +# 1) Install APD. +# 2) Profile your script with APD accordingto the directions in it's +# README file. +# 3) Take the pprof trace file for your script (pprof.XXXXX.Y) and run it +# through this script as follows: +# > pprof2calltree -f pprof.12345.1 +# This creates a new file cachegrind.out.12345.1 +# 4) View your trace with pprof2calltree cachegrind.out.12345.1 + +<?php + +require "Console/Getopt.php"; + +$con = new Console_Getopt; +$args = $con->readPHPArgv(); +array_shift($args); +$shortoptions = 'f:'; +$retval = $con->getopt( $args, $shortoptions); +if(is_object($retval)) { + usage(); +} +foreach ($retval[0] as $kv_array) { + $opt[$kv_array[0]] = $kv_array[1]; +} +if(!$opt['f']) { + usage(); +} +if(!file_exists($opt['f'])) { + print "Trace file ${opt['f']} does not exist\n"; + exit; +} +$IN = fopen($opt['f'], "r"); +if(!$IN) { + print "Trace file ${opt['f']} could not be opened\n"; + exit; +} + +$path_parts = pathinfo($opt['f']); +$outfile = "cachegrind.out.".$path_parts['basename']; +$OUT = fopen($outfile, "w"); +if(!$OUT) { + print "Destination file $outfile could not be opened.\n"; + exit; +} + +while(($line = fgets($IN)) !== false) { + $line = rtrim($line); + if($line == "END_HEADER") { + break; + } +} +$tree = array(); +$callstack = array(); +while(($line = fgets($IN)) !== false) { + $line = rtrim($line); + $args = explode(" ", $line); + if($args[0] == '!') { + $file_lookup[$args[1]] = $args[2]; + } + else if($args[0] == '&') { + $function_lookup[$args[1]] = $args[2]; + $function_type[$args[1]] = ($args[3] == 2)?"USER":"INTERNAL"; + } + else if($args[0] == '+') { + $val = array(function_id => $args[1], + file_id => $args[2], + line => $args[3], + cost => 0); + array_push($callstack, $val); + } + else if($args[0] == '-') { + // retrieve $called to discard + $called = array_pop($callstack); + // retrieve $caller for reference + $caller = array_pop($callstack); + $called_id = $called['function_id']; + + // Set meta data if not already set' + if(!array_key_exists($called_id, $tree)) { + $tree[$called_id] = $called; + // initialize these to 0 + $tree[$called_id]['cost_per_line'] = array(); + } + if($caller !== null) { + $caller['child_calls']++; + $caller_id = $caller['function_id']; + if(!array_key_exists($caller_id, $tree)) { + $tree[$caller_id] = $caller; + } + $caller['cost'] += $called['cost']; + $tree[$caller_id]['called_funcs'][$tree[$caller_id]['call_counter']++][$called_id][$called['file_id']][$called['line']] += $called['cost']; + array_push($callstack, $caller); + } + if(is_array($called['cost_per_line'])) { + foreach($called[cost_per_line] as $file => $lines) { + foreach($lines as $line => $cost) { + $tree[$called_id]['cost_per_line'][$file][$line] += $cost; + } + } + } + } + else if($args[0] == '@') { + $called = array_pop($callstack); + switch(count($args)) { + // support new and old-style pprof data + case 6: + $file = $args[1]; + $line = $args[2]; + $real_tm = $args[5]; + break; + case 4: + $file = $called['file_id']; + $line = $called['line']; + $real_tm = $args[3]; + break; + + } + $called['cost_per_line'][$file][$line] += $real_tm; + $called['cost'] += $real_tm; + $total_cost += $real_tm; + array_push($callstack, $called); + } +} + +ob_start(); +print "events: Tick\n"; +print "summary: $total_cost\n"; +printf("cmd: %s\n", $file_lookup[1]); +print "\n"; + +foreach($tree as $caller => $data) { + $filename = $file_lookup[$data['file_id']]?$file_lookup[$data['file_id']]:"???"; + printf("ob=%s\n", $function_type[$caller]); + printf("fl=%s\n", $filename); + printf("fn=%s\n", $function_lookup[$caller]); + if(is_array($data['cost_per_line'])) { + foreach($data['cost_per_line'] as $file => $lines) { + foreach($lines as $line => $cost) { + print "$line $cost\n"; + } + } + } + else if ($data['cost']) { + printf("COST %s %s\n", $items['line'], $items['cost']); + } + else { + print_r($items); + } + if(is_array($data['called_funcs'])) { + foreach($data['called_funcs'] as $counter => $items) { + foreach($items as $called_id => $costs) { + if(is_array($costs)) { + printf("cfn=%s\n", $function_lookup[$called_id]); + foreach($costs as $file => $lines) { + printf("cfi=%s\ncalls=1\n", $file_lookup[$file]); + foreach($lines as $line => $cost) { + print "$line $cost\n"; + } + } + } + } + } + } + print "\n"; +} +print "\ntotals=$total_cost\n"; +$buffer = ob_get_clean(); +print "Writing tdecachegrind compatible output to $outfile\n"; +fwrite($OUT, $buffer); + +function usage() +{ + print <<<EOD +pprof2calltree -f <tracefile> + +EOD; + exit(1); +} +?> |