Location: PHPKode > scripts > phpbench > sexyprout-phpbench-8158542/phpbench.class.php
<?php
/**
 * phpbench
 * Simple PHP5 class to perform advanced benchmarks.
 * Copyright (C) 2009, 2010  sexyprout <hide@address.com>

 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * @version 2.0
 * @link https://github.com/sexyprout/phpbench
 */

class phpbench {

	/**
	 * Number of iterations using method loop() (defaults to 1,000)
	 *
	 * @var integer
	 * @access protected
	 */
	protected $iterations = 1000;

	/**
	 * Number of decimal places in formatted numbers (defaults to 4)
	 *
	 * @var integer
	 * @access protected
	 */
	protected $decimals = 4;

	/**
	 * Stores loops durations
	 *
	 * @var array
	 * @access protected
	 */
	protected $loops = array();

	/**
	 * HTML results table
	 *
	 * @var string
	 * @access protected
	 */
	protected $html;

	/**
	 * Headers of the results table
	 *
	 * @var array
	 * @access protected
	 */
	protected $table_headers = array(
		'phpbench',
		'Total execution time',
		 array(
		 	'Loops',
		 	 array(
		 	 	'No',
		 	 	'Time',
		 	 	'Diff. w/ the prev. loop',
		 	 	'Pct'
		 	 )
		 ),
		'Number of iterations'
	);

	/**
	 * Processed bench data that will be displayed in the table
	 *
	 * @var array
	 * @access
	 */
	protected $data = array();

	/**
	 * Class constructor
	 * Defines options
	 *
	 * @param integer $iterations Set number of iterations
	 * @param integer $decimals Set number of decimal places in
	   formatted numbers (see <http://www.php.net/manual/en/ini.core.php#ini.precision>);
	   does NOT affect percentages and faster/slower comparisons.
	 * @param integer $rendering Set rendering mode
	 * @return void
	 * @access public
	 */
	function __construct($iterations = 1000, $decimals = 4) {
		if(!is_int($iterations)) {
			trigger_error(__METHOD__ . '() expects parameter 1 to be long, ' . gettype($iterations) . ' given', E_USER_ERROR);
		} else {
			$this->iterations = intval($iterations);
		}

		if(!is_int($decimals)) {
			trigger_error(__METHOD__ . '() expects parameter 2 to be long, ' . gettype($decimals) . ' given', E_USER_ERROR);
		} else {
			$this->decimals = $decimals;
		}
	}

	/**
	 * Class destructor
	 * Displays the results table
	 *
	 * @since 2.0
	 * @return void
	 * @access public
	 */
	function __destruct() {
		$this->computeData();
		$this->processData();
		$this->buildTable();

		echo $this->html;
	}

	/**
	 * Loop
	 *
	 * @param closure $callback Callback function to execute
	 * @return void
	 * @access public
	 */
	function loop($callback) {
		$start = microtime(true);
		ob_start();

		for($i = 0; $i < $this->iterations; $i++)
			$callback();

		ob_end_clean();
		$this->loops[] = microtime(true) - $start;
	}

	/**
	 * Computes the data
	 * This sets the basic data array for further process
	 *
	 * @return void
	 * @access protected
	 */
	protected function computeData() {
		$data = array(); // new data

		$data['exec_time']  = array_sum($this->loops);
		$data['iterations'] = $this->iterations;

		$data['loops'] = array();

		foreach($this->loops as $i => $exec_time) {
			$prev_loop = $i == 0 ? array() : $data['loops'][$i - 1]; // don't worry, there shouldn't be any errors if you're a good developer
			$ldata = array(); // new data

			$ldata['nbr'] = $i + 1;
			$ldata['exec_time'] = $exec_time;

			if($i == 0) {
				$ldata['_faster'] = -1;
			} else {
				$ldata['_faster'] = $prev_loop['exec_time'] > $ldata['exec_time'];
				$ldata['diff'] = abs($ldata['exec_time'] - $prev_loop['exec_time']); // if you still don't understand the first comment of this method then you're a fag
				$ldata['comparison'] = $ldata['exec_time'] / $prev_loop['exec_time'];
			}

			if(count($this->loops) == 0) {
				$ldata['_fastest'] = -1;
				$ldata['_slowest'] = -1;
			} else {
				$ldata['_fastest'] = $ldata['exec_time'] == min($this->loops);
				$ldata['_slowest'] = $ldata['exec_time'] == max($this->loops);
			}

			$ldata['pct'] = $ldata['exec_time'] * 100 / $data['exec_time'];

			$data['loops'][] = $ldata;
		}

		$this->data = $data;
	}

