/
class.profiler.php
207 lines (186 loc) · 6.09 KB
/
class.profiler.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
<?php
/**
* @package toolkit
*/
/**
* The Profiler class tracks various performance metrics while a Symphony
* page is being generated. It provides a basic stopwatch functionality and
* memory usage statistics. Profiling occurs in both the Frontend and
* Administration execution. The Profiler implements the Singleton interface.
*/
class Profiler implements Singleton
{
/**
* Holds the timestamp from when the profiler was first initialised
* @var integer
*/
protected static $_starttime = 0;
/**
* An array of arrays containing profiling samples. A record contains a
* profile message, the time since `$_starttime` timestamp, the end timestamp,
* the group for this record, the number of SQL queries and the result of
* memory_get_usage()
* @var array
*/
protected static $_samples = array();
/**
* A seed holds a start time to be used in profiling. If this is not null
* the profiler will use this as the start time instead of `$_starttime`. This
* is set with the seed function.
* @var integer
* @see seed()
*/
protected static $_seed = null;
/**
* An instance of the Profiler class
* @var Profiler
*/
protected static $_instance = null;
/**
* Returns the Profiler instance, creating one if it does not exist
*
* @return Profiler
*/
public static function instance()
{
if (!(Profiler::$_instance instanceof Profiler)) {
Profiler::$_instance = new self;
}
return Profiler::$_instance;
}
/**
* The constructor for the profile function sets the start time
*/
protected function __construct()
{
Profiler::$_starttime = precision_timer();
}
/**
* Sets the seed to be a timestamp so that time profiling will use this
* as a starting point
*
* @param integer $time
* The time in seconds
*/
public static function seed($time = null)
{
Profiler::$_seed = (is_null($time)) ? precision_timer() : $time;
}
/**
* This function creates a new report in the `$_samples` array where the message
* is the name of this report. By default, all samples are compared to the `$_starttime`
* but if the `PROFILE_LAP` constant is passed, it will be compared to specific `$_seed`
* timestamp. Samples can grouped by type (ie. Datasources, Events), but by default
* are grouped by 'General'. Optionally, the number of SQL queries that have occurred
* since either `$_starttime` or `$_seed` can be passed. Memory usage is taken with each
* sample which measures the amount of memory used by this script by PHP at the
* time of sampling.
*
* @param string $msg
* A description for this sample
* @param integer $type
* Either `PROFILE_RUNNING_TOTAL` or `PROFILE_LAP`
* @param string $group
* Allows samples to be grouped together, defaults to General.
* @param integer $queries
* The number of MySQL queries that occurred since the `$_starttime` or `$_seed`
*/
public function sample($msg, $type = PROFILE_RUNNING_TOTAL, $group = 'General', $queries = null)
{
if ($type == PROFILE_RUNNING_TOTAL) {
Profiler::$_samples[] = array($msg, precision_timer('stop', Profiler::$_starttime), precision_timer(), $group, $queries, memory_get_usage());
} else {
if (!is_null(Profiler::$_seed)) {
$start = Profiler::$_seed;
Profiler::$_seed = null;
} else {
$start = null;
}
$prev = Profiler::retrieveLast();
Profiler::$_samples[] = array($msg, precision_timer('stop', ($start ? $start : $prev[2])), precision_timer(), $group, $queries, memory_get_usage());
}
}
/**
* Given an index, return the sample at that position otherwise just
* return all samples.
*
* @param integer $index
* The array index to return the sample for
* @return array
* If no `$index` is passed an array of all the sample arrays are returned
* otherwise just the sample at the given `$index` will be returned.
*/
public function retrieve($index = null)
{
return !is_null($index) ? Profiler::$_samples[$index] : Profiler::$_samples;
}
/**
* Returns a sample by message, if no sample is found, an empty
* array is returned
*
* @param string $msg
* The name of the sample to return
* @return array
*/
public function retrieveByMessage($msg)
{
foreach (Profiler::$_samples as $record) {
if ($record[0] == $msg) {
return $record;
}
}
return array();
}
/**
* Returns all the samples that belong to a particular group.
*
* @param string $group
* @return array
*/
public function retrieveGroup($group)
{
$result = array();
foreach (Profiler::$_samples as $record) {
if ($record[3] == $group) {
$result[] = $record;
}
}
return $result;
}
/**
* Returns the last record from the `$_records` array
*
* @return array
*/
public static function retrieveLast()
{
return end(Profiler::$_samples);
}
/**
* Returns the difference between when the Profiler was initialised
* (aka `$_starttime`) and the last record the Profiler has.
*
* @return integer
*/
public function retrieveTotalRunningTime()
{
return precision_timer('stop', Profiler::$_starttime);
}
/**
* Returns the total memory usage from all samples taken by comparing
* each sample to the base memory sample.
*
* @return integer
* Memory usage in bytes.
*/
public function retrieveTotalMemoryUsage()
{
$base = $this->retrieve(0);
$total = $last = 0;
foreach ($this->retrieve() as $item) {
$total += max(0, (($item[5]-$base[5]) - $last));
$last = $item[5]-$base[5];
}
return $total;
}
}