>gcc has __builtin_expect_with_probability(cond, 0, 0.5) but it does nothing (tested v10). ↩ I wonder what could possibly be the use of this builtin. Branch prediction varies enough between different processors that it seems unlikely that anything useful could be done with a fine-grained probability estimate.
Presumably it’s not about matching the dynamic branch prediction estimate but rather exploiting static (or profile-provided) information to assist other optimizations. Inlining seems like a natural application: Inlining is perhaps the most critical optimization to get right, and getting it right is a complex balance of frequency of use vs. added code bloat and associated further optimization cost. Having more than on…
Fastest branchless binary search
101–110 of 155 posts
Re: Fastest branchless binary search
#102 | Benchmark | gcc | clang | clang -cmov |
|-----------|------|-------|-------------|
| slow u32 | 23.4 | 46.7 | 45.8 |
| fast u32 | 18.1 | 19.8 | 31.4 |
The numbers are nanoseconds/bsearch on a 100mb uint32 array. Seem to me that clang (15.0.7) is just much worse at optimizing this particular piece of code than gcc (13.2.1). You can see the assembly here https://godbolt.org/z/cbx5Kdjs6. The gcc assembly looks way cleaner to me.Re: Fastest branchless binary search
#103Earlier quoted context omitted.
> Also, what's wrong with C? Oodles and oodles of undefined behaviour, for example. C ain't clean.
Nah, thanks to CompCert[1] C actually has one of the highest quality and most predictable compilers. [1] https://compcert.org/
All I know is that it tries to ensure that the behavior of the program is the same as the input, meaning that the compiler itself does not have bugs. But how does that actually interact with undefined behavior in the language? What happens to an array out of bounds?
And what are the limitations imposed, since it only works on a subset of the C language?
It seems unlikely that I could just switch compilers and suddenly have a safe program written in C.
Re: Fastest branchless binary search
#104Every time I see people trying to eliminate branches, I wonder, do we realize that having long pipelines where a branch misprediction stalls the pipeline is not actually a necessary part of architecture? The pipeline is long because we do lots of analysis and translation on the fly, just in time, which could easily be done in most cases ahead of time, as it's not a very stateful algorithm. This is how Transmeta Cruso…
> The pipeline is long because we do lots of analysis and translation on the fly, just in time, which could easily be done in most cases ahead of time, as it's not a very stateful algorithm. You're going down the wrong path, again, as Intel did with Itanium. We have pipelines because CPUs are performing Tomasulo's algorithm at runtime, because there are 10 pipelines in practice (for Intel systems), and all can be run…
In the "theLoop" example, say the first load misses L1 and L2 cache and takes needs 40 cycles to load.
AMD's Zen 4 has enough resources to issue about 64 iterations of "theLoop:" all before that first load needs to complete. With the micro op cache, it can probably issue those 64 loop iterations in about 35 cycles.
Zen 4 has enough resources to start all 64 loads early, so they run in parallel.
Who cares if there is a branch mispredict and it you actually needed to do only 16 iterations of "theLoop"? In this example, the loop length isn't dependant on any of the loads so the CPU can actually finish executing the "add ecx, 4; cmp max; jnz theLoop;" instructions of the first 16 iterations of the "theLoop". And then detect the mispredict, flush the pipeline and load the correct branch location, all before the 40 cycles it takes for that first load to complete.
------
It's just absolutely insane. No short pipeline without a branch predictor could possibly compete.
Re: Fastest branchless binary search
#105Every time I see people trying to eliminate branches, I wonder, do we realize that having long pipelines where a branch misprediction stalls the pipeline is not actually a necessary part of architecture? The pipeline is long because we do lots of analysis and translation on the fly, just in time, which could easily be done in most cases ahead of time, as it's not a very stateful algorithm. This is how Transmeta Cruso…
> as it's not a very stateful algorithm It might be stateless, but it depends on many things unknown at compile time. One of them is the input data being processed. Binary search is exactly that, compiler don’t know at which position the result will be found. Another one is micro-architecture, most notably cache hierarchy, and composition of EUs inside codes. If you switch to ISA with instructions resembling the micr…
> It might be stateless, but it depends on many things unknown at compile time.
> One of them is the input data being processed. Binary search is exactly that, compiler don’t know at which position the result will be found.
Are you and 3cats-in-a-coat are talking about the same "it"? I think they're talking about the work that requires such a long pipeline [1], as they've stated that doing more ahead of time would reduce the length of the pipeline and thus importance of accurate branch prediction. You are talking about...the branch predictor? the application's algorithm being executed (binary search in this case)?
[1] my CPU microarchitectural knowledge isn't that good; I have only the vaguest idea of what that is. Register renaming / data dependency analysis / instruction scheduling, maybe? translation to micro-ops? other things? don't know!
Re: Fastest branchless binary search
#106Earlier quoted context omitted.
I believe this happens because branch prediction lets you pipeline multiple simultaneous comparisons, and rewind whenever the branch predictor is wrong (about half the time for truly random data and inputs). The CMOV approach blocks after each comparison function due to the data dependency. On average, you're doing two comparisons at a time with branches, and one with CMOV, so when comparison time is greater than bra…
Switching to an N-way search (for N>2) could help extract the lost parallelism. At the cost of touching more cachelines though, so it is not necessarily a win.
Re: Fastest branchless binary search
#107Re: Fastest branchless binary search
#108How can you call it branchless if it has "while (length > 0) {"
Re: Fastest branchless binary search
#109There is a data dependency: until I read the middle index, I can't tell if I want to search the data in the upper section or the lower section. I can speculate and issue reads to both. That would fix the dependency, but create more memory traffic. Is this the right trade-off?
What do you want? Removing branches is not it.
Re: Fastest branchless binary search
#110I don't get it. The problem with binary search and branches is not the branches themselves, it's the fact that until you have done the comparison, you don't know which memory location in the array to fetch next. It doesn't matter if you use branches or anything else, the question is what do you want the processor to do? There is a data dependency: until I read the middle index, I can't tell if I want to search the da…