	/**
	 * Processes the data
	 * This correctly formats the data to be displayed in the results table
	 *
	 * @return void
	 * @access protected
	 */
	protected function processData() {
		$data = array(); // new data

		$data['exec_time']  = round($this->data['exec_time'], $this->decimals);
		$data['exec_time'] .= ' s';

		$data['iterations'] = number_format($this->data['iterations']);

		$data['loops'] = array();

		foreach($this->data['loops'] as $i => $loop) {
			$ldata = array(); // new loop data

			$ldata['nbr']  = '#';
			$ldata['nbr'] .= $loop['nbr'];

			$ldata['exec_time']  = round($loop['exec_time'], $this->decimals);
			$ldata['exec_time'] .= ' s';

			if($i == 0) {
				$ldata['diff'] = '-';
				$ldata['comparison'] = '-';
			} else {
				$ldata['diff']  = round($loop['diff'], $this->decimals);
				$ldata['diff'] .= ' s';

				$ldata['comparison']  = $loop['_faster'] ? 1 / $loop['comparison'] : $loop['comparison'];
				$ldata['comparison']  = round($ldata['comparison'], 1);
				$ldata['comparison'] .= 'x ';
				$ldata['comparison'] .= $loop['_faster'] ? 'faster' : 'slower';
			}

			$ldata['_faster']  = $loop['_faster'];
			$ldata['_fastest'] = $loop['_fastest'];
			$ldata['_slowest'] = $loop['_slowest'];

			$ldata['pct']  = round($loop['pct'], 1);
			$ldata['pct'] .= '%';

			$data['loops'][] = $ldata;
		}

		$this->data = $data;
	}

	/**
	 * Builds the table 
	 * This fills the data into the table
	 *
	 * @return void
	 * @access protected
	 */
	protected function buildTable() {
		$headers = $this->table_headers;
		$data = $this->data;

		$table  = '<table style="font: 13px \'Helvetica Neue\', Helvetica, Arial, \'Liberation Sans\', sans-serif; border-collapse: collapse">';
		$table .= '<caption>' . $headers[0] . '</caption>';
		$table .= '<tr>';
		$table .= '<th colspan="5" style="border: 1px solid #999; background-color: #E0E0E0; padding: 5px 10px">' . $headers[1] . '</th>';
		$table .= '</tr>';
		$table .= '<tr>';
		$table .= '<td colspan="5" style="border: 1px solid #999; padding: 5px 10px">' . $data['exec_time'] . '</td>';
		$table .= '</tr>';
		$table .= '<tr>';
		$table .= '<th colspan="5" style="border: 1px solid #999; background-color: #E0E0E0; padding: 5px 10px">' . $headers[2][0] . '</th>';
		$table .= '</tr>';
		$table .= '<tr>';
		$table .= '<th style="border: 1px solid #999; background-color: #f1f1f1; padding: 5px 10px">' . $headers[2][1][0] . '</th>';
		$table .= '<th style="border: 1px solid #999; background-color: #f1f1f1; padding: 5px 10px">' . $headers[2][1][1] . '</th>';
		$table .= '<th colspan="2" style="border: 1px solid #999; background-color: #f1f1f1; padding: 5px 10px">' . $headers[2][1][2] . '</th>';
		$table .= '<th style="border: 1px solid #999; background-color: #f1f1f1; padding: 5px 10px">' . $headers[2][1][3] . '</th>';
		$table .= '</tr>';

		foreach($this->data['loops'] as $loop) {
			$table .= '<tr';

			if($loop['_fastest']) {
				$table .= ' style="background-color: #e0ffe0">';
			} elseif($loop['_slowest']) {
				$table .= ' style="background-color: #ffe0e0">';
			} else {
				$table .= '>';
			}

			$table .= '<td style="border: 1px solid #999; padding: 5px 10px">' . $loop['nbr'] . '</td>';
			$table .= '<td style="border: 1px solid #999; padding: 5px 10px">' . $loop['exec_time'] . '</td>';
			$table .= '<td style="border: 1px solid #999; padding: 5px 10px">' . $loop['diff'] . '</td>';

			$table .= '<td style="border: 1px solid #999; padding: 5px 10px';
			
			if($loop['_faster'] === true) { // -1 == true
				$table .= '; color: green">';
			} elseif(!$loop['_faster']) {
				$table .= '; color: red">';
			} else {
				$table .= '">';
			}

			$table .= $loop['comparison'];
			$table .= '</td>';

			$table .= '<td style="border: 1px solid #999; padding: 5px 10px">' . $loop['pct'] . '</td>';
			$table .= '</tr>';
		}

		$table .= '<tr>';
		$table .= '<th colspan="5" style="border: 1px solid #999; background-color: #E0E0E0; padding: 5px 10px">' . $headers[3] . '</th>';
		$table .= '</tr>';
		$table .= '<tr>';
		$table .= '<td colspan="5" style="border: 1px solid #999; padding: 5px 10px">' . $this->data['iterations'] . '</td>';
		$table .= '</tr>';
		$table .= '</table>';

		$this->html = $table;
	}
}
Return current item: phpbench