Skip to content

Instantly share code, notes, and snippets.

@hpbuniat
Created May 11, 2012 15:35
Show Gist options
  • Save hpbuniat/2660487 to your computer and use it in GitHub Desktop.
Save hpbuniat/2660487 to your computer and use it in GitHub Desktop.
Find memory intensive functions in a bunch of xhprof-results (e.g. phpunit run with xhprof-listener)
<?php
class xhparser {
/**
* Content
*
* @var string
*/
private $_aFiles = array();
/**
* Functions to filter
*
* @var array
*/
private $_aFilter = array(
'main()',
'PHPUnit_Framework_TestCase',
'PHPUnit_Framework_MockObject'
);
/**
* The result
*
* @var array
*/
private $_aResult = array();
/**
* Order by
*
* @var string
*/
private $_sOrder = 'mu';
/**
* Load a file
*
* @param string $sFile
*
* @return xhparser
*/
public function load($sFile) {
if (file_exists($sFile) === true) {
$this->_aFiles[] = unserialize(file_get_contents($sFile));
}
return $this;
}
/**
* Run
*
* @return array
*/
public function run() {
$aResult = array();
foreach ($this->_aFiles as $aTrace) {
foreach ($aTrace as $sFunction => $aData) {
$bAdd = true;
foreach ($this->_aFilter as $sFilter) {
if (strpos($sFunction, $sFilter) !== false) {
$bAdd = false;
break;
}
}
if ($bAdd === true) {
if (isset($aResult[$sFunction]) === false) {
$aResult[$sFunction] = array();
}
$this->_merge($aResult[$sFunction], $aData);
}
}
}
$this->_order($aResult);
$this->_aResult = $aResult;
return $this;
}
/**
* Limit the result
*
* @param int $iLimit
*
* @return xhparser
*/
public function limit($iLimit = 0) {
$iLimit = (int) $iLimit;
if ($iLimit > 0) {
$this->_aResult = array_slice($this->_aResult, 0, $iLimit);
}
return $this;
}
/**
* Return the result-string
*
* @return string
*/
public function get() {
$sResult = '';
foreach ($this->_aResult as $sFunction => $aResult) {
$sResult .= PHP_EOL . sprintf('Result: %s', $sFunction) . PHP_EOL . "Num\tCalls\t(avg)\t";
$sResult .= str_pad("Wall", 10, " ");
$sResult .= str_pad("(avg)", 10, " ");
$sResult .= str_pad("CPU", 10, " ");
$sResult .= str_pad("(avg)", 10, " ");
$sResult .= str_pad("MEM", 10, " ");
$sResult .= str_pad("(avg)", 10, " ");
$sResult .= PHP_EOL;
$sResult .= ($aResult['count'] . "\t");
$sResult .= ($aResult['ct'] . "\t");
$sResult .= (ceil($aResult['ct_avg']) . "\t");
$sResult .= str_pad($aResult['wt'], 10, " ");
$sResult .= str_pad(ceil($aResult['wt_avg']), 10, " ");
$sResult .= str_pad($aResult['cpu'], 10, " ");
$sResult .= str_pad(ceil($aResult['cpu_avg']), 10, " ");
$sResult .= str_pad(round($aResult['mu'] / 1024, 2), 10, " ");
$sResult .= str_pad(round($aResult['mu_avg'] / 1024, 2), 10, " ");
$sResult .= (PHP_EOL);
}
return $sResult;
}
/**
* Merge data of a function
*
* @param array $aBase
* @param array $aData
*
* @return xhparser
*/
protected function _merge(array &$aBase, array $aData) {
$aData['count'] = 1;
if (empty($aBase) === true) {
$aBase = $aData;
}
else {
foreach ($aData as $sKey => $mValue) {
$aBase[$sKey] += $mValue;
}
}
foreach ($aData as $sKey => $mValue) {
$aBase[$sKey . '_avg'] = ($aBase[$sKey] / $aBase['count']);
}
return $this;
}
/**
* Order the traces of a file
*
* @param array $aTrace
*
* @return xhparser
*/
protected function _order(&$aTrace) {
foreach ($aTrace as $sKey => $aRow) {
$aMemory[$sKey] = $aRow[$this->_sOrder];
}
array_multisort($aMemory, SORT_DESC, $aTrace);
return $this;
}
/**
* Set order by
*
* @param string $sOrder
*
* @return xhparser
*/
public function order($sOrder) {
$this->_sOrder = $sOrder;
return $this;
}
/**
* Add a filter
*
* @param string $sFilter
*
* @return xhparser
*/
public function filter($sFilter) {
$this->_aFilter[] = trim($sFilter);
return $this;
}
}
$o = new xhparser();
$aArgs = getopt('f:d:l:o:');
if (isset($aArgs['d']) !== true) {
$aArgs['d'] = ini_get('xhprof.output_dir');
}
if (isset($aArgs['o']) === true) {
$o->order($aArgs['o']);
}
if (empty($aArgs['f']) !== true) {
$aFilter = explode(',', $aArgs['f']);
foreach ($aFilter as $sFilter) {
$o->filter($sFilter);
}
}
$oIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(realpath($aArgs['d'])));
$aFiles = array();
foreach ($oIterator as $sName => $oFile) {
$aFiles[] = $oFile->getPath() . DIRECTORY_SEPARATOR . $oFile->getFilename();
}
foreach ($aFiles as $sFile) {
$o->load($sFile);
}
$o->run();
if (empty($aArgs['l']) !== true) {
$o->limit($aArgs['l']);
}
print_r($o->get());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment