Simone Nigro Simone Nigro -4 years ago 75
PHP Question

PHP: understanding how branch predication works

After reading branch predication, I tried to understand how it works.

I wrote a basic test (below).

I think after the first loop php knows how array is structured and predicts the result of condition

($items[$i] <= 150000)
, but the time of second loop is the same as the first loop and it does not seem to benefit from branch predication.

Some questions:


  1. Maybe php does not support branch predication?

  2. Maybe I did not understand branch predication?

  3. My test is wrong/has other performance issues?



My test:

$count = 300000;
$items = array();
$found = 0;

// build array
for ($i = 0; $i <= $count; $i++) {
array_push($items, rand(0, $i));
}

// first loop with no predication benefit
// ------------------------------------
$time_start = microtime(true);

for($i = 0; $i <= $count; $i++) {
$found = ($items[$i] <= 150000) ? $found+1 : $found;
}

$time_end = microtime(true);
$time = $time_end - $time_start;
// ------------------------------------

echo "first loop\r\n";
echo 'Found:'. $found . "\r\n";
echo 'End:' . $time . "\r\n";

// reset counter
$found = 0;

// second loop with predication benefit
// ------------------------------------
$time_start = microtime(true);

for($i = 0; $i <= $count; $i++) {
$found = ($items[$i] <= 150000) ? $found+1 : $found;
}

$time_end = microtime(true);
$time = $time_end - $time_start;
// ------------------------------------

echo "second loop\r\n";
echo 'Found:'. $found . "\r\n";
echo 'End:' . $time . "\r\n";


output

first loop
Found:254052
End:0.093052864074707
second loop
Found:254052
End:0.092923879623413


http://codepad.org/Zni0b5rS

Answer Source

TL;TR

Branch prediction is a hardware feature.


The programming language which benefits from hardware features is C in this case. (PHP is written in C). Or truly spoken the machine code compiled from PHP's C sources. So yes, you already benefiting from branch prediction, but not it the way you might think of.

Benefiting from branch prediction happens on a far lower level. Basically you need to know that subsequent machine(!) commands are loaded into the CPU's pipeline before getting executed. But loading commands takes time.

If there is a conditional jump command to be executed, the subsequent commands in the pipeline might not being up to date any more if the condition evaluates to true, since the jump commands tells the CPU to go on loading commands from a complete different location in the (machine(!)) code - the jump target - in that case.

This means the CPU needs to flush the existing pipeline and refill it with commands starting a the jump target's location. If at the location there is another jump target the same would happen again. Note that conditional jumps are one of the most seen machine code commands.

That said, the performance of the command pipe line would basically not being sufficient.

What if the CPU might be smart and guess if the condition evaluates to true even before it get's evaluated? It could load commands from that jump target immediately after it loads a jump command into the pipeline. Note that loads is not equal to executes! Again, the CPU tries to guess that before the condition gets evaluated. If the guess should be wrong, the CPU will of course still need to flush the pipeline and refill it with the correct commands. But chances that flushing isn't necessary are better than compared to not guessing it.

There are multiple algorithms that implements the guess, from static to dynamic approaches which take into account what the code has been doing so far. They are pretty sophisticated and reach amazingly high success rates. Check back to Wikipedia, algorithms are explained there:

https://en.wikipedia.org/wiki/Branch_predictor


Returning back to your PHP code; Even the first loop might likely benefit from branch prediction.

Yes, it is obvious that both loops are doing the same and are therefore only needed to be executed once. However, PHP as an interpreted programming language is a far too high level to analyze such hardware features because too many things happen behind the scenes. (Probably even a task switch between the loops).

Btw, if you would have written comparable code in C, the C compiler would have likely opted this out. gcc for example can detect a lot of such situation. (Amazing!) However, this would already happen at compile time, even before run time.


If you are willing to analyze branch prediction, using the Assembler language and the GDB debugger can show it working in practice.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download