Elgg  Version 2.2
 All Classes Namespaces Files Functions Variables Pages
Profiler.php
Go to the documentation of this file.
1 <?php
2 namespace Elgg;
3 
9 class Profiler {
10 
11  public $percentage_format = "%01.2f";
12  public $duration_format = "%01.6f";
13  public $minimum_percentage = 0.2;
14 
18  private $total;
19 
26  public function buildTree(Timer $timer) {
27  $times = $timer->getTimes();
28 
29  if (!isset($times[':end'])) {
30  $times[':end'] = microtime();
31  }
32 
33  $begin = $this->findBeginTime($times);
34  $end = $this->findEndTime($times);
35  $this->total = $this->diffMicrotime($begin, $end);
36 
37  return $this->analyzePeriod('', $times);
38  }
39 
48  public function flattenTree(array &$list = [], array $tree, $prefix = '') {
49  $is_root = empty($list);
50 
51  if (isset($tree['periods'])) {
52  foreach ($tree['periods'] as $period) {
53  $this->flattenTree($list, $period, "{$prefix} {$period['name']}");
54  }
55  unset($tree['periods']);
56  }
57  $tree['name'] = trim($prefix);
58  $list[] = $tree;
59 
60  if ($is_root) {
61  usort($list, function ($a, $b) {
62  if ($a['duration'] == $b['duration']) {
63  return 0;
64  }
65  return ($a['duration'] > $b['duration']) ? -1 : 1;
66  });
67  }
68  }
69 
76  public function formatTree(array $tree) {
77  $tree['duration'] = sprintf($this->duration_format, $tree['duration']);
78  if (isset($tree['percentage'])) {
79  $tree['percentage'] = sprintf($this->percentage_format, $tree['percentage']);
80  }
81  if (isset($tree['periods'])) {
82  $tree['periods'] = array_map([$this, 'formatTree'], $tree['periods']);
83  }
84  return $tree;
85  }
86 
97  public static function handlePageOutput($hook, $type, $html, $params) {
98  $profiler = new self();
99  $min_percentage = elgg_get_config('profiling_minimum_percentage');
100  if ($min_percentage !== null) {
101  $profiler->minimum_percentage = $min_percentage;
102  }
103 
104  $tree = $profiler->buildTree(_elgg_services()->timer);
105  $tree = $profiler->formatTree($tree);
106  $data['tree'] = $tree;
107  $data['total'] = $tree['duration'] . " seconds";
108 
109  $list = [];
110  $profiler->flattenTree($list, $tree);
111 
112  $root = elgg_get_config('path');
113  $list = array_map(function ($period) use ($root) {
114  $period['name'] = str_replace("Closure $root", "Closure ", $period['name']);
115  return "{$period['percentage']}% ({$period['duration']}) {$period['name']}";
116  }, $list);
117 
118  $data['list'] = $list;
119 
120  $html .= "<script>console.log(" . json_encode($data) . ");</script>";
121 
122  return $html;
123  }
124 
133  private function analyzePeriod($name, array $times) {
134  $begin = $this->findBeginTime($times);
135  $end = $this->findEndTime($times);
136  if ($begin === false || $end === false) {
137  return false;
138  }
139  unset($times[':begin'], $times[':end']);
140 
141  $total = $this->diffMicrotime($begin, $end);
142  $ret = [
143  'name' => $name,
144  'percentage' => 100, // may be overwritten by parent
145  'duration' => $total,
146  ];
147 
148  foreach ($times as $times_key => $period) {
149  $period = $this->analyzePeriod($times_key, $period);
150  if ($period === false) {
151  continue;
152  }
153  $period['percentage'] = 100 * $period['duration'] / $this->total;
154  if ($period['percentage'] < $this->minimum_percentage) {
155  continue;
156  }
157  $ret['periods'][] = $period;
158  }
159 
160  if (isset($ret['periods'])) {
161  usort($ret['periods'], function ($a, $b) {
162  if ($a['duration'] == $b['duration']) {
163  return 0;
164  }
165  return ($a['duration'] > $b['duration']) ? -1 : 1;
166  });
167  }
168 
169  return $ret;
170  }
171 
178  private function findBeginTime(array $times) {
179  if (isset($times[':begin'])) {
180  return $times[':begin'];
181  }
182  unset($times[':begin'], $times[':end']);
183  $first = reset($times);
184  if (is_array($first)) {
185  return $this->findBeginTime($first);
186  }
187  return false;
188  }
189 
196  private function findEndTime(array $times) {
197  if (isset($times[':end'])) {
198  return $times[':end'];
199  }
200  unset($times[':begin'], $times[':end']);
201  $last = end($times);
202  if (is_array($last)) {
203  return $this->findEndTime($last);
204  }
205  return false;
206  }
207 
216  private function diffMicrotime($start, $end) {
217  list($start_usec, $start_sec) = explode(" ", $start);
218  list($end_usec, $end_sec) = explode(" ", $end);
219  $diff_sec = (int)$end_sec - (int)$start_sec;
220  $diff_usec = (float)$end_usec - (float)$start_usec;
221  return (float)$diff_sec + $diff_usec;
222  }
223 }
elgg_get_config($name, $site_guid=0)
Get an Elgg configuration value.
static handlePageOutput($hook, $type, $html, $params)
Append a SCRIPT element to the page output.
Definition: Profiler.php:97
getTimes()
Get the tree of recorded start/end times.
Definition: Timer.php:51
if($guid==elgg_get_logged_in_user_guid()) $name
Definition: delete.php:21
$data
Definition: opendd.php:13
Analyzes duration of functions, queries, and processes.
Definition: Profiler.php:9
Capture timing info for profiling.
Definition: Timer.php:9
$params
Definition: login.php:72
foreach($emails as $email) $html
Definition: exceptions.php:34
buildTree(Timer $timer)
Return a tree of time periods from a Timer.
Definition: Profiler.php:26
flattenTree(array &$list=[], array $tree, $prefix= '')
Turn the tree of times into a sorted list.
Definition: Profiler.php:48
formatTree(array $tree)
Nicely format the elapsed time values.
Definition: Profiler.php:76
_elgg_services(\Elgg\Di\ServiceProvider $services=null)
Get the global service provider.
Definition: autoloader.php:17
if(!$display_name) $type
Definition: delete.php:27