Simple profiler
Posted: Fri Apr 30, 2010 7:16 am
Just wrote a little script for fun to profile the performance of multiple events within a single script. It's pretty cool me thinks and extremely simple.
The Script:
The Test:
The results as an array:
The results as an html table:

This is the kind of stuff that is fun to write! I found it interesting to note that sleep(3) took 2.993 seconds. If anything, my profiling script would add some milliseconds of time to that.. so hmm.
The Script:
Code: Select all
<?php
/**
* Simple profiler class for checking speed performance of multiple events
* in a single script or checking for possible bottlenecks.
*
* It can output results as an array or as an html table for visual processing
*
* @author Scott Martin <sjmdot[at]gmail[dot]com>
* @version 1.0.0
* @version-history
* 1.0.0 - Initial release
* @date April 30th, 2010
*/
class profiler
{
//holds events
private $events = array();
//holds number of events to stop repetitive calls to count()
private $events_num = 0;
//the number of decimal places to round to
private $round_to = 3;
/**
* Starts the timing of an event
*
* @access public
* [@param string $event] - the name of the event being timed,
* defaults to empty string
* @return null
*/
public function start_event($event='')
{
//stop previous event if it hasn't been stopped
$this->stop_event();
//add to events array
$this->events[] = array(
'name' => (empty($event) === true) ? 'Un-named Event' : $event,
'start' => microtime(true)
);
//increase event count
$this->events_num += 1;
}
/**
* Stops the currently running event, or, if called after another event is
* is added, stops the previous event. Not required to call, but improves
* code readability
*
* @access public
* @param void
* @return null;
*/
public function stop_event()
{
if ($this->events_num)
{
$event_index = $this->events_num - 1;
if (!isset($this->events[$event_index]['end']))
{
$this->events[$event_index]['end'] = microtime(true);
}
}
}
/**
* Gathers the results of the events by calculating the duration of
* each event and then adding a totals section. Can be returned as
* an array or as an html table if $html_table is set to true
*
* @access public
* [@param boolean $html_table] - whether or not to return the result
* as an html table. defaults to false
* @return mixed - array or string depending on $html_table param
*/
public function profile($html_table = false)
{
//stop previous event if it hasn't been stopped
$this->stop_event();
//return array
$ret = array();
//loop and calculate
foreach ($this->events AS $event)
{
$event['duration'] = round($event['end'] - $event['start'], $this->round_to);
$ret[] = $event;
}
//totals
$ret[] = !empty($ret) ?
array(
'name' => 'Profiler Totals (' . $this->events_num . ' Events)',
'start' => $ret[0]['start'],
'end' => $ret[$this->events_num-1]['end'],
'duration' => round($ret[$this->events_num-1]['end'] - $ret[0]['start'], $this->round_to)
) :
array(
'name' => 'Profiler Totals',
'start' => null,
'end' => null,
'duration' => null
);
return $html_table ? $this->generate_html_table($ret) : $ret;
}
/**
* Generates and returns an HTML table from the results
*
* @access private
* @param $results
* @return string
*/
private function generate_html_table($results)
{
$totals = array_pop($results);
$ret = '<table cellspacing="0" cellpadding="2" border="1">
<tr>
<td bgcolor="#FFFFFF"><strong>Event</strong></td>
<td bgcolor="#FFFFFF"><strong>Duration</strong></td>
</tr>';
foreach ($results AS $k => $v)
{
$ret .= '<tr>
<td bgcolor="#FFFFFF">' . $v['name'] . '</td>
<td bgcolor="#FFFFFF">' . $v['duration'] . 's</td>
</tr>';
}
$ret .= '<tr>
<td bgcolor="#E6E6E6"><strong>' . $totals['name'] . '</strong></td>
<td bgcolor="#E6E6E6">' . $totals['duration'] . 's</td>
</tr>
</table>';
return $ret;
}
/**
* Sets the number of decimal places to round to for duration
*
* @access public
* @param integer $roundto
* @return null
*/
public function set_round_to($roundto)
{
$this->round_to = (int) $roundto;
}
}Code: Select all
$profiler = new profiler();
//do something so we can profile
//time getting remote contents
$profiler->start_event('Grabbing google content');
file_get_contents('http://www.google.com');
$profiler->stop_event();
//do something again so we can profile
//time looping a dumb math equation
$profiler->start_event('Looping a dumb math equation');
for ($i=0; $i<1000; $i++)
{
sqrt(mt_rand(1, 99999)) * rand(1, 2);
}
$profiler->stop_event();
//do something again
//like sleep?
$profiler->start_event('Sleeping a little bit');
sleep(3);
$profiler->stop_event();
$profiler->start_event('Adding hi');
$hi = 'hi';
$profiler->stop_event();
//get an array of results
echo '<pre>';
print_r($profiler->profile());
echo '</pre>';
//get an html table of results
echo $profiler->profile(true);Code: Select all
Array
(
[0] => Array
(
[name] => Grabbing google content
[start] => 1272629527.51
[end] => 1272629527.71
[duration] => 0.197
)
[1] => Array
(
[name] => Looping a dumb math equation
[start] => 1272629527.71
[end] => 1272629527.71
[duration] => 0.002
)
[2] => Array
(
[name] => Sleeping a little bit
[start] => 1272629527.71
[end] => 1272629530.71
[duration] => 2.993
)
[3] => Array
(
[name] => Adding hi
[start] => 1272629530.71
[end] => 1272629530.71
[duration] => 0
)
[4] => Array
(
[name] => Profiler Totals (4 Events)
[start] => 1272629527.51
[end] => 1272629530.71
[duration] => 3.193
)
)
This is the kind of stuff that is fun to write! I found it interesting to note that sleep(3) took 2.993 seconds. If anything, my profiling script would add some milliseconds of time to that.. so hmm.