diff options
author | diosmosis <benakamoorthi@fastmail.fm> | 2014-08-20 23:05:32 +0400 |
---|---|---|
committer | diosmosis <benakamoorthi@fastmail.fm> | 2014-08-21 18:49:19 +0400 |
commit | 2a3fa03749e74847a243df4a780f9062e0945d3c (patch) | |
tree | 6be466b9347da91a15989f30d94f3b7915553815 /core | |
parent | 42f5b0273649978540a331786a42937d92fdd8c3 (diff) |
Get xhprof integration to work. Only setup xhprof once per php execution and correctly aggregate xhprof runs (xhprof aggregation will always normalize so we must aggregate ourselves).
Diffstat (limited to 'core')
-rw-r--r-- | core/Profiler.php | 100 |
1 files changed, 78 insertions, 22 deletions
diff --git a/core/Profiler.php b/core/Profiler.php index 04d2443082..2000701bff 100644 --- a/core/Profiler.php +++ b/core/Profiler.php @@ -9,6 +9,7 @@ namespace Piwik; use Exception; +use XHProfRuns_Default; /** * Class Profiler helps with measuring memory, and profiling the database. @@ -24,6 +25,13 @@ use Exception; class Profiler { /** + * Whether xhprof has been setup or not. + * + * @var bool + */ + private static $isXhprofSetup = false; + + /** * Returns memory usage * * @return string @@ -197,11 +205,24 @@ class Profiler return; } + if (self::$isXhprofSetup) { + return; + } + + $xhProfPath = PIWIK_INCLUDE_PATH . '/vendor/facebook/xhprof/extension/modules/xhprof.so'; + if (!file_exists($xhProfPath)) { + throw new Exception("Cannot find xhprof, run 'composer update' and build the extension."); // TODO: automate building w/ composer + } + if (!function_exists('xhprof_enable')) { - throw new Exception("Cannot find xhprof, run 'composer update'."); + throw new Exception("Cannot find xhprof_enable, make sure to add 'extension=$xhProfPath' to your php.ini."); } - if (!is_writable(ini_get("xhprof.output_dir"))) { + $outputDir = ini_get("xhprof.output_dir"); + if (empty($outputDir)) { + throw new Exception("The profiler output dir is not set. Add 'xhprof.output_dir=...' to your php.ini."); + } + if (!is_writable($outputDir)) { throw new Exception("The profiler output dir '" . ini_get("xhprof.output_dir") . "' should exist and be writable."); } @@ -223,40 +244,75 @@ class Profiler self::setProfilingRunIds(array()); } - register_shutdown_function(function () use($profilerNamespace, $mainRun) { + $baseUrlStored = SettingsPiwik::getPiwikUrl(); + + register_shutdown_function(function () use($profilerNamespace, $mainRun, $baseUrlStored) { $xhprofData = xhprof_disable(); - $xhprofRuns = new \XHProfRuns_Default(); + $xhprofRuns = new XHProfRuns_Default(); $runId = $xhprofRuns->save_run($xhprofData, $profilerNamespace); - if(empty($runId)) { + if (empty($runId)) { die('could not write profiler run'); } - $runs = self::getProfilingRunIds(); - $runs[] = $runId; - if($mainRun) { - $runIds = implode(',', $runs); + $runs = Profiler::getProfilingRunIds(); + array_unshift($runs, $runId); + + if ($mainRun) { + self::aggregateXhprofRuns($runs, $profilerNamespace, $saveTo = $runId); + $out = "\n\n"; $baseUrl = "http://" . @$_SERVER['HTTP_HOST'] . "/" . @$_SERVER['REQUEST_URI']; - $baseUrlStored = SettingsPiwik::getPiwikUrl(); - if(strlen($baseUrlStored) > strlen($baseUrl)) { + if (strlen($baseUrlStored) > strlen($baseUrl)) { $baseUrl = $baseUrlStored; } - $baseUrl = "\n" . $baseUrl - ."tests/lib/xhprof-0.9.4/xhprof_html/?source=$profilerNamespace&run="; - - $out .= "Profiler report is available at:"; - $out .= $baseUrl . $runId; - if($runId != $runIds) { - $out .= "\n\nProfiler Report aggregating all runs triggered from this process: "; - $out .= $baseUrl . $runIds; - } + $baseUrl = $baseUrlStored . "vendor/facebook/xhprof/xhprof_html/?source=$profilerNamespace&run=$runId"; + + $out .= "Profiler report is available at:\n"; + $out .= $baseUrl; $out .= "\n\n"; - echo ($out); + + echo $out; } else { - self::setProfilingRunIds($runs); + Profiler::setProfilingRunIds($runs); } }); + + self::$isXhprofSetup = true; + } + + /** + * Aggregates xhprof runs w/o normalizing (xhprof_aggregate_runs will always average data which + * does not fit Piwik's use case). + */ + private static function aggregateXhprofRuns($runIds, $profilerNamespace, $saveToRunId) + { + $xhprofRuns = new XHProfRuns_Default(); + + $aggregatedData = array(); + + foreach ($runIds as $runId) { + $xhprofRunData = $xhprofRuns->get_run($runId, $profilerNamespace, $description); + + foreach ($xhprofRunData as $key => $data) { + if (empty($aggregatedData[$key])) { + $aggregatedData[$key] = $data; + } else { + // don't aggregate main() metrics since only the super run has the correct metrics for the entire run + if ($key == "main()") { + continue; + } + + $aggregatedData[$key]["ct"] += $data["ct"]; + $aggregatedData[$key]["wt"] += $data["wt"]; + $aggregatedData[$key]["cpu"] += $data["cpu"]; + $aggregatedData[$key]["mu"] += $data["mu"]; + $aggregatedData[$key]["pmu"] = max($aggregatedData[$key]["pmu"], $data["pmu"]); + } + } + } + + $xhprofRuns->save_run($aggregatedData, $profilerNamespace, $saveToRunId); } private static function setProfilingRunIds($ids) |