|
<?php |
|
error_reporting(E_ALL); |
|
ini_set('display_errors', true); |
|
|
|
/** |
|
* Benchmark blowfish execution time with different #rounds. |
|
* @author Tom Hennigan <[email protected]> |
|
* @date 24-12-2012 |
|
*/ |
|
|
|
$test = function ($rounds) { |
|
// We use a static salt to avoid benchmarking the RNG as well. |
|
$notSoRandomSalt = 'OMbSIk2dfA0cY0p.cAGMje'; |
|
$hashStr = sprintf('$2a$%02d$%s', $rounds, $notSoRandomSalt); |
|
return crypt('testPassword', $hashStr); |
|
}; |
|
|
|
// We could go up to 31, but above 20 the hashes take > 1min to compute on |
|
// modern hardware, so aren't particuarly practical in most applications. |
|
$testParams = range(4, 20); |
|
|
|
foreach ($testParams as $testParam) { |
|
$times = array(); |
|
|
|
if (!is_array($testParam)) { |
|
// Single arg to test, wrap for call_user_func_array. |
|
$testParam = array($testParam); |
|
} |
|
|
|
// Bench once to estimate number of tests to take. |
|
$start = microtime(true); |
|
call_user_func_array($test, $testParam); |
|
$taken = microtime(true) - $start; |
|
$times[] = $taken; |
|
|
|
// 100 times or < 5s per test. |
|
$maxExecutionTime = 5; |
|
if ($taken > $maxExecutionTime) { |
|
$iters = 1; |
|
} else { |
|
// If we're going to take the mean then work out how many iterations. |
|
$iters = min(100, $maxExecutionTime / $taken); |
|
for ($i = 1; $i < $iters; $i++) { |
|
$start = microtime(true); |
|
call_user_func_array($test, $testParam); |
|
$taken = microtime(true) - $start; |
|
$times[] = $taken; |
|
} |
|
} |
|
|
|
$meanTime = array_sum($times) / count($times); |
|
printf("%s rounds mean (from %d iters): %.5fs per call (~%.2f hashes/s)\n", implode(',', $testParam), $iters, $meanTime, 1 / $meanTime); |
|
} |