Implementing Value Speculation in OCaml
lortex.org
lortex.org
More generally, where can I read about this kind of thing to find out exactly what the speculative execution system is or isn't allowed to do? Arm documents the speculation barrier instruction, and I've found a paper which models speculative execution formally, but no actual design semantics.
Look for Address dependency in Arm: see e.g. https://developer.arm.com/documentation/ddi0406/c/Appendices... .
Note that the approach in the original post is also wrong if the GC sees the expected value, because it would try to access it regardless of whether the prediction is valid.
I'd also be interested in seeing how this performs when the data isn't allocated in one chunk (which seems to be the absolute best case scenario for this trick). Will it end up worse than the "naive" version due to all the branch mispredictions?
> Doesn't the unrolled version skip the speculation for three out of every four entries ?
It does, but what matters is removing data dependencies often enough. By only speculating once every 4 items, we're lowering the average number of instructions per iteration (from 16 to 7.7). In the meantime, and thanks to value speculation, the CPU is still able to start working on 4 next items while processing the current loop iteration.
Indeed it's not pure unrolling of the second function.
> Will it end up worse than the "naive" version due to all the branch mispredictions?
If the data is allocated randomly, then the next cell prediction will often be wrong. In turn, the branch predictor of the CPU will predict that the prediction is wrong and won't continue execution with the predicted value. So it's the same behavior as the original implementation. So the overhead is not due to branch misprediction, but to additional cycles needed to compute the predicted value.
If the data is allocated in chunks, then the optimization remains useful as the cost of rolling back the CPU pipeline is not that much (I tested with the original list cut in 10 chunks and it added 100ms caused by 100k additional branch misses).
That said I'd be a bit lost if I found the end result in any code that I was working with. I hope anyone using these sorts of tricks is also good at documentation and encapsulation.
I'd be curious what the machine code looks like.