-
-
Save DarkSide666/203074a0bb5532fda5a88f4683676549 to your computer and use it in GitHub Desktop.
benchmark of some loops in php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$a = function($array) { | |
$ret = []; | |
foreach($array as $item) | |
{ | |
$ret[] = $item; | |
} | |
return $ret; | |
}; | |
$b = function($array) { | |
$ret = []; | |
foreach($array as $key => $item) | |
{ | |
$ret[] = $item; | |
} | |
return $ret; | |
}; | |
$c = function($array) { | |
/** | |
* Note: The end of an array is indistinguishable from a boolean FALSE element. | |
* To properly traverse an array which may contain FALSE elements, see the foreach() function. | |
* To still use next() and properly check if the end of the array has been reached, | |
* verify that the key() is NULL. | |
*/ | |
$ret = []; | |
while(!is_null(key($array))) { | |
$ret[] = current($array);next($array); | |
} | |
return $ret; | |
}; | |
$d = function($array) { | |
$ret = []; | |
for($a=0;$a<count($array);$a++) { | |
$ret[] = $array[$a]; | |
}; | |
return $ret; | |
}; | |
$e = function($array) { | |
$ret = []; | |
$count = count($array); | |
for($a=0;$a<$count;$a++) { | |
$ret[] = $array[$a]; | |
}; | |
return $ret; | |
}; | |
$f = function($array) { | |
$ret = []; | |
$count = sizeof($array); | |
for($a=0;$a<$count;$a++) { | |
$ret[] = $array[$a]; | |
}; | |
return $ret; | |
}; | |
$argArrayKeyValue = []; | |
$argArrayWithArrayValue = []; | |
$argArrayWithArrayKeyValue = []; | |
for($x = 0; $x < 1000; $x++) | |
{ | |
$argArrayKeyValue[$x] = $x; | |
$argArrayWithArrayValue[$x] = [$x]; | |
$argArrayWithArrayKeyValue[$x] = [$x => $x]; | |
} | |
$tests = [ | |
'Test with Array simple : $a[$x] = $x' => $argArrayKeyValue, | |
'Test with Array simple : $a[$x] = [$x]' => $argArrayWithArrayValue, | |
'Test with Array simple : $a[$x] = [$x => $x]' => $argArrayWithArrayKeyValue, | |
]; | |
foreach($tests as $title => $array) | |
{ | |
echo '<h1>' . $title . '</h1>'; | |
$bm = new benchmark(); | |
$bm->_sample_output = 0; | |
$bm->show_differences = 1; // it will check the return value if is the same throw cycles | |
$bm->time_this('foreach:$val', $a, [$array]); | |
$bm->time_this('foreach:$key=>$val', $b, [$array]); | |
$bm->time_this('do...while+next', $c, [$array]); | |
$bm->time_this('for+count_in', $d, [$array]); | |
$bm->time_this('for+count_out', $e, [$array]); | |
$bm->time_this('for+sizeof_out', $f, [$array]); | |
$bm->html_summary(); | |
} | |
// https://github.com/scottchiefbaker/php-benchmark | |
class benchmark { | |
public $_sample_output = 0; // sample out in HTML summary | |
public $show_differences = 0; // Highlight if one test has diferent output than the others | |
public $test_seconds = 1; // Time to run each test | |
private $results = array(); // Array that will store the results | |
public function time_this($name, $func, $args = array()) { | |
$seconds = $this->test_seconds; | |
$count = 0; | |
$start = microtime(1); | |
$time = 0; | |
while ($time < $seconds) { | |
$ret = call_user_func_array($func,$args); | |
$time = microtime(1) - $start; | |
$count++; | |
} | |
$this->results['count'][$name] = intval($count / $seconds); | |
$this->results['return'][$name] = $ret; | |
} | |
public function summary($type = "") { | |
if ($type != "html" && php_sapi_name() === 'cli') { | |
$this->text_summary(); | |
} else { | |
$this->html_summary(); | |
} | |
} | |
public function text_summary() { | |
if (sizeof($this->results['count']) === 0) { | |
print "No results found"; | |
return false; | |
} | |
$use_color = 1; | |
if ($use_color) { | |
$red = "\033[38;5;9m"; | |
$white = "\033[38;5;15m"; | |
$blue = "\033[38;5;51m"; | |
$yellow = "\033[38;5;227m"; | |
$reset = "\033[0m"; | |
} else { | |
$red = ""; | |
$white = ""; | |
$blue = ""; | |
$yellow = ""; | |
$reset = ""; | |
} | |
$php_version = phpversion(); | |
print $white . "PHP Version: $blue$php_version$reset\n\n"; | |
arsort($this->results['count']); | |
$test_names = array_keys($this->results['count']); | |
$max_len = 0; | |
$total_len = 0; | |
foreach ($test_names as $name) { | |
// Minimum allowed length for alignment is 8 in text mode | |
$len = strlen($name); | |
if ($len < 8) { | |
$len = 8; | |
} | |
$total_len += $len; | |
if (strlen($name) > $max_len) { | |
$max_len = strlen($name); | |
} | |
} | |
############################################## | |
print str_repeat(" ",$max_len + 4); // Indent | |
$pad_names = $test_names; | |
foreach ($pad_names as &$i) { | |
$i = sprintf("$yellow%8s$reset",$i); | |
} | |
print join(" | ",$pad_names) . "\n"; | |
// The length of the bar is the total length of the test names, | |
// plus the " | " between each word test pair, | |
// plus four because there are two spaces at the start and end | |
$additional = (sizeof($test_names) - 1) * 3; | |
$bar = str_repeat(" ",$max_len + 2) . "+" . str_repeat("-",$total_len + $additional + 2) . "+\n"; | |
print $bar; | |
foreach($test_names as $y_name) { | |
printf(" $yellow%{$max_len}s$reset |",$y_name); | |
foreach ($test_names as $x_name) { | |
$x_val = $this->results['count'][$x_name]; | |
$y_val = $this->results['count'][$y_name]; | |
$percent = round(($y_val / $x_val) * 100,2) . "%"; | |
$x_name = sprintf("%8s",$x_name); | |
$col_width = strlen($x_name) + 1; | |
if ($y_val === $x_val) { | |
$percent = "N/A"; | |
printf("$red%{$col_width}s$reset |",$percent); | |
} else { | |
printf("$white%{$col_width}s$reset |",$percent); | |
} | |
} | |
print "\n"; | |
} | |
print $bar; | |
print "\n"; | |
$max_len += 1; | |
$expected_results = reset($this->results['return']); | |
//print_r($this->results['count']); | |
foreach($test_names as $name) { | |
$count = $this->results['count'][$name]; | |
$ret = $this->results['return'][$name]; | |
if ($this->_sample_output) { | |
printf(" %s = %s iterations per second\n",$name,number_format($count)); | |
if ($this->show_differences && ($ret !== $expected_results)) { | |
print " ** Return value from this function differs from the first test **\n"; | |
} | |
$print_r_output = trim(print_r($ret,true)); | |
$print_r_output = preg_replace("/^/m"," ",$print_r_output); | |
print " Sample output: \n$print_r_output\n\n"; | |
} else { | |
printf("%{$max_len}s = %s iterations per second\n",$name,number_format($count)); | |
} | |
} | |
print "\n"; | |
} | |
public function html_summary() { | |
if (sizeof($this->results['count']) === 0) { | |
print "<div>No results found</div>"; | |
return false; | |
} | |
arsort($this->results['count']); | |
$tests = array_keys($this->results['count']); | |
array_unshift($tests,' '); | |
$first = 1; | |
$php_version = phpversion(); | |
$out = "<h2>PHP Version: $php_version</h2>"; | |
$header_color = '#CCE6FF'; | |
$out .= '<table style="border-collapse: collapse; border: 1px solid black; width: 100%;">'; | |
$x = 0; | |
foreach ($tests as $name) { | |
$out .= "<tr>"; | |
// If it's the first row, output all the headers | |
if ($first) { | |
foreach ($tests as $i) { | |
$out .= '<td style="padding: 5px; white-space: nowrap; text-align: center; font-weight: bold; background-color: '.$header_color.'; border: 1px solid black; width: 10em;">'.$i.'</td>'; | |
} | |
$first = 0; | |
// It's not the first row so loop through outputting each data cell | |
} else { | |
$column = 0; | |
$y = 0; | |
foreach ($tests as $i) { | |
// If it's the first column, it's the row header (on the left) | |
if ($column == 0) { | |
$content = $tests[$x + 1]; | |
$color = $header_color; | |
$align = 'right'; | |
$fw = 'bold'; | |
$x++; | |
} else { | |
$y++; | |
$x_name = $tests[$x]; | |
$y_name = $tests[$y]; | |
$a = $this->results['count'][$x_name]; | |
$b = $this->results['count'][$y_name]; | |
$percentage = sprintf("%.2f%%",($a / $b) * 100); | |
$color = 'white'; | |
$align = 'center'; | |
$fw = 'normal'; | |
// Row/Column are the same so we output n/a | |
if ($x === $y) { | |
$color = "#FF9999"; | |
$content = "<b>n/a</b>"; | |
// It's a legit data point | |
} else { | |
$content = "$percentage"; | |
} | |
} | |
// Output each data cell | |
$out .= '<td style="padding: 5px; white-space: nowrap; background-color: '.$color.'; font-weight: '.$fw.'; text-align: '.$align.'; border: 1px solid black; width: 10em;">'.$content.'</td>'; | |
$column++; | |
} | |
} | |
$out .= "</tr>"; | |
} | |
$out .= "</table>"; | |
$out .= "<br />"; | |
$slowest = min($this->results['count']); | |
$fastest = max($this->results['count']); | |
$expected_results = reset($this->results['return']); | |
$out .= "<table>"; | |
foreach ($this->results['count'] as $test => $speed) { | |
$ret = $this->results['return'][$test]; | |
$speed_str = number_format($speed); | |
$out .= '<tr><td style="padding: 1px 3px; text-align: right;"><b>'.$test.':</b></td><td style="padding: 0 3px;">'.$speed_str.' iterations per second'; | |
if ($this->show_differences && ($ret !== $expected_results)) { | |
$out .= '<div style="margin: 0 0 1em 2em; "><span style="color: red;"><b>!!!</b></span> Return value from this function differs from the first test</div>'; | |
} | |
if ($this->_sample_output) { | |
$out .= '<div style="margin: 0 0 1em 2em; "><b>Sample output:</b> ' . print_r($ret,true) . '</div>'; | |
} | |
$out .= "</td></tr>"; | |
} | |
$out .= "</table>"; | |
print $out; | |
} | |
public function reset() { | |
$this->results = array(); | |
} | |
} // End of class |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment