Last active
January 17, 2017 18:38
-
-
Save ciiqr/1f9e0c2478cea28c95019a299225ff01 to your computer and use it in GitHub Desktop.
A very quick hack of this following to work with tideways and to be a standalone script that takes the raw output from tideways in json format https://github.com/tlevi/xh2cg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// This is just an example of how you could generate that json file in the first place (this is likely more complicated that you need, but is what I need) | |
if (PROFILE_MEMORY && function_exists('tideways_enable')) { | |
// Start profiler | |
tideways_enable(TIDEWAYS_FLAGS_MEMORY); | |
// Stop profiler on shutdown | |
register_shutdown_function(function() { | |
// Ensure we have enough memory to save the data | |
$shutdownextra = 32 * 1024 * 1024; | |
@ini_set('memory_limit', memory_get_usage() + $shutdownextra); | |
// Stop the profiler | |
$tideways = tideways_disable(); | |
// PHP_SELF is relative to the directory root, but we also want to have the parent directories name in the profile-memory path | |
$dir = basename(realpath(dirname($_SERVER['PHP_SELF']))); | |
// Re-create the directory structure of the document root in the profile-memory directory (so we know which file we're dealing with) | |
$profileMemoryOutPath = '/tmp/profile-memory/'.$dir.'/'.ltrim($_SERVER['PHP_SELF'], '/').'-'.gmdate('Y-m-d_H-i-s_T').'.out'; | |
// Out directory | |
$profileMemoryOutDir = dirname($profileMemoryOutPath); | |
// Make sure the directory exists | |
if (!file_exists($profileMemoryOutDir)) | |
mkdir($profileMemoryOutDir, 0777, true); | |
// Save to the output file | |
file_put_contents($profileMemoryOutPath, json_encode($tideways, JSON_PRETTY_PRINT)); | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
xh2cg::main($argv, $argc); | |
class xh2cg { | |
const COMPRESSION = false; | |
public static function main($args, $argc) | |
{ | |
if ($argc != 3) { | |
echo 'usage: ', __FILE__, ' inFile outFile', PHP_EOL; | |
exit(1); | |
} | |
$inFile = $args[1]; | |
$outFile = $args[2]; | |
if (!file_exists($inFile)) { | |
echo 'WHY!!! THAT FILE DOES NOT EXIST', PHP_EOL; | |
exit(1); | |
} | |
self::process($inFile, $outFile); | |
} | |
protected static function convert($outFile, stdClass $tideways, $map = null) { | |
if (!$fh = fopen($outFile, 'w')) { | |
throw new Exception('Failed to open output file!'); | |
} | |
$types = array('wt'=>'WallTime', 'cpu'=>'CPU', 'mu'=>'Memory', 'pmu'=>'Peak_memory'); | |
$totals = array(); | |
$funcs = array(); | |
foreach ($tideways as $edge => $data) { | |
list($fn, $cfn) = strpos($edge, '==>') !== false ? explode('==>', $edge, 2) : array($edge, null); | |
if (!isset($funcs[$fn])) { | |
$funcs[$fn] = new stdClass; | |
$funcs[$fn]->children = array(); | |
} | |
if (!isset($cfn)) { | |
$funcs[$fn]->data = clone $data; | |
continue; | |
} | |
$funcs[$fn]->children[$cfn] = clone $data; | |
if (!isset($funcs[$cfn]->data)) { | |
if (!isset($funcs[$cfn])) { | |
$funcs[$cfn] = new stdClass; | |
$funcs[$cfn]->children = array(); | |
} | |
$funcs[$cfn]->data = clone $data; | |
continue; | |
} | |
foreach ($data as $k => $v) { | |
$funcs[$cfn]->data->$k += $v; | |
} | |
} | |
foreach ($types as $k => $unused) { | |
if (!isset($funcs['main()']->data->$k)) { | |
unset($types[$k]); | |
continue; | |
} | |
$totals[$k] = $funcs['main()']->data->$k; | |
} | |
// Calculate exclusive costs for each function. | |
$reduce = array_keys($types); | |
foreach ($funcs as $fn => $f) { | |
foreach ($f->children as $cfn => $d) { | |
foreach ($reduce as $k) { | |
$f->data->$k -= $d->$k; | |
} | |
} | |
} | |
fwrite($fh, "version: 1\n"); | |
fwrite($fh, "creator: xh2cg for tideways\n"); | |
fwrite($fh, "cmd: Unknown PHP script\n"); | |
fwrite($fh, "part: 1\n"); | |
fwrite($fh, "positions: line\n"); | |
fwrite($fh, "events: ".implode(" ", array_values($types))." \n"); | |
fwrite($fh, "summary: ".implode(" ", $totals)."\n"); | |
fwrite($fh, "\n\n"); | |
function comp($t, $v) { | |
static $seen = array(); | |
if (!defined('COMPRESSION') || !COMPRESSION) { | |
return $v; | |
} | |
if (!isset($seen[$t])) { | |
$seen[$t] = array(); | |
} | |
if (!isset($seen[$t][$v])) { | |
$seen[$t][$v] = !empty($seen[$t]) ? reset($seen[$t]) + 1 : 1; | |
return "({$seen[$t][$v]}) $v"; | |
} | |
return "({$seen[$t][$v]})"; | |
} | |
function map($map, $f) { | |
$f = preg_replace('#@\d+$#', '', $f); | |
$v = array('file' => '<unknown>', 'line' => 0); | |
if (!empty($map[$f])) { | |
$v = array_merge($v, $map[$f]); | |
} | |
return array_values($v); | |
} | |
function cline($d) { | |
$cline = ''; | |
foreach ($d as $k => $v) { | |
$cline .= $k !== 'ct' ? " {$v}" : ''; | |
} | |
return $cline; | |
} | |
foreach ($funcs as $fn => $f) { | |
list($fl, $fline) = map($map, $fn); | |
if (!empty($fl)) { | |
fwrite($fh, "fl=".comp('fl', $fl)."\n"); // file name | |
} | |
fwrite($fh, "fn=".comp('fn', $fn)."\n"); // function name | |
fwrite($fh, "$fline ".cline($f->data)."\n"); // exclusive time | |
foreach ($f->children as $cfn => $d) { | |
list($cfl, $cfline) = map($map, $cfn); | |
if ($cfl != $fl && !empty($cfl)) { | |
fwrite($fh, "cfl=".comp('cfl', $cfl)."\n"); // child function file name | |
} | |
fwrite($fh, "cfn=".comp('cfn', $cfn)."\n"); // child function name | |
fwrite($fh, "calls={$d->ct} $cfline\n"); // called N times | |
fwrite($fh, "$fline ".cline($d)."\n"); // lineno and cost | |
} | |
fwrite($fh, "\n"); | |
} | |
fwrite($fh, "totals: ".cline($totals)."\n"); | |
} | |
protected static function process($inFile, $outFile) { | |
$main = 'script.php'; // NOTE: This is arbitrary... look at the original file name/path for the script name/path | |
$tideways = json_decode(file_get_contents($inFile)); | |
$funcs = array(); | |
foreach ($tideways as $edge => $unused) { | |
list($fn, $cfn) = strpos($edge, '==>') !== false ? explode('==>', $edge, 2) : array($edge, false); | |
$funcs[$fn] = null; | |
$funcs[$cfn] = null; | |
} | |
foreach ($funcs as $fn => $unused) { | |
if (preg_match('#@\d+$#', $fn)) { | |
unset($funcs[$fn]); | |
continue; | |
} | |
try { | |
if (strpos($fn, '::') !== false) { | |
list($c, $f) = explode('::', $fn, 2); | |
$o = new ReflectionMethod($c, $f); | |
} else { | |
$o = new ReflectionFunction($fn); | |
} | |
} catch (ReflectionException $e) { | |
unset($funcs[$fn]); | |
continue; | |
} | |
$file = $o->getFileName(); | |
$line = $o->getStartLine(); | |
if (!empty($CFG->dirroot)) { | |
$file = str_replace($CFG->dirroot, '', $file); | |
} | |
if (!empty($file) && !empty($line)) { | |
$funcs[$fn] = array('line' => $line, 'file' => $file); | |
} | |
} | |
$funcs['main()'] = array('line' => 0, 'file' => $main); | |
$funcs = array_filter($funcs); | |
self::convert($outFile, json_decode(json_encode($tideways), false), $funcs); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment