Skip to content

Instantly share code, notes, and snippets.

@DarkSide666
Forked from abbadon1334/benchmark_loops.php
Created February 21, 2019 11:19
Show Gist options
  • Save DarkSide666/203074a0bb5532fda5a88f4683676549 to your computer and use it in GitHub Desktop.
Save DarkSide666/203074a0bb5532fda5a88f4683676549 to your computer and use it in GitHub Desktop.
benchmark of some loops in php
<?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