Every now and then I want to profile a given part of PHP code. For example I want to quickly check wether my current changeset to GeSHi works faster or is horribly slower. For a big change I’ll stick to Xdebug and KCachegrind. But for a quick overview? Overkill in my eyes.
Say hello to profile.class.php
, a simple timer class for PHP5 which you can use to get an overview about where how much time is spent. This is in no way a scientific method nor should you take the results of a single run as a basis for you decisions.
I’ve set an emphasize on an easy API so you don’t have to pollute your code with arbitrary hoops and whistles.
UPDATE: You can find the current updated source in the SVN repo of GeSHi.
Simple example
This is a quick example on how you could use the class:
<?php require'profile.class.php'; // should be obvious ;-) // here might be uninteresting code profile::start('overall'); // start a timer and give it a name // we add this one to get a time // for the overall runtime // this is the code you want to profile profile::start('$_SERVER'); profile::stop(); // stop the last active counter profile::start('$GLOBALS'); profile::stop(); profile::stop(); // stop overall timer
The output will be something like this:
profile results -------------------------------------- $GLOBALS 0.000027s 100.00% $_SERVER 0.000035s 128.07% overall 0.000212s 779.82%
Quite simple with a simple overview as a result.
Codeblocks
If you want to let some implementations of the same thing compete against each other do decide which one is the fastest, I’ve also added the codeblocks
method. In the example below you can see one of my testcase which checks wether stristr
or preg_match
is faster to check wether a string is inside the other on a case insensitive base:
<?php require'profile.class.php'; 'stristr'=>'if (stristr($string, "loRem")) {}', 'preg_match'=>'if (preg_match("/loRem/i", $string)) {}', 'string'=>$string, ),$iterations);
The results for a dummy text of about 24k size:
profile results ---------------------------------------- preg_match 0.229575s 100.00% stristr 2.601574s 1133.21%
So I’d say stristr
is pretty slow!
The class
You can also download the file below.
<?php /** * profile.class.php - A timer class for qualitative profiling * * This is a static class which you can use to qualitatively compare and * profile parts of your PHP code. It is as simple as * * <?php ... * require 'profile.class.php'; * ... * profile::start('some name'); * ... * profile::stop(); * ... * profile::print_results(profile::flush()); * ?> * * The class itself should be self explaining and well documented. Take a look below! * * * * profile.class.php 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 2 of the License, or * (at your option) any later version. * * profile.class.php 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 profile.class.php; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @author Milian Wolff <mail@milianw.de> * @copyright (C) 2008 Milian Wolff * @license http://gnu.org/copyleft/gpl.html GNU GPL */ class profile { // list of start and end timestamps // current names /** * start the profile timer * * @param $name optional name for this profile */ // nested timer // add old name to running profiles if(self::$cur_name===$name){ $name++; }else{ $name.='-SUB'; } } } // init } self::$cur_name=$name; // start timer } /** * stop the profile timer */ // stop timer // got a parent timer (nested timer) }else{ self::$cur_name=null; } } /** * get the results and reset internal result cache * * @param $reverse boolean; calculate deviation to longest diff, defaults to false (shortest diff) * @return array of results */ trigger_error('A timer is still running. Stop it before flushing the results by calling profile::stop().', E_USER_ERROR); return; } } // reset vars $start=self::$start; $end=self::$end; self::$cur_name=null; // get runtimes $deviate_key=$names[0]; foreach($namesas$key){ if(($reverse&&$diffs[$key]>$diffs[$deviate_key]) || (!$reverse&&$diffs[$key]<$diffs[$deviate_key])){ // remember which run we take as reference point to calculate deviations $deviate_key=$key; } } if($reverse){ }else{ } // calculate percental deviations and build up return array foreach($diffsas$name=>$diff){ 'diff'=>$diff, 'start'=>$start[$name], 'end'=>$end[$name], 'name'=>$name, 'deviation'=>($diffs[$name]/$diffs[$deviate_key])*100, )); } return$results; } /** * default implementation as to how one could present the results, optimized for CLI usage * * @param $results an array as returned by profile::flush() * @param $dont_print optionally; only return the result and dont print it * @return string */ $output="profile results\n"; $output="no code was profiled, empty resultset\n"; }else{ // get maximum col-width: $max_col_width=0; } foreach($resultsas$profile){ $profile['name'],$profile['diff'],$profile['deviation']); } } if(!$dont_print){ echo$output; } return$output; } /** * define code blocks and run them in random order, profiling each * this is great when writing little scripts to see which implementation of a given feature is faster * * @param $code_blocks an array with strings of php-code (just like eval or create_function accepts). * don't forget keys to give those codeblocks a name * @param $vars assoc array with global values which are used in the code blocks (i.e. varname => value) * @param $iterations number of times each block gets run * @return void */ }else{ $vars_keys=''; } // pita to get random order foreach($code_blocksas$name=>$block){ $block.=';'; } } foreach($blocksas$block){ self::start($block['name']); for($i=0; $i<$iterations; ++$i){ } self::stop(); } } }
Attachment | Size |
---|---|
profile.class_.php.txt | 6.55 KB |