Skip to content

Instantly share code, notes, and snippets.

@ciiqr
Last active January 17, 2017 18:38
Show Gist options
  • Save ciiqr/1f9e0c2478cea28c95019a299225ff01 to your computer and use it in GitHub Desktop.
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
<?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));
});
}
<?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