Why is processing a sorted array faster than an unsorted array?
stackoverflow.com
stackoverflow.com
In case you think that the people here are intelligent and might have something to add, here is the previous discussion of this:
https://news.ycombinator.com/item?id=4637196 (119 comments)
For those complaining that it seems to be posted regularly, here are some of the previous submissions:
https://news.ycombinator.com/item?id=4167834 (366 days ago)
https://news.ycombinator.com/item?id=4170972 (365 days ago)
https://news.ycombinator.com/item?id=4185226 (362 days ago)
https://news.ycombinator.com/item?id=4355548 (324 days ago)
https://news.ycombinator.com/item?id=4964931 (185 days ago)
https://news.ycombinator.com/item?id=5167935 (143 days ago)
https://news.ycombinator.com/item?id=5666751 (52 days ago)
https://news.ycombinator.com/item?id=5679080 (50 days ago)
Edit: Looks like each URL is slightly different.
(https://news.ycombinator.com/item?id=5679080)
And it's not helpful that people link to various places on the SE page (the question, or one of the answers), rather than a canonical link to the page.
I've found architecture effects fairly hard to predict in real situations, with my level of knowledge. I think it's hard to reduce these to straightforward lessons. It's useful to know that things like branch mispredictions and cache misses are important, but you should probably not try to optimize for them until you've timed the loop and built up a good case for what's occurring. Most of the time, when I think I can make something faster that way, I rewrite the code and it's no faster.
One case where something did get faster was in a case where I had two large arrays, one containing indexes into the other, which contained data, and I needed to permute the data by the indexes and write it out to a file. Initially, the indexes were arranged so that the output was sequential, but the array accesses were random. I switched out the array of indexes with its inverse, which would access the data sequentially, but produce output in random order, which I captured in a new array before writing out. The second version was measurably faster. The lesson seems to be that loads benefit more from locality than stores. In the end, though, it only saved a fraction of a second, even with 100 million elements in the array. Unoptimized, it was already pretty fast, taking slightly over a second. It was nice, but I'm glad I didn't spend too much time on it.
I think this kind of optimization is somewhat like saving money by doing your own plumbing. It's usually not worth it unless you know what you're doing, or you can afford to spend lots of time.
Edit: Reading more of the comments, I found something useful that I didn't know. The ternary ?: operator generates a conditional move rather than a branch. So that's a viable solution, although it came out a little slower than the predictable branch.
.L11:
movl (%r12,%rdx,4), %eax ; load value of data[c] in eax
leal (%rsi,%rax), %ecx ; (sum is in rsi)
; add data[c] to sum, store in ecx
; yes, this is (ab)using the
; "load effective address" instruction as an
; "add a to b and store in c" instruction
cmpl $128, %eax ; compare data[c] to 128
cmovge %ecx, %esi ; if above comparison was true,
; set rsi (sum) to ecx, computed above
addq $1, %rdx ; c = c+1
.L9:
cmpq $134217727, %rdx ; this is the for end clause
jbe .L11
jmp .L12
In effect, it's adding data[c] to sum, storing it in a register and storing the result back in sum if data[c] was larger than 128, all with no jumps except for the loop itself and that jump is mispredicted exactly once. I don't see why java's JIT can't do the same.The branch in this example is essentially random and so pretty much impossible to predict. I would classify it as a pathological case. A modern predictor such as perceptron [1] or even the older tournament predictor [2] is extremely accurate for branches found in real benchmarks.
[1] http://www.cs.utexas.edu/~lin/papers/hpca01.pdf [2] http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-TN-36.pdf
PS. Sidenote about the P4, it achieved the highest SpecINT CPU score among all its contemporary processors so it wasn't the performance disaster some people make it out to be. It's worth noting that SpecINT CPU is has traditionally been the most challenging benchmark in terms of branch prediction requirements. SpecFP CPU for example is full of easy to predict loops.
It's a highly contrived example, and it's a little bit misleading.
HN does have a dupe detector and won't let an identical URL be posted a second time. But, as you can see in the above comments on this same page, even very slight differences are sufficient for it to allow the post through.
Anyway, I hope you keep posting items like this! If they're not sufficiently interesting and novel to enough people, they won't be upvoted. No harm.