Added KH 3.3.0
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_ArrCallback extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Parsing <em>command[param,param]</em> strings in <code>Arr::callback()</code>:
|
||||
http://github.com/shadowhand/kohana/commit/c3aaae849164bf92a486e29e736a265b350cb4da#L0R127';
|
||||
|
||||
public $loops = 10000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
// Valid callback strings
|
||||
'foo',
|
||||
'foo::bar',
|
||||
'foo[apple,orange]',
|
||||
'foo::bar[apple,orange]',
|
||||
'[apple,orange]', // no command, only params
|
||||
'foo[[apple],[orange]]', // params with brackets inside
|
||||
|
||||
// Invalid callback strings
|
||||
'foo[apple,orange', // no closing bracket
|
||||
);
|
||||
|
||||
public function bench_shadowhand($subject)
|
||||
{
|
||||
// The original regex we're trying to optimize
|
||||
if (preg_match('/([^\[]*+)\[(.*)\]/', $subject, $match))
|
||||
return $match;
|
||||
}
|
||||
|
||||
public function bench_geert_regex_1($subject)
|
||||
{
|
||||
// Added ^ and $ around the whole pattern
|
||||
if (preg_match('/^([^\[]*+)\[(.*)\]$/', $subject, $matches))
|
||||
return $matches;
|
||||
}
|
||||
|
||||
public function bench_geert_regex_2($subject)
|
||||
{
|
||||
// A rather experimental approach using \K which requires PCRE 7.2 ~ PHP 5.2.4
|
||||
// Note: $matches[0] = params, $matches[1] = command
|
||||
if (preg_match('/^([^\[]*+)\[\K.*(?=\]$)/', $subject, $matches))
|
||||
return $matches;
|
||||
}
|
||||
|
||||
public function bench_geert_str($subject)
|
||||
{
|
||||
// A native string function approach which beats all the regexes
|
||||
if (strpos($subject, '[') !== FALSE AND substr($subject, -1) === ']')
|
||||
return explode('[', substr($subject, 0, -1), 2);
|
||||
}
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_AutoLinkEmails extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Fixing <a href="http://dev.kohanaphp.com/issues/2772">#2772</a>, and comparing some possibilities.';
|
||||
|
||||
public $loops = 1000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
'<ul>
|
||||
<li>voorzitter@xxxx.com</li>
|
||||
<li>vicevoorzitter@xxxx.com</li>
|
||||
</ul>',
|
||||
);
|
||||
|
||||
// The original function, with str_replace replaced by preg_replace. Looks clean.
|
||||
public function bench_match_all_loop($subject)
|
||||
{
|
||||
if (preg_match_all('~\b(?<!href="mailto:|">|58;)(?!\.)[-+_a-z0-9.]++(?<!\.)@(?![-.])[-a-z0-9.]+(?<!\.)\.[a-z]{2,6}\b~i', $subject, $matches))
|
||||
{
|
||||
foreach ($matches[0] as $match)
|
||||
{
|
||||
$subject = preg_replace('!\b'.preg_quote($match).'\b!', HTML::mailto($match), $subject);
|
||||
}
|
||||
}
|
||||
|
||||
return $subject;
|
||||
}
|
||||
|
||||
// The "e" stands for "eval", hmm... Ugly and slow because it needs to reinterpret the PHP code upon each match.
|
||||
public function bench_replace_e($subject)
|
||||
{
|
||||
return preg_replace(
|
||||
'~\b(?<!href="mailto:|">|58;)(?!\.)[-+_a-z0-9.]++(?<!\.)@(?![-.])[-a-z0-9.]+(?<!\.)\.[a-z]{2,6}\b~ie',
|
||||
'HTML::mailto("$0")', // Yuck!
|
||||
$subject
|
||||
);
|
||||
}
|
||||
|
||||
// This one should be quite okay, it just requires an otherwise useless single-purpose callback.
|
||||
public function bench_replace_callback_external($subject)
|
||||
{
|
||||
return preg_replace_callback(
|
||||
'~\b(?<!href="mailto:|">|58;)(?!\.)[-+_a-z0-9.]++(?<!\.)@(?![-.])[-a-z0-9.]+(?<!\.)\.[a-z]{2,6}\b~i',
|
||||
array($this, '_callback_external'),
|
||||
$subject
|
||||
);
|
||||
}
|
||||
protected function _callback_external($matches)
|
||||
{
|
||||
return HTML::mailto($matches[0]);
|
||||
}
|
||||
|
||||
// This one clearly is the ugliest, the slowest and consumes a lot of memory!
|
||||
public function bench_replace_callback_internal($subject)
|
||||
{
|
||||
return preg_replace_callback(
|
||||
'~\b(?<!href="mailto:|">|58;)(?!\.)[-+_a-z0-9.]++(?<!\.)@(?![-.])[-a-z0-9.]+(?<!\.)\.[a-z]{2,6}\b~i',
|
||||
create_function('$matches', 'return HTML::mailto($matches[0]);'), // Yuck!
|
||||
$subject
|
||||
);
|
||||
}
|
||||
|
||||
}
|
186
includes/kohana/modules/codebench/classes/Bench/DateSpan.php
Normal file
186
includes/kohana/modules/codebench/classes/Bench/DateSpan.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Woody Gilk <woody.gilk@kohanaphp.com>
|
||||
*/
|
||||
class Bench_DateSpan extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Optimization for <code>Date::span()</code>.';
|
||||
|
||||
public $loops = 1000;
|
||||
|
||||
public $subjects = array();
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->subjects = array(
|
||||
time(),
|
||||
time() - Date::MONTH,
|
||||
time() - Date::YEAR,
|
||||
time() - Date::YEAR * 10,
|
||||
);
|
||||
}
|
||||
|
||||
// Original method
|
||||
public static function bench_span_original($remote, $local = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds')
|
||||
{
|
||||
// Array with the output formats
|
||||
$output = preg_split('/[^a-z]+/', strtolower( (string) $output));
|
||||
|
||||
// Invalid output
|
||||
if (empty($output))
|
||||
return FALSE;
|
||||
|
||||
// Make the output values into keys
|
||||
extract(array_flip($output), EXTR_SKIP);
|
||||
|
||||
if ($local === NULL)
|
||||
{
|
||||
// Calculate the span from the current time
|
||||
$local = time();
|
||||
}
|
||||
|
||||
// Calculate timespan (seconds)
|
||||
$timespan = abs($remote - $local);
|
||||
|
||||
if (isset($years))
|
||||
{
|
||||
$timespan -= Date::YEAR * ($years = (int) floor($timespan / Date::YEAR));
|
||||
}
|
||||
|
||||
if (isset($months))
|
||||
{
|
||||
$timespan -= Date::MONTH * ($months = (int) floor($timespan / Date::MONTH));
|
||||
}
|
||||
|
||||
if (isset($weeks))
|
||||
{
|
||||
$timespan -= Date::WEEK * ($weeks = (int) floor($timespan / Date::WEEK));
|
||||
}
|
||||
|
||||
if (isset($days))
|
||||
{
|
||||
$timespan -= Date::DAY * ($days = (int) floor($timespan / Date::DAY));
|
||||
}
|
||||
|
||||
if (isset($hours))
|
||||
{
|
||||
$timespan -= Date::HOUR * ($hours = (int) floor($timespan / Date::HOUR));
|
||||
}
|
||||
|
||||
if (isset($minutes))
|
||||
{
|
||||
$timespan -= Date::MINUTE * ($minutes = (int) floor($timespan / Date::MINUTE));
|
||||
}
|
||||
|
||||
// Seconds ago, 1
|
||||
if (isset($seconds))
|
||||
{
|
||||
$seconds = $timespan;
|
||||
}
|
||||
|
||||
// Remove the variables that cannot be accessed
|
||||
unset($timespan, $remote, $local);
|
||||
|
||||
// Deny access to these variables
|
||||
$deny = array_flip(array('deny', 'key', 'difference', 'output'));
|
||||
|
||||
// Return the difference
|
||||
$difference = array();
|
||||
foreach ($output as $key)
|
||||
{
|
||||
if (isset($$key) AND ! isset($deny[$key]))
|
||||
{
|
||||
// Add requested key to the output
|
||||
$difference[$key] = $$key;
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid output formats string
|
||||
if (empty($difference))
|
||||
return FALSE;
|
||||
|
||||
// If only one output format was asked, don't put it in an array
|
||||
if (count($difference) === 1)
|
||||
return current($difference);
|
||||
|
||||
// Return array
|
||||
return $difference;
|
||||
}
|
||||
|
||||
// Using an array for the output
|
||||
public static function bench_span_use_array($remote, $local = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds')
|
||||
{
|
||||
// Array with the output formats
|
||||
$output = preg_split('/[^a-z]+/', strtolower( (string) $output));
|
||||
|
||||
// Invalid output
|
||||
if (empty($output))
|
||||
return FALSE;
|
||||
|
||||
// Convert the list of outputs to an associative array
|
||||
$output = array_combine($output, array_fill(0, count($output), 0));
|
||||
|
||||
// Make the output values into keys
|
||||
extract(array_flip($output), EXTR_SKIP);
|
||||
|
||||
if ($local === NULL)
|
||||
{
|
||||
// Calculate the span from the current time
|
||||
$local = time();
|
||||
}
|
||||
|
||||
// Calculate timespan (seconds)
|
||||
$timespan = abs($remote - $local);
|
||||
|
||||
if (isset($output['years']))
|
||||
{
|
||||
$timespan -= Date::YEAR * ($output['years'] = (int) floor($timespan / Date::YEAR));
|
||||
}
|
||||
|
||||
if (isset($output['months']))
|
||||
{
|
||||
$timespan -= Date::MONTH * ($output['months'] = (int) floor($timespan / Date::MONTH));
|
||||
}
|
||||
|
||||
if (isset($output['weeks']))
|
||||
{
|
||||
$timespan -= Date::WEEK * ($output['weeks'] = (int) floor($timespan / Date::WEEK));
|
||||
}
|
||||
|
||||
if (isset($output['days']))
|
||||
{
|
||||
$timespan -= Date::DAY * ($output['days'] = (int) floor($timespan / Date::DAY));
|
||||
}
|
||||
|
||||
if (isset($output['hours']))
|
||||
{
|
||||
$timespan -= Date::HOUR * ($output['hours'] = (int) floor($timespan / Date::HOUR));
|
||||
}
|
||||
|
||||
if (isset($output['minutes']))
|
||||
{
|
||||
$timespan -= Date::MINUTE * ($output['minutes'] = (int) floor($timespan / Date::MINUTE));
|
||||
}
|
||||
|
||||
// Seconds ago, 1
|
||||
if (isset($output['seconds']))
|
||||
{
|
||||
$output['seconds'] = $timespan;
|
||||
}
|
||||
|
||||
if (count($output) === 1)
|
||||
{
|
||||
// Only a single output was requested, return it
|
||||
return array_pop($output);
|
||||
}
|
||||
|
||||
// Return array
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_ExplodeLimit extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Having a look at the effect of adding a limit to the <a href="http://php.net/explode">explode</a> function.<br />
|
||||
http://stackoverflow.com/questions/1308149/how-to-get-a-part-of-url-between-4th-and-5th-slashes';
|
||||
|
||||
public $loops = 10000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
'http://example.com/articles/123a/view',
|
||||
'http://example.com/articles/123a/view/x/x/x/x/x',
|
||||
'http://example.com/articles/123a/view/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x',
|
||||
);
|
||||
|
||||
public function bench_explode_without_limit($subject)
|
||||
{
|
||||
$parts = explode('/', $subject);
|
||||
return $parts[4];
|
||||
}
|
||||
|
||||
public function bench_explode_with_limit($subject)
|
||||
{
|
||||
$parts = explode('/', $subject, 6);
|
||||
return $parts[4];
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_GruberURL extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Optimization for http://daringfireball.net/2009/11/liberal_regex_for_matching_urls';
|
||||
|
||||
public $loops = 10000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
'http://foo.com/blah_blah',
|
||||
'http://foo.com/blah_blah/',
|
||||
'(Something like http://foo.com/blah_blah)',
|
||||
'http://foo.com/blah_blah_(wikipedia)',
|
||||
'(Something like http://foo.com/blah_blah_(wikipedia))',
|
||||
'http://foo.com/blah_blah.',
|
||||
'http://foo.com/blah_blah/.',
|
||||
'<http://foo.com/blah_blah>',
|
||||
'<http://foo.com/blah_blah/>',
|
||||
'http://foo.com/blah_blah,',
|
||||
'http://www.example.com/wpstyle/?p=364.',
|
||||
'http://✪df.ws/e7l',
|
||||
'rdar://1234',
|
||||
'rdar:/1234',
|
||||
'x-yojimbo-item://6303E4C1-xxxx-45A6-AB9D-3A908F59AE0E',
|
||||
'message://%3c330e7f8409726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e',
|
||||
'http://➡.ws/䨹',
|
||||
'www.➡.ws/䨹',
|
||||
'<tag>http://example.com</tag>',
|
||||
'Just a www.example.com link.',
|
||||
// To test the use of possessive quatifiers:
|
||||
'httpppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp',
|
||||
);
|
||||
|
||||
public function bench_daringfireball($subject)
|
||||
{
|
||||
// Original regex by John Gruber
|
||||
preg_match('~\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))~', $subject, $matches);
|
||||
return (empty($matches)) ? FALSE : $matches[0];
|
||||
}
|
||||
|
||||
public function bench_daringfireball_v2($subject)
|
||||
{
|
||||
// Removed outer capturing parentheses, made another pair non-capturing
|
||||
preg_match('~\b(?:[\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|(?:[^[:punct:]\s]|/))~', $subject, $matches);
|
||||
return (empty($matches)) ? FALSE : $matches[0];
|
||||
}
|
||||
|
||||
public function bench_daringfireball_v3($subject)
|
||||
{
|
||||
// Made quantifiers possessive where possible
|
||||
preg_match('~\b(?:[\w-]++://?+|www[.])[^\s()<>]+(?:\([\w\d]++\)|(?:[^[:punct:]\s]|/))~', $subject, $matches);
|
||||
return (empty($matches)) ? FALSE : $matches[0];
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_LtrimDigits extends Codebench {
|
||||
|
||||
public $description = 'Chopping off leading digits: regex vs ltrim.';
|
||||
|
||||
public $loops = 100000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
'123digits',
|
||||
'no-digits',
|
||||
);
|
||||
|
||||
public function bench_regex($subject)
|
||||
{
|
||||
return preg_replace('/^\d+/', '', $subject);
|
||||
}
|
||||
|
||||
public function bench_ltrim($subject)
|
||||
{
|
||||
return ltrim($subject, '0..9');
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_MDDoBaseURL extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Optimization for the <code>doBaseURL()</code> method of <code>Kohana_Kodoc_Markdown</code>
|
||||
for the Kohana Userguide.';
|
||||
|
||||
public $loops = 10000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
// Valid matches
|
||||
'[filesystem](about.filesystem)',
|
||||
'[filesystem](about.filesystem "Optional title")',
|
||||
'[same page link](#id)',
|
||||
'[object oriented](http://wikipedia.org/wiki/Object-Oriented_Programming)',
|
||||
|
||||
// Invalid matches
|
||||
'',
|
||||
'[filesystem](about.filesystem',
|
||||
);
|
||||
|
||||
public function bench_original($subject)
|
||||
{
|
||||
// The original regex contained a bug, which is fixed here for benchmarking purposes.
|
||||
// At the very start of the regex, (?!!) has been replace by (?<!!)
|
||||
return preg_replace_callback('~(?<!!)\[(.+?)\]\(([^#]\S*(?:\s*".+?")?)\)~', array($this, '_add_base_url_original'), $subject);
|
||||
}
|
||||
public function _add_base_url_original($matches)
|
||||
{
|
||||
if ($matches[2] AND strpos($matches[2], '://') === FALSE)
|
||||
{
|
||||
// Add the base url to the link URL
|
||||
$matches[2] = 'http://BASE/'.$matches[2];
|
||||
}
|
||||
|
||||
// Recreate the link
|
||||
return "[{$matches[1]}]({$matches[2]})";
|
||||
}
|
||||
|
||||
public function bench_optimized_callback($subject)
|
||||
{
|
||||
return preg_replace_callback('~(?<!!)\[(.+?)\]\((?!\w++://)([^#]\S*(?:\s*+".+?")?)\)~', array($this, '_add_base_url_optimized'), $subject);
|
||||
}
|
||||
public function _add_base_url_optimized($matches)
|
||||
{
|
||||
// Add the base url to the link URL
|
||||
$matches[2] = 'http://BASE/'.$matches[2];
|
||||
|
||||
// Recreate the link
|
||||
return "[{$matches[1]}]({$matches[2]})";
|
||||
}
|
||||
|
||||
public function bench_callback_gone($subject)
|
||||
{
|
||||
// All the optimized callback was doing now, is prepend some text to the URL.
|
||||
// We don't need a callback for that, and that should be clearly faster.
|
||||
return preg_replace('~(?<!!)(\[.+?\]\()(?!\w++://)([^#]\S*(?:\s*+".+?")?\))~', '$1http://BASE/$2', $subject);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_MDDoImageURL extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Optimization for the <code>doImageURL()</code> method of <code>Kohana_Kodoc_Markdown</code>
|
||||
for the Kohana Userguide.';
|
||||
|
||||
public $loops = 10000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
// Valid matches
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'![Alt text containing [square] brackets](img/install.png)',
|
||||
'![Empty src]()',
|
||||
|
||||
// Invalid matches
|
||||
';
|
||||
|
||||
public function bench_original($subject)
|
||||
{
|
||||
return preg_replace_callback('~!\[(.+?)\]\((\S*(?:\s*".+?")?)\)~', array($this, '_add_image_url_original'), $subject);
|
||||
}
|
||||
protected function _add_image_url_original($matches)
|
||||
{
|
||||
if ($matches[2] AND strpos($matches[2], '://') === FALSE)
|
||||
{
|
||||
// Add the base url to the link URL
|
||||
$matches[2] = 'http://BASE/'.$matches[2];
|
||||
}
|
||||
|
||||
// Recreate the link
|
||||
return "![{$matches[1]}]({$matches[2]})";
|
||||
}
|
||||
|
||||
public function bench_optimized_callback($subject)
|
||||
{
|
||||
// Moved the check for "://" to the regex, simplifying the callback function
|
||||
return preg_replace_callback('~!\[(.+?)\]\((?!\w++://)(\S*(?:\s*+".+?")?)\)~', array($this, '_add_image_url_optimized'), $subject);
|
||||
}
|
||||
protected function _add_image_url_optimized($matches)
|
||||
{
|
||||
// Add the base url to the link URL
|
||||
$matches[2] = 'http://BASE/'.$matches[2];
|
||||
|
||||
// Recreate the link
|
||||
return "![{$matches[1]}]({$matches[2]})";
|
||||
}
|
||||
|
||||
public function bench_callback_gone($subject)
|
||||
{
|
||||
// All the optimized callback was doing now, is prepend some text to the URL.
|
||||
// We don't need a callback for that, and that should be clearly faster.
|
||||
return preg_replace('~(!\[.+?\]\()(?!\w++://)(\S*(?:\s*+".+?")?\))~', '$1http://BASE/$2', $subject);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_MDDoIncludeViews extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Optimization for the <code>doIncludeViews()</code> method of <code>Kohana_Kodoc_Markdown</code>
|
||||
for the Kohana Userguide.';
|
||||
|
||||
public $loops = 10000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
// Valid matches
|
||||
'{{one}} two {{three}}',
|
||||
'{{userguide/examples/hello_world_error}}',
|
||||
|
||||
// Invalid matches
|
||||
'{}',
|
||||
'{{}}',
|
||||
'{{userguide/examples/hello_world_error}',
|
||||
'{{userguide/examples/hello_world_error }}',
|
||||
'{{userguide/examples/{{hello_world_error }}',
|
||||
);
|
||||
|
||||
public function bench_original($subject)
|
||||
{
|
||||
preg_match_all('/{{(\S+?)}}/m', $subject, $matches, PREG_SET_ORDER);
|
||||
return $matches;
|
||||
}
|
||||
|
||||
public function bench_possessive($subject)
|
||||
{
|
||||
// Using a possessive character class
|
||||
// Removed useless /m modifier
|
||||
preg_match_all('/{{([^\s{}]++)}}/', $subject, $matches, PREG_SET_ORDER);
|
||||
return $matches;
|
||||
}
|
||||
|
||||
public function bench_lookaround($subject)
|
||||
{
|
||||
// Using lookaround to move $mathes[1] into $matches[0]
|
||||
preg_match_all('/(?<={{)[^\s{}]++(?=}})/', $subject, $matches, PREG_SET_ORDER);
|
||||
return $matches;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_StripNullBytes extends Codebench {
|
||||
|
||||
public $description =
|
||||
'String replacement comparisons related to <a href="http://dev.kohanaphp.com/issues/2676">#2676</a>.';
|
||||
|
||||
public $loops = 1000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
"\0",
|
||||
"\0\0\0\0\0\0\0\0\0\0",
|
||||
"bla\0bla\0bla\0bla\0bla\0bla\0bla\0bla\0bla\0bla",
|
||||
"blablablablablablablablablablablablablablablabla",
|
||||
);
|
||||
|
||||
public function bench_str_replace($subject)
|
||||
{
|
||||
return str_replace("\0", '', $subject);
|
||||
}
|
||||
|
||||
public function bench_strtr($subject)
|
||||
{
|
||||
return strtr($subject, array("\0" => ''));
|
||||
}
|
||||
|
||||
public function bench_preg_replace($subject)
|
||||
{
|
||||
return preg_replace('~\0+~', '', $subject);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_Transliterate extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Inspired by:
|
||||
http://forum.kohanaframework.org/comments.php?DiscussionID=6113';
|
||||
|
||||
public $loops = 10;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
// ASCII
|
||||
'a', 'b', 'c', 'd', '1', '2', '3',
|
||||
|
||||
// Non-ASCII
|
||||
'à', 'ô', 'ď', 'ḟ', 'ë', 'š', 'ơ',
|
||||
'ß', 'ă', 'ř', 'ț', 'ň', 'ā', 'ķ',
|
||||
'ŝ', 'ỳ', 'ņ', 'ĺ', 'ħ', 'ṗ', 'ó',
|
||||
'ú', 'ě', 'é', 'ç', 'ẁ', 'ċ', 'õ',
|
||||
'ṡ', 'ø', 'ģ', 'ŧ', 'ș', 'ė', 'ĉ',
|
||||
'ś', 'î', 'ű', 'ć', 'ę', 'ŵ', 'ṫ',
|
||||
'ū', 'č', 'ö', 'è', 'ŷ', 'ą', 'ł',
|
||||
'ų', 'ů', 'ş', 'ğ', 'ļ', 'ƒ', 'ž',
|
||||
'ẃ', 'ḃ', 'å', 'ì', 'ï', 'ḋ', 'ť',
|
||||
'ŗ', 'ä', 'í', 'ŕ', 'ê', 'ü', 'ò',
|
||||
'ē', 'ñ', 'ń', 'ĥ', 'ĝ', 'đ', 'ĵ',
|
||||
'ÿ', 'ũ', 'ŭ', 'ư', 'ţ', 'ý', 'ő',
|
||||
'â', 'ľ', 'ẅ', 'ż', 'ī', 'ã', 'ġ',
|
||||
'ṁ', 'ō', 'ĩ', 'ù', 'į', 'ź', 'á',
|
||||
'û', 'þ', 'ð', 'æ', 'µ', 'ĕ', 'ı',
|
||||
'À', 'Ô', 'Ď', 'Ḟ', 'Ë', 'Š', 'Ơ',
|
||||
'Ă', 'Ř', 'Ț', 'Ň', 'Ā', 'Ķ', 'Ĕ',
|
||||
'Ŝ', 'Ỳ', 'Ņ', 'Ĺ', 'Ħ', 'Ṗ', 'Ó',
|
||||
'Ú', 'Ě', 'É', 'Ç', 'Ẁ', 'Ċ', 'Õ',
|
||||
'Ṡ', 'Ø', 'Ģ', 'Ŧ', 'Ș', 'Ė', 'Ĉ',
|
||||
'Ś', 'Î', 'Ű', 'Ć', 'Ę', 'Ŵ', 'Ṫ',
|
||||
'Ū', 'Č', 'Ö', 'È', 'Ŷ', 'Ą', 'Ł',
|
||||
'Ų', 'Ů', 'Ş', 'Ğ', 'Ļ', 'Ƒ', 'Ž',
|
||||
'Ẃ', 'Ḃ', 'Å', 'Ì', 'Ï', 'Ḋ', 'Ť',
|
||||
'Ŗ', 'Ä', 'Í', 'Ŕ', 'Ê', 'Ü', 'Ò',
|
||||
'Ē', 'Ñ', 'Ń', 'Ĥ', 'Ĝ', 'Đ', 'Ĵ',
|
||||
'Ÿ', 'Ũ', 'Ŭ', 'Ư', 'Ţ', 'Ý', 'Ő',
|
||||
'Â', 'Ľ', 'Ẅ', 'Ż', 'Ī', 'Ã', 'Ġ',
|
||||
'Ṁ', 'Ō', 'Ĩ', 'Ù', 'Į', 'Ź', 'Á',
|
||||
'Û', 'Þ', 'Ð', 'Æ', 'İ',
|
||||
);
|
||||
|
||||
public function bench_utf8($subject)
|
||||
{
|
||||
return UTF8::transliterate_to_ascii($subject);
|
||||
}
|
||||
|
||||
public function bench_iconv($subject)
|
||||
{
|
||||
// Note: need to suppress errors on iconv because some chars trigger the following notice:
|
||||
// "Detected an illegal character in input string"
|
||||
return preg_replace('~[^-a-z0-9]+~i', '', @iconv('UTF-8', 'ASCII//TRANSLIT', $subject));
|
||||
}
|
||||
|
||||
}
|
123
includes/kohana/modules/codebench/classes/Bench/URLSite.php
Normal file
123
includes/kohana/modules/codebench/classes/Bench/URLSite.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_URLSite extends Codebench {
|
||||
|
||||
public $description = 'http://dev.kohanaframework.org/issues/3110';
|
||||
|
||||
public $loops = 1000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
'',
|
||||
'news',
|
||||
'news/',
|
||||
'/news/',
|
||||
'news/page/5',
|
||||
'news/page:5',
|
||||
'http://example.com/',
|
||||
'http://example.com/hello',
|
||||
'http://example.com:80/',
|
||||
'http://user:pass@example.com/',
|
||||
);
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
foreach ($this->subjects as $subject)
|
||||
{
|
||||
// Automatically create URIs with query string and/or fragment part appended
|
||||
$this->subjects[] = $subject.'?query=string';
|
||||
$this->subjects[] = $subject.'#fragment';
|
||||
$this->subjects[] = $subject.'?query=string#fragment';
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function bench_original($uri)
|
||||
{
|
||||
// Get the path from the URI
|
||||
$path = trim(parse_url($uri, PHP_URL_PATH), '/');
|
||||
|
||||
if ($query = parse_url($uri, PHP_URL_QUERY))
|
||||
{
|
||||
$query = '?'.$query;
|
||||
}
|
||||
|
||||
if ($fragment = parse_url($uri, PHP_URL_FRAGMENT))
|
||||
{
|
||||
$fragment = '#'.$fragment;
|
||||
}
|
||||
|
||||
return $path.$query.$fragment;
|
||||
}
|
||||
|
||||
public function bench_explode($uri)
|
||||
{
|
||||
// Chop off possible scheme, host, port, user and pass parts
|
||||
$path = preg_replace('~^[-a-z0-9+.]++://[^/]++/?~', '', trim($uri, '/'));
|
||||
|
||||
$fragment = '';
|
||||
$explode = explode('#', $path, 2);
|
||||
if (isset($explode[1]))
|
||||
{
|
||||
$path = $explode[0];
|
||||
$fragment = '#'.$explode[1];
|
||||
}
|
||||
|
||||
$query = '';
|
||||
$explode = explode('?', $path, 2);
|
||||
if (isset($explode[1]))
|
||||
{
|
||||
$path = $explode[0];
|
||||
$query = '?'.$explode[1];
|
||||
}
|
||||
|
||||
return $path.$query.$fragment;
|
||||
}
|
||||
|
||||
public function bench_regex($uri)
|
||||
{
|
||||
preg_match('~^(?:[-a-z0-9+.]++://[^/]++/?)?([^?#]++)?(\?[^#]*+)?(#.*)?~', trim($uri, '/'), $matches);
|
||||
$path = Arr::get($matches, 1, '');
|
||||
$query = Arr::get($matches, 2, '');
|
||||
$fragment = Arr::get($matches, 3, '');
|
||||
|
||||
return $path.$query.$fragment;
|
||||
}
|
||||
|
||||
public function bench_regex_without_arrget($uri)
|
||||
{
|
||||
preg_match('~^(?:[-a-z0-9+.]++://[^/]++/?)?([^?#]++)?(\?[^#]*+)?(#.*)?~', trim($uri, '/'), $matches);
|
||||
$path = isset($matches[1]) ? $matches[1] : '';
|
||||
$query = isset($matches[2]) ? $matches[2] : '';
|
||||
$fragment = isset($matches[3]) ? $matches[3] : '';
|
||||
|
||||
return $path.$query.$fragment;
|
||||
}
|
||||
|
||||
// And then I thought, why do all the work of extracting the query and fragment parts and then reappending them?
|
||||
// Just leaving them alone should be fine, right? As a bonus we get a very nice speed boost.
|
||||
public function bench_less_is_more($uri)
|
||||
{
|
||||
// Chop off possible scheme, host, port, user and pass parts
|
||||
$path = preg_replace('~^[-a-z0-9+.]++://[^/]++/?~', '', trim($uri, '/'));
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
public function bench_less_is_more_with_strpos_optimization($uri)
|
||||
{
|
||||
if (strpos($uri, '://') !== FALSE)
|
||||
{
|
||||
// Chop off possible scheme, host, port, user and pass parts
|
||||
$uri = preg_replace('~^[-a-z0-9+.]++://[^/]++/?~', '', trim($uri, '/'));
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Woody Gilk <woody.gilk@kohanaphp.com>
|
||||
*/
|
||||
class Bench_UserFuncArray extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Testing the speed difference of using <code>call_user_func_array</code>
|
||||
compared to counting args and doing manual calls.';
|
||||
|
||||
public $loops = 100000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
// Argument sets
|
||||
array(),
|
||||
array('one'),
|
||||
array('one', 'two'),
|
||||
array('one', 'two', 'three'),
|
||||
);
|
||||
|
||||
public function bench_count_args($args)
|
||||
{
|
||||
$name = 'callme';
|
||||
switch (count($args))
|
||||
{
|
||||
case 1:
|
||||
$this->$name($args[0]);
|
||||
break;
|
||||
case 2:
|
||||
$this->$name($args[0], $args[1]);
|
||||
break;
|
||||
case 3:
|
||||
$this->$name($args[0], $args[1], $args[2]);
|
||||
break;
|
||||
case 4:
|
||||
$this->$name($args[0], $args[1], $args[2], $args[3]);
|
||||
break;
|
||||
default:
|
||||
call_user_func_array(array($this, $name), $args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function bench_direct_call($args)
|
||||
{
|
||||
$name = 'callme';
|
||||
call_user_func_array(array($this, $name), $args);
|
||||
}
|
||||
|
||||
protected function callme()
|
||||
{
|
||||
return count(func_get_args());
|
||||
}
|
||||
|
||||
}
|
116
includes/kohana/modules/codebench/classes/Bench/ValidColor.php
Normal file
116
includes/kohana/modules/codebench/classes/Bench/ValidColor.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_ValidColor extends Codebench {
|
||||
|
||||
public $description =
|
||||
'Optimization for <code>Validate::color()</code>.
|
||||
See: http://forum.kohanaphp.com/comments.php?DiscussionID=2192.
|
||||
|
||||
Note that the methods with an <em>_invalid</em> suffix contain flawed regexes and should be
|
||||
completely discarded. I left them in here for educational purposes, and to remind myself
|
||||
to think harder and test more thoroughly. It can\'t be that I only found out so late in
|
||||
the game. For the regex explanation have a look at the forum topic mentioned earlier.';
|
||||
|
||||
public $loops = 10000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
// Valid colors
|
||||
'aaA',
|
||||
'123',
|
||||
'000000',
|
||||
'#123456',
|
||||
'#abcdef',
|
||||
|
||||
// Invalid colors
|
||||
'ggg',
|
||||
'1234',
|
||||
'#1234567',
|
||||
"#000\n",
|
||||
'}§è!çà%$z',
|
||||
);
|
||||
|
||||
// Note that I added the D modifier to corey's regexes. We need to match exactly
|
||||
// the same if we want the benchmarks to be of any value.
|
||||
public function bench_corey_regex_1_invalid($subject)
|
||||
{
|
||||
return (bool) preg_match('/^#?([0-9a-f]{1,2}){3}$/iD', $subject);
|
||||
}
|
||||
|
||||
public function bench_corey_regex_2($subject)
|
||||
{
|
||||
return (bool) preg_match('/^#?([0-9a-f]){3}(([0-9a-f]){3})?$/iD', $subject);
|
||||
}
|
||||
|
||||
// Optimized corey_regex_1
|
||||
// Using non-capturing parentheses and a possessive interval
|
||||
public function bench_geert_regex_1a_invalid($subject)
|
||||
{
|
||||
return (bool) preg_match('/^#?(?:[0-9a-f]{1,2}+){3}$/iD', $subject);
|
||||
}
|
||||
|
||||
// Optimized corey_regex_2
|
||||
// Removed useless parentheses, made the remaining ones non-capturing
|
||||
public function bench_geert_regex_2a($subject)
|
||||
{
|
||||
return (bool) preg_match('/^#?[0-9a-f]{3}(?:[0-9a-f]{3})?$/iD', $subject);
|
||||
}
|
||||
|
||||
// Optimized geert_regex_1a
|
||||
// Possessive "#"
|
||||
public function bench_geert_regex_1b_invalid($subject)
|
||||
{
|
||||
return (bool) preg_match('/^#?+(?:[0-9a-f]{1,2}+){3}$/iD', $subject);
|
||||
}
|
||||
|
||||
// Optimized geert_regex_2a
|
||||
// Possessive "#"
|
||||
public function bench_geert_regex_2b($subject)
|
||||
{
|
||||
return (bool) preg_match('/^#?+[0-9a-f]{3}(?:[0-9a-f]{3})?$/iD', $subject);
|
||||
}
|
||||
|
||||
// Using \z instead of $
|
||||
public function bench_salathe_regex_1($subject)
|
||||
{
|
||||
return (bool) preg_match('/^#?+[0-9a-f]{3}(?:[0-9a-f]{3})?\z/i', $subject);
|
||||
}
|
||||
|
||||
// Using \A instead of ^
|
||||
public function bench_salathe_regex_2($subject)
|
||||
{
|
||||
return (bool) preg_match('/\A#?+[0-9a-f]{3}(?:[0-9a-f]{3})?\z/i', $subject);
|
||||
}
|
||||
|
||||
// A solution without regex
|
||||
public function bench_geert_str($subject)
|
||||
{
|
||||
if ($subject[0] === '#')
|
||||
{
|
||||
$subject = substr($subject, 1);
|
||||
}
|
||||
|
||||
$strlen = strlen($subject);
|
||||
return (($strlen === 3 OR $strlen === 6) AND ctype_xdigit($subject));
|
||||
}
|
||||
|
||||
// An ugly, but fast, solution without regex
|
||||
public function bench_salathe_str($subject)
|
||||
{
|
||||
if ($subject[0] === '#')
|
||||
{
|
||||
$subject = substr($subject, 1);
|
||||
}
|
||||
|
||||
// TRUE if:
|
||||
// 1. $subject is 6 or 3 chars long
|
||||
// 2. $subject contains only hexadecimal digits
|
||||
return (((isset($subject[5]) AND ! isset($subject[6])) OR
|
||||
(isset($subject[2]) AND ! isset($subject[3])))
|
||||
AND ctype_xdigit($subject));
|
||||
}
|
||||
}
|
105
includes/kohana/modules/codebench/classes/Bench/ValidURL.php
Normal file
105
includes/kohana/modules/codebench/classes/Bench/ValidURL.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* @package Kohana/Codebench
|
||||
* @category Tests
|
||||
* @author Geert De Deckere <geert@idoe.be>
|
||||
*/
|
||||
class Bench_ValidURL extends Codebench {
|
||||
|
||||
public $description =
|
||||
'filter_var vs regex:
|
||||
http://dev.kohanaframework.org/issues/2847';
|
||||
|
||||
public $loops = 1000;
|
||||
|
||||
public $subjects = array
|
||||
(
|
||||
// Valid
|
||||
'http://google.com',
|
||||
'http://google.com/',
|
||||
'http://google.com/?q=abc',
|
||||
'http://google.com/#hash',
|
||||
'http://localhost',
|
||||
'http://hello-world.pl',
|
||||
'http://hello--world.pl',
|
||||
'http://h.e.l.l.0.pl',
|
||||
'http://server.tld/get/info',
|
||||
'http://127.0.0.1',
|
||||
'http://127.0.0.1:80',
|
||||
'http://user@127.0.0.1',
|
||||
'http://user:pass@127.0.0.1',
|
||||
'ftp://my.server.com',
|
||||
'rss+xml://rss.example.com',
|
||||
|
||||
// Invalid
|
||||
'http://google.2com',
|
||||
'http://google.com?q=abc',
|
||||
'http://google.com#hash',
|
||||
'http://hello-.pl',
|
||||
'http://hel.-lo.world.pl',
|
||||
'http://ww£.google.com',
|
||||
'http://127.0.0.1234',
|
||||
'http://127.0.0.1.1',
|
||||
'http://user:@127.0.0.1',
|
||||
"http://finalnewline.com\n",
|
||||
);
|
||||
|
||||
public function bench_filter_var($url)
|
||||
{
|
||||
return (bool) filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED);
|
||||
}
|
||||
|
||||
public function bench_regex($url)
|
||||
{
|
||||
// Based on http://www.apps.ietf.org/rfc/rfc1738.html#sec-5
|
||||
if ( ! preg_match(
|
||||
'~^
|
||||
|
||||
# scheme
|
||||
[-a-z0-9+.]++://
|
||||
|
||||
# username:password (optional)
|
||||
(?:
|
||||
[-a-z0-9$_.+!*\'(),;?&=%]++ # username
|
||||
(?::[-a-z0-9$_.+!*\'(),;?&=%]++)? # password (optional)
|
||||
@
|
||||
)?
|
||||
|
||||
(?:
|
||||
# ip address
|
||||
\d{1,3}+(?:\.\d{1,3}+){3}+
|
||||
|
||||
| # or
|
||||
|
||||
# hostname (captured)
|
||||
(
|
||||
(?!-)[-a-z0-9]{1,63}+(?<!-)
|
||||
(?:\.(?!-)[-a-z0-9]{1,63}+(?<!-)){0,126}+
|
||||
)
|
||||
)
|
||||
|
||||
# port (optional)
|
||||
(?::\d{1,5}+)?
|
||||
|
||||
# path (optional)
|
||||
(?:/.*)?
|
||||
|
||||
$~iDx', $url, $matches))
|
||||
return FALSE;
|
||||
|
||||
// We matched an IP address
|
||||
if ( ! isset($matches[1]))
|
||||
return TRUE;
|
||||
|
||||
// Check maximum length of the whole hostname
|
||||
// http://en.wikipedia.org/wiki/Domain_name#cite_note-0
|
||||
if (strlen($matches[1]) > 253)
|
||||
return FALSE;
|
||||
|
||||
// An extra check for the top level domain
|
||||
// It must start with a letter
|
||||
$tld = ltrim(substr($matches[1], (int) strrpos($matches[1], '.')), '.');
|
||||
return ctype_alpha($tld[0]);
|
||||
}
|
||||
|
||||
}
|
3
includes/kohana/modules/codebench/classes/Codebench.php
Normal file
3
includes/kohana/modules/codebench/classes/Codebench.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Codebench extends Kohana_Codebench {}
|
@@ -0,0 +1,36 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* Codebench — A benchmarking module.
|
||||
*
|
||||
* @package Kohana/Codebench
|
||||
* @category Controllers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license.html
|
||||
*/
|
||||
class Controller_Codebench extends Kohana_Controller_Template {
|
||||
|
||||
// The codebench view
|
||||
public $template = 'codebench';
|
||||
|
||||
public function action_index()
|
||||
{
|
||||
$class = $this->request->param('class');
|
||||
|
||||
// Convert submitted class name to URI segment
|
||||
if (isset($_POST['class']))
|
||||
{
|
||||
throw HTTP_Exception::factory(302)->location('codebench/'.trim($_POST['class']));
|
||||
}
|
||||
|
||||
// Pass the class name on to the view
|
||||
$this->template->class = (string) $class;
|
||||
|
||||
// Try to load the class, then run it
|
||||
if (Kohana::auto_load($class) === TRUE)
|
||||
{
|
||||
$codebench = new $class;
|
||||
$this->template->codebench = $codebench->run();
|
||||
}
|
||||
}
|
||||
}
|
217
includes/kohana/modules/codebench/classes/Kohana/Codebench.php
Normal file
217
includes/kohana/modules/codebench/classes/Kohana/Codebench.php
Normal file
@@ -0,0 +1,217 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* Codebench — A benchmarking module.
|
||||
*
|
||||
* @package Kohana/Codebench
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license.html
|
||||
*/
|
||||
abstract class Kohana_Codebench {
|
||||
|
||||
/**
|
||||
* @var string Some optional explanatory comments about the benchmark file.
|
||||
* HTML allowed. URLs will be converted to links automatically.
|
||||
*/
|
||||
public $description = '';
|
||||
|
||||
/**
|
||||
* @var integer How many times to execute each method per subject.
|
||||
*/
|
||||
public $loops = 1000;
|
||||
|
||||
/**
|
||||
* @var array The subjects to supply iteratively to your benchmark methods.
|
||||
*/
|
||||
public $subjects = array();
|
||||
|
||||
/**
|
||||
* @var array Grade letters with their maximum scores. Used to color the graphs.
|
||||
*/
|
||||
public $grades = array
|
||||
(
|
||||
125 => 'A',
|
||||
150 => 'B',
|
||||
200 => 'C',
|
||||
300 => 'D',
|
||||
500 => 'E',
|
||||
'default' => 'F',
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Set the maximum execution time
|
||||
set_time_limit(Kohana::$config->load('codebench')->max_execution_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs Codebench on the extending class.
|
||||
*
|
||||
* @return array benchmark output
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// Array of all methods to loop over
|
||||
$methods = array_filter(get_class_methods($this), array($this, '_method_filter'));
|
||||
|
||||
// Make sure the benchmark runs at least once,
|
||||
// also if no subject data has been provided.
|
||||
if (empty($this->subjects))
|
||||
{
|
||||
$this->subjects = array('NULL' => NULL);
|
||||
}
|
||||
|
||||
// Initialize benchmark output
|
||||
$codebench = array
|
||||
(
|
||||
'class' => get_class($this),
|
||||
'description' => $this->description,
|
||||
'loops' => array
|
||||
(
|
||||
'base' => (int) $this->loops,
|
||||
'total' => (int) $this->loops * count($this->subjects) * count($methods),
|
||||
),
|
||||
'subjects' => $this->subjects,
|
||||
'benchmarks' => array(),
|
||||
);
|
||||
|
||||
// Benchmark each method
|
||||
foreach ($methods as $method)
|
||||
{
|
||||
// Initialize benchmark output for this method
|
||||
$codebench['benchmarks'][$method] = array('time' => 0, 'memory' => 0);
|
||||
|
||||
// Using Reflection because simply calling $this->$method($subject) in the loop below
|
||||
// results in buggy benchmark times correlating to the length of the method name.
|
||||
$reflection = new ReflectionMethod(get_class($this), $method);
|
||||
|
||||
// Benchmark each subject on each method
|
||||
foreach ($this->subjects as $subject_key => $subject)
|
||||
{
|
||||
// Prerun each method/subject combo before the actual benchmark loop.
|
||||
// This way relatively expensive initial processes won't be benchmarked, e.g. autoloading.
|
||||
// At the same time we capture the return here so we don't have to do that in the loop anymore.
|
||||
$return = $reflection->invoke($this, $subject);
|
||||
|
||||
// Start the timer for one subject
|
||||
$token = Profiler::start('codebench', $method.$subject_key);
|
||||
|
||||
// The heavy work
|
||||
for ($i = 0; $i < $this->loops; ++$i)
|
||||
{
|
||||
$reflection->invoke($this, $subject);
|
||||
}
|
||||
|
||||
// Stop and read the timer
|
||||
$benchmark = Profiler::total($token);
|
||||
|
||||
// Benchmark output specific to the current method and subject
|
||||
$codebench['benchmarks'][$method]['subjects'][$subject_key] = array
|
||||
(
|
||||
'return' => $return,
|
||||
'time' => $benchmark[0],
|
||||
'memory' => $benchmark[1],
|
||||
);
|
||||
|
||||
// Update method totals
|
||||
$codebench['benchmarks'][$method]['time'] += $benchmark[0];
|
||||
$codebench['benchmarks'][$method]['memory'] += $benchmark[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the fastest and slowest benchmarks for both methods and subjects, time and memory,
|
||||
// these values will be overwritten using min() and max() later on.
|
||||
// The 999999999 values look like a hack, I know, but they work,
|
||||
// unless your method runs for more than 31 years or consumes over 1GB of memory.
|
||||
$fastest_method = $fastest_subject = array('time' => 999999999, 'memory' => 999999999);
|
||||
$slowest_method = $slowest_subject = array('time' => 0, 'memory' => 0);
|
||||
|
||||
// Find the fastest and slowest benchmarks, needed for the percentage calculations
|
||||
foreach ($methods as $method)
|
||||
{
|
||||
// Update the fastest and slowest method benchmarks
|
||||
$fastest_method['time'] = min($fastest_method['time'], $codebench['benchmarks'][$method]['time']);
|
||||
$fastest_method['memory'] = min($fastest_method['memory'], $codebench['benchmarks'][$method]['memory']);
|
||||
$slowest_method['time'] = max($slowest_method['time'], $codebench['benchmarks'][$method]['time']);
|
||||
$slowest_method['memory'] = max($slowest_method['memory'], $codebench['benchmarks'][$method]['memory']);
|
||||
|
||||
foreach ($this->subjects as $subject_key => $subject)
|
||||
{
|
||||
// Update the fastest and slowest subject benchmarks
|
||||
$fastest_subject['time'] = min($fastest_subject['time'], $codebench['benchmarks'][$method]['subjects'][$subject_key]['time']);
|
||||
$fastest_subject['memory'] = min($fastest_subject['memory'], $codebench['benchmarks'][$method]['subjects'][$subject_key]['memory']);
|
||||
$slowest_subject['time'] = max($slowest_subject['time'], $codebench['benchmarks'][$method]['subjects'][$subject_key]['time']);
|
||||
$slowest_subject['memory'] = max($slowest_subject['memory'], $codebench['benchmarks'][$method]['subjects'][$subject_key]['memory']);
|
||||
}
|
||||
}
|
||||
|
||||
// Percentage calculations for methods
|
||||
foreach ($codebench['benchmarks'] as & $method)
|
||||
{
|
||||
// Calculate percentage difference relative to fastest and slowest methods
|
||||
$method['percent']['fastest']['time'] = (empty($fastest_method['time'])) ? 0 : ($method['time'] / $fastest_method['time'] * 100);
|
||||
$method['percent']['fastest']['memory'] = (empty($fastest_method['memory'])) ? 0 : ($method['memory'] / $fastest_method['memory'] * 100);
|
||||
$method['percent']['slowest']['time'] = (empty($slowest_method['time'])) ? 0 : ($method['time'] / $slowest_method['time'] * 100);
|
||||
$method['percent']['slowest']['memory'] = (empty($slowest_method['memory'])) ? 0 : ($method['memory'] / $slowest_method['memory'] * 100);
|
||||
|
||||
// Assign a grade for time and memory to each method
|
||||
$method['grade']['time'] = $this->_grade($method['percent']['fastest']['time']);
|
||||
$method['grade']['memory'] = $this->_grade($method['percent']['fastest']['memory']);
|
||||
|
||||
// Percentage calculations for subjects
|
||||
foreach ($method['subjects'] as & $subject)
|
||||
{
|
||||
// Calculate percentage difference relative to fastest and slowest subjects for this method
|
||||
$subject['percent']['fastest']['time'] = (empty($fastest_subject['time'])) ? 0 : ($subject['time'] / $fastest_subject['time'] * 100);
|
||||
$subject['percent']['fastest']['memory'] = (empty($fastest_subject['memory'])) ? 0 : ($subject['memory'] / $fastest_subject['memory'] * 100);
|
||||
$subject['percent']['slowest']['time'] = (empty($slowest_subject['time'])) ? 0 : ($subject['time'] / $slowest_subject['time'] * 100);
|
||||
$subject['percent']['slowest']['memory'] = (empty($slowest_subject['memory'])) ? 0 : ($subject['memory'] / $slowest_subject['memory'] * 100);
|
||||
|
||||
// Assign a grade letter for time and memory to each subject
|
||||
$subject['grade']['time'] = $this->_grade($subject['percent']['fastest']['time']);
|
||||
$subject['grade']['memory'] = $this->_grade($subject['percent']['fastest']['memory']);
|
||||
}
|
||||
}
|
||||
|
||||
return $codebench;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for array_filter().
|
||||
* Filters out all methods not to benchmark.
|
||||
*
|
||||
* @param string method name
|
||||
* @return boolean
|
||||
*/
|
||||
protected function _method_filter($method)
|
||||
{
|
||||
// Only benchmark methods with the "bench" prefix
|
||||
return (substr($method, 0, 5) === 'bench');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the applicable grade letter for a score.
|
||||
*
|
||||
* @param integer|double score
|
||||
* @return string grade letter
|
||||
*/
|
||||
protected function _grade($score)
|
||||
{
|
||||
foreach ($this->grades as $max => $grade)
|
||||
{
|
||||
if ($max === 'default')
|
||||
continue;
|
||||
|
||||
if ($score <= $max)
|
||||
return $grade;
|
||||
}
|
||||
|
||||
return $this->grades['default'];
|
||||
}
|
||||
}
|
16
includes/kohana/modules/codebench/config/codebench.php
Normal file
16
includes/kohana/modules/codebench/config/codebench.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
return array(
|
||||
|
||||
/**
|
||||
* The maximum execution time, in seconds. If set to zero, no time limit is imposed.
|
||||
* Note: http://php.net/manual/en/function.set-time-limit.php#84563
|
||||
*/
|
||||
'max_execution_time' => 0,
|
||||
|
||||
/**
|
||||
* Expand all benchmark details by default.
|
||||
*/
|
||||
'expand_all' => FALSE,
|
||||
|
||||
);
|
23
includes/kohana/modules/codebench/config/userguide.php
Normal file
23
includes/kohana/modules/codebench/config/userguide.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
return array(
|
||||
// Leave this alone
|
||||
'modules' => array(
|
||||
|
||||
// This should be the path to this modules userguide pages, without the 'guide/'. Ex: '/guide/modulename/' would be 'modulename'
|
||||
'codebench' => array(
|
||||
|
||||
// Whether this modules userguide pages should be shown
|
||||
'enabled' => TRUE,
|
||||
|
||||
// The name that should show up on the userguide index page
|
||||
'name' => 'Codebench',
|
||||
|
||||
// A short description of this module, shown on the index page
|
||||
'description' => 'Code benchmarking tool.',
|
||||
|
||||
// Copyright message, shown in the footer for this module
|
||||
'copyright' => '© 2008–2012 Kohana Team',
|
||||
)
|
||||
)
|
||||
);
|
76
includes/kohana/modules/codebench/guide/codebench/index.md
Normal file
76
includes/kohana/modules/codebench/guide/codebench/index.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Using Codebench
|
||||
|
||||
[!!] The contents of this page are taken (with some minor changes) from <http://www.geertdedeckere.be/article/introducing-codebench> and are copyright Geert De Deckere.
|
||||
|
||||
For a long time I have been using a quick-and-dirty `benchmark.php` file to optimize bits of PHP code, many times regex-related stuff. The file contained not much more than a [gettimeofday](http://php.net/gettimeofday) function wrapped around a `for` loop. It worked, albeit not very efficiently. Something more solid was needed. I set out to create a far more usable piece of software to aid in the everlasting quest to squeeze every millisecond out of those regular expressions.
|
||||
|
||||
## Codebench Goals
|
||||
|
||||
### Benchmark multiple regular expressions at once
|
||||
|
||||
Being able to compare the speed of an arbitrary amount of regular expressions would be tremendously useful. In case you are wondering—yes, I had been writing down benchmark times for each regex, uncommenting them one by one. You get the idea. Those days should be gone forever now.
|
||||
|
||||
### Benchmark multiple subjects at once
|
||||
|
||||
What gets overlooked too often when testing and optimizing regular expressions is the fact that speed can vastly differ depending on the subjects, also known as input or target strings. Just because your regular expression matches, say, a valid email address quickly, does not necessarily mean it will quickly realize when an invalid email is provided. I plan to write a follow-up article with hands-on regex examples to demonstrate this point. Anyway, Codebench allows you to create an array of subjects which will be passed to each benchmark.
|
||||
|
||||
### Make it flexible enough to work for all PCRE functions
|
||||
|
||||
Initially I named the module “Regexbench”. I quickly realized, though, it would be flexible enough to benchmark all kinds of PHP code, hence the change to “Codebench”. While tools specifically built to help profiling PCRE functions, like [preg_match](http://php.net/preg_match) or [preg_replace](http://php.net/preg_replace), definitely have their use, more flexibility was needed here. You should be able to compare all kinds of constructions like combinations of PCRE functions and native PHP string functions.
|
||||
|
||||
### Create clean and portable benchmark cases
|
||||
|
||||
Throwing valuable benchmark data away every time I needed to optimize another regular expression had to stop. A clean file containing the complete set of all regex variations to compare, together with the set of subjects to test them against, would be more than welcome. Moreover, it would be easy to exchange benchmark cases with others.
|
||||
|
||||
### Visualize the benchmarks
|
||||
|
||||
Obviously providing a visual representation of the benchmark results, via simple graphs, would make interpreting them easier. Having not to think about Internet Explorer for once, made writing CSS a whole lot more easy and fun. It resulted in some fine graphs which are fully resizable.
|
||||
|
||||
Below are two screenshots of Codebench in action. `Valid_Color` is a class made for benchmarking different ways to validate hexadecimal HTML color values, e.g. `#FFF`. If you are interested in the story behind the actual regular expressions, take a look at [this topic in the Kohana forums](http://forum.kohanaphp.com/comments.php?DiscussionID=2192).
|
||||
|
||||

|
||||
**Benchmarking seven ways to validate HTML color values**
|
||||
|
||||

|
||||
**Collapsable results per subject for each method**
|
||||
|
||||
## Working with Codebench
|
||||
|
||||
Codebench is included in Kohana 3, but if you need you [can download it](http://github.com/kohana/codebench/) from GitHub. Be sure Codebench is activated in your `application/bootstrap.php`.
|
||||
|
||||
Creating your own benchmarks is just a matter of creating a class that extends the Codebench class. The class should go in `classes/bench` and the class name should have the `Bench_` prefix. Put the code parts you want to compare into separate methods. Be sure to prefix those methods with `bench_`, other methods will not be benchmarked. Glance at the files in `modules/codebench/classes/bench/` for more examples.
|
||||
|
||||
Here is another short example with some extra explanations.
|
||||
|
||||
// classes/bench/ltrimdigits.php
|
||||
class Bench_LtrimDigits extends Codebench {
|
||||
|
||||
// Some optional explanatory comments about the benchmark file.
|
||||
// HTML allowed. URLs will be converted to links automatically.
|
||||
public $description = 'Chopping off leading digits: regex vs ltrim.';
|
||||
|
||||
// How many times to execute each method per subject.
|
||||
// Total loops = loops * number of methods * number of subjects
|
||||
public $loops = 100000;
|
||||
|
||||
// The subjects to supply iteratively to your benchmark methods.
|
||||
public $subjects = array
|
||||
(
|
||||
'123digits',
|
||||
'no-digits',
|
||||
);
|
||||
|
||||
public function bench_regex($subject)
|
||||
{
|
||||
return preg_replace('/^\d+/', '', $subject);
|
||||
}
|
||||
|
||||
public function bench_ltrim($subject)
|
||||
{
|
||||
return ltrim($subject, '0..9');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
And the winner is… [ltrim](http://php.net/ltrim). Happy benchmarking!
|
@@ -0,0 +1 @@
|
||||
## [Codebench]()
|
8
includes/kohana/modules/codebench/init.php
Normal file
8
includes/kohana/modules/codebench/init.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
// Catch-all route for Codebench classes to run
|
||||
Route::set('codebench', 'codebench(/<class>)')
|
||||
->defaults(array(
|
||||
'controller' => 'Codebench',
|
||||
'action' => 'index',
|
||||
'class' => NULL));
|
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
260
includes/kohana/modules/codebench/views/codebench.php
Normal file
260
includes/kohana/modules/codebench/views/codebench.php
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* Codebench — A benchmarking module.
|
||||
*
|
||||
* @package Kohana/Codebench
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license.html
|
||||
*/
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<title><?php if ($class !== ''): ?>
|
||||
<?php echo $class, ' · ' ?>
|
||||
<?php endif; ?>Codebench</title>
|
||||
|
||||
<style>
|
||||
/* General styles*/
|
||||
body { position:relative; margin:1em 2em; font:12px monaco,monospace; }
|
||||
h1 { font-size:24px; letter-spacing:-0.05em; }
|
||||
h2 { font-size:18px; letter-spacing:-0.1em; }
|
||||
input, code { font:inherit; }
|
||||
code { background:#e5e5e5; }
|
||||
caption { display:none; }
|
||||
|
||||
/* Form */
|
||||
#runner { margin-bottom:2em; }
|
||||
#runner input[type="text"] { letter-spacing:-0.05em; }
|
||||
|
||||
/* Expand/Collapse all */
|
||||
#toggle_all { position:absolute; top:0; right:0; margin:0; padding:0 4px; background:#000; font-size:18px; color:#fff; cursor:pointer; -moz-border-radius:2px; -webkit-border-radius:2px; }
|
||||
|
||||
/* Benchmark main graphs */
|
||||
#bench { margin:2em 0; padding:0; list-style:none; }
|
||||
#bench > li { margin:6px 0; }
|
||||
#bench h2 { position:relative; margin:0; padding:2px; background:#ccc; border:1px solid #999; cursor:pointer; -moz-border-radius:3px; -webkit-border-radius:3px; }
|
||||
#bench h2 > span { display:block; min-width:1px; height:33px; background:#fff; -moz-border-radius:2px; -webkit-border-radius:2px; }
|
||||
#bench h2 .method { position:absolute; top:6px; left:8px; text-shadow:0 -1px 0 rgba(255,255,255,0.6); }
|
||||
#bench h2 .method:before { content:'▸ '; }
|
||||
#bench h2 .percent { position:absolute; top:6px; right:6px; padding:0 4px; background:#000; color:#fff; font-weight:normal; letter-spacing:0; -moz-border-radius:2px; -webkit-border-radius:2px; }
|
||||
#bench h2:hover .method { left:10px; }
|
||||
#bench h2.expanded { margin:12px 0 0; -moz-border-radius-bottomleft:0; -moz-border-radius-bottomright:0; -webkit-border-bottom-left-radius:0; -webkit-border-bottom-right-radius:0; }
|
||||
#bench h2.expanded .method:before { content:'▾ '; }
|
||||
|
||||
/* Colorization of the bars */
|
||||
#bench .grade-A { background:#3f0; }
|
||||
#bench .grade-B { background:#fc0; }
|
||||
#bench .grade-C { background:#f90; }
|
||||
#bench .grade-D { background:#f60; }
|
||||
#bench .grade-E { background:#f30; }
|
||||
#bench .grade-F { background:#f00; }
|
||||
|
||||
/* Benchmark details */
|
||||
#bench > li > div { display:none; margin:0 0 12px; padding:0 0 2px; background:#eee; border:1px solid #999; border-top:0; -moz-border-radius-bottomleft:3px; -moz-border-radius-bottomright:3px; -webkit-border-bottom-left-radius:3px; -webkit-border-bottom-right-radius:3px; }
|
||||
#bench > li > div table { width:100%; background:#eee; border-collapse:collapse; }
|
||||
#bench > li > div th { padding:6px; background:#ddd url(data:image/gif;base64,R0lGODlhAQASALMAAMfHx8TExM7Oztvb29jY2NbW1tPT09DQ0MrKygAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABABIAAAQNMAQAEBLiHGNKIcQwRAA7) repeat-x 0 1px; text-align:left; }
|
||||
#bench > li > div td { padding:6px; border-top:1px solid #ccc; vertical-align:top; }
|
||||
#bench .numeric { padding-left:18px; text-align:right; }
|
||||
#bench .numeric span { position:relative; display:block; height:16px; }
|
||||
#bench .numeric span span { position:absolute; top:0; right:0; min-width:1px; background:#ccc; -moz-border-radius:2px; -webkit-border-radius:2px; }
|
||||
#bench .numeric span span span { top:0; right:0; background:none; }
|
||||
#bench tbody tr:hover { background:#fff; }
|
||||
#bench tbody tr.highlight { background:#ffc; }
|
||||
|
||||
/* Footer */
|
||||
#footer { margin-top:2em; padding-top:1em; border-top:1px solid #ccc; color:#999; }
|
||||
#footer a { color:inherit; }
|
||||
|
||||
/* Misc text styles */
|
||||
.alert { padding:0 0.5em; background:#900; font-weight:normal; color:#fff; -moz-border-radius:3px; -webkit-border-radius:3px; }
|
||||
.quiet { color:#999; }
|
||||
.help { cursor:help; }
|
||||
</style>
|
||||
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Insert "Toggle All" button
|
||||
var expand_all_text = '▸ Expand all';
|
||||
var collapse_all_text = '▾ Collapse all';
|
||||
$('#bench').before('<p id="toggle_all">'+expand_all_text+'</p>');
|
||||
|
||||
// Cache these selection operations
|
||||
var $runner = $('#runner');
|
||||
var $toggle_all = $('#toggle_all');
|
||||
var $bench_titles = $('#bench > li > h2');
|
||||
var $bench_rows = $('#bench > li > div > table > tbody > tr');
|
||||
|
||||
// Runner form
|
||||
$(':input:first', $runner).focus();
|
||||
$runner.submit(function() {
|
||||
$(':submit', this).attr('value', 'Running…').attr('disabled', 'disabled');
|
||||
$('.alert', this).remove();
|
||||
});
|
||||
|
||||
// Toggle details for all benchmarks
|
||||
$('#toggle_all').click(function() {
|
||||
if ($(this).data('expanded')) {
|
||||
$(this).data('expanded', false);
|
||||
$(this).text(expand_all_text);
|
||||
$bench_titles.removeClass('expanded').siblings().hide();
|
||||
}
|
||||
else {
|
||||
$(this).data('expanded', true);
|
||||
$(this).text(collapse_all_text);
|
||||
$bench_titles.addClass('expanded').siblings().show();
|
||||
}
|
||||
});
|
||||
|
||||
<?php if (Kohana::$config->load('codebench')->expand_all) { ?>
|
||||
// Expand all benchmark details by default
|
||||
$toggle_all.click();
|
||||
<?php } ?>
|
||||
|
||||
// Toggle details for a single benchmark
|
||||
$bench_titles.click(function() {
|
||||
$(this).toggleClass('expanded').siblings().toggle();
|
||||
|
||||
// Counts of bench titles
|
||||
var total_bench_titles = $bench_titles.length;
|
||||
var expanded_bench_titles = $bench_titles.filter('.expanded').length;
|
||||
|
||||
// If no benchmark details are expanded, change "Collapse all" to "Expand all"
|
||||
if (expanded_bench_titles == 0 && $toggle_all.data('expanded')) {
|
||||
$toggle_all.click();
|
||||
}
|
||||
// If all benchmark details are expanded, change "Expand all" to "Collapse all"
|
||||
else if (expanded_bench_titles == total_bench_titles && ! $toggle_all.data('expanded')) {
|
||||
$toggle_all.click();
|
||||
}
|
||||
});
|
||||
|
||||
// Highlight clicked rows
|
||||
$bench_rows.click(function() {
|
||||
$(this).toggleClass('highlight');
|
||||
// Highlight doubleclicked rows globally
|
||||
}).dblclick(function() {
|
||||
var nth_row = $(this).parent().children().index(this) + 1;
|
||||
if ($(this).hasClass('highlight')) {
|
||||
$bench_rows.filter(':nth-child('+nth_row+')').removeClass('highlight');
|
||||
}
|
||||
else {
|
||||
$bench_rows.filter(':nth-child('+nth_row+')').addClass('highlight');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--[if IE]><p class="alert">This page is not meant to be viewed in Internet Explorer. Get a better browser.</p><![endif]-->
|
||||
|
||||
<form id="runner" method="post" action="<?php echo URL::site('codebench') ?>">
|
||||
<h1>
|
||||
<input name="class" type="text" value="<?php echo ($class !== '') ? $class : 'Bench_' ?>" size="25" title="Name of the Codebench library to run" />
|
||||
<input type="submit" value="Run" />
|
||||
<?php if ( ! empty($class)) { ?>
|
||||
<?php if (empty($codebench)) { ?>
|
||||
<strong class="alert">Library not found</strong>
|
||||
<?php } elseif (empty($codebench['benchmarks'])) { ?>
|
||||
<strong class="alert">No methods found to benchmark</strong>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
</h1>
|
||||
</form>
|
||||
|
||||
<?php if ( ! empty($codebench)) { ?>
|
||||
|
||||
<?php if (empty($codebench['benchmarks'])) { ?>
|
||||
|
||||
<p>
|
||||
<strong>
|
||||
Remember to prefix the methods you want to benchmark with “bench”.<br />
|
||||
You might also want to overwrite <code>Codebench->method_filter()</code>.
|
||||
</strong>
|
||||
</p>
|
||||
|
||||
<?php } else { ?>
|
||||
|
||||
<ul id="bench">
|
||||
<?php foreach ($codebench['benchmarks'] as $method => $benchmark) { ?>
|
||||
<li>
|
||||
|
||||
<h2 title="<?php printf('%01.6f', $benchmark['time']) ?>s">
|
||||
<span class="grade-<?php echo $benchmark['grade']['time'] ?>" style="width:<?php echo $benchmark['percent']['slowest']['time'] ?>%">
|
||||
<span class="method"><?php echo $method ?></span>
|
||||
<span class="percent">+<?php echo (int) $benchmark['percent']['fastest']['time'] ?>%</span>
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<div>
|
||||
<table>
|
||||
<caption>Benchmarks per subject for <?php echo $method ?></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:50%">subject → return</th>
|
||||
<th class="numeric" style="width:25%" title="Total method memory"><?php echo Text::bytes($benchmark['memory'], 'MB', '%01.6f%s') ?></th>
|
||||
<th class="numeric" style="width:25%" title="Total method time"><?php printf('%01.6f', $benchmark['time']) ?>s</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<?php foreach ($benchmark['subjects'] as $subject_key => $subject) { ?>
|
||||
<tr>
|
||||
<td>
|
||||
<strong class="help" title="(<?php echo gettype($codebench['subjects'][$subject_key]) ?>) <?php echo HTML::chars(var_export($codebench['subjects'][$subject_key], TRUE)) ?>">
|
||||
[<?php echo HTML::chars($subject_key) ?>] →
|
||||
</strong>
|
||||
<span class="quiet">(<?php echo gettype($subject['return']) ?>)</span>
|
||||
<?php echo HTML::chars(var_export($subject['return'], TRUE)) ?>
|
||||
</td>
|
||||
<td class="numeric">
|
||||
<span title="+<?php echo (int) $subject['percent']['fastest']['memory'] ?>% memory">
|
||||
<span style="width:<?php echo $subject['percent']['slowest']['memory'] ?>%">
|
||||
<span><?php echo Text::bytes($subject['memory'], 'MB', '%01.6f%s') ?></span>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td class="numeric">
|
||||
<span title="+<?php echo (int) $subject['percent']['fastest']['time'] ?>% time">
|
||||
<span style="width:<?php echo $subject['percent']['slowest']['time'] ?>%">
|
||||
<span><?php printf('%01.6f', $subject['time']) ?>s</span>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<?php if ( ! empty($codebench['description'])) { ?>
|
||||
<?php echo Text::auto_p(Text::auto_link($codebench['description']), FALSE) ?>
|
||||
<?php } ?>
|
||||
|
||||
<?php // echo '<h2>Raw output:</h2>', Debug::vars($codebench) ?>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<p id="footer">
|
||||
Page executed in <strong><?php echo round(microtime(TRUE) - KOHANA_START_TIME, 2) ?> s</strong>
|
||||
using <strong><?php echo Text::widont(Text::bytes(memory_get_usage(), 'MB')) ?></strong> of memory.<br />
|
||||
<a href="http://github.com/kohana/codebench">Codebench</a>, a <a href="http://kohanaframework.org/">Kohana</a> module
|
||||
by <a href="http://www.geertdedeckere.be/article/introducing-codebench">Geert De Deckere</a>.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user