Skip to content

Instantly share code, notes, and snippets.

@sanmai
Forked from mnpenner/startswith_benchmark.php
Last active June 7, 2016 07:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sanmai/e1e7556e5ec219a4166e072beb50cb2e to your computer and use it in GitHub Desktop.
Save sanmai/e1e7556e5ec219a4166e072beb50cb2e to your computer and use it in GitHub Desktop.
Various StartsWith implementations
<?php
/*
Run with all available processing power:
sudo nice -n -20 php startswith_benchmark.php | sort -h
Running with PHP 7.0.7-3 gives:
1.6±0.0014 msec - strncmp_startswith_shortcut
1.71±0.0014 msec - strncmp_startswith
1.78±0.0013 msec - substr_compare_startswith
1.84±0.0013 msec - substr_startswith
2.89±0.0025 msec - strpos_startswith
78.86±0.1781 msec - preg_match_startswith
*/
function substr_startswith($haystack, $needle) {
return substr($haystack, 0, strlen($needle)) === $needle;
}
function preg_match_startswith($haystack, $needle) {
return preg_match('~'.preg_quote($needle,'~').'~A', $haystack) > 0;
}
function substr_compare_startswith($haystack, $needle) {
return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
}
function strpos_startswith($haystack, $needle) {
return strpos($haystack, $needle) === 0;
}
function strncmp_startswith($haystack, $needle) {
return strncmp($haystack, $needle, strlen($needle)) === 0;
}
function strncmp_startswith_shortcut($haystack, $needle) {
return $haystack[0] === $needle[0]
? strncmp($haystack, $needle, strlen($needle)) === 0
: false;
}
// helper functions
function randstr($len) {
return substr(base64_encode(openssl_random_pseudo_bytes(ceil($len * 3 / 4))), 0, $len);
}
function avg_value($values) {
return array_sum($values) / sizeof($values);
}
function stddev_value($values) {
$mean = array_sum($values) / sizeof($values);
return (float) sqrt(array_reduce($values, function ($variance, $delay) use ($mean) {
return $variance + pow($delay - $mean, 2);
}, 0) / (sizeof($values)));
}
echo 'generating tests';
for ($i = 0; $i < 100000; $i += 1) {
if ($i % 1000 === 0) echo '.';
// 99,9% of random cases are failing
$test_cases[] = $randomCase = [
'haystack' => randstr(mt_rand(1, 7000)),
'needle' => randstr(mt_rand(1, 3000)),
];
// in real life not every call fails
// therefore we need to benchmark succeding calls too
$randomCase['haystack'] = $randomCase['needle'].$randomCase['needle'];
$test_cases[] = $randomCase;
}
echo "done!\n";
foreach ([
'substr_startswith',
'preg_match_startswith',
'substr_compare_startswith',
'strpos_startswith',
'strncmp_startswith',
'strncmp_startswith_shortcut',
] as $func) {
$times = [];
foreach($test_cases as $tc) {
$start = microtime(true);
$func($tc['haystack'], $tc['needle']);
$times[] = microtime(true) - $start;
}
// seconds to msec
$times = array_map(function ($seconds) {
return $seconds * 1000 * 1000;
}, $times);
$elapsed = round(array_sum($times), 4);
$avg = round(avg_value($times), 2);
$stddev = round(stddev_value($times), 2);
$stderr = round($stddev / sqrt(sizeof($times)), 4);
echo "{$avg}±{$stderr} msec - $func\n"; // (sigma $stddev total $elapsed)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment