Live data from Hacker News

Print(“lol”) doubled the speed of my Go function

medium.com

11–20 of 130 posts

Re: Print(“lol”) doubled the speed of my Go function

#11
post #8

I'm a noob. Looking at the disasm: https://godbolt.org/z/766aPTPc3 It turns a CMOVQLT to a JLT. Is the blog saying CMOVQLT don't have branch predication? I don't get it.

Your disasm is for x86-64. The benchmarks in the blog were run on an M1 MacBook Pro, which is an ARM64.

Re: Print(“lol”) doubled the speed of my Go function

#12

Why is there a "continue" at all in the first code sample? Edit to add: does removing it make any difference?

According to the godot compiler explorer removing the `continue` makes no difference to the generated assembly.

https://godbolt.org/z/ds1raTYc9

https://godbolt.org/z/rbWsxM83b

The `print("lol")` output looks remarkably different.

https://godbolt.org/z/c3afrb6bG

Re: Print(“lol”) doubled the speed of my Go function

#13
post #7

In the Linux kernel, there are unlikely() and likely() macros which indicate to the compiler whether or not a condition is likely using __builtin_expect (which then influences the output assembly into producing code that should make the branch predictor do the right thing more of the time). Unfortunately, the issue here is that the performance depends on the input and so such hints wouldn't help (unless you knew a-pr…

It's nice using these to mark less-likely, but latency sensitive, paths, which is something that profiler guided optimization can't do.

Re: Print(“lol”) doubled the speed of my Go function

#14
post #9

Earlier quoted context omitted.

I'm in school, so this may be oversimplified, but if the processor/assembly code is predicting the next result, it gets the result faster. The processor only does this prediction with conditional branches. The extra if for printing or finding the min invoke the prediction with the accuracies stated.

> The processor only does this prediction with conditional branches This sounds... wrong? Unless ARM64 is designed in an absurd way? I'd love to see the full disassembly; something seems funny here. If it was x86 I would say it's a conditional move causing this, but I don't know what's going on on ARM.

It's interesting that you say conditional move here.

I am confused by this behaviour, and although I definitely don't know what the answer is here; the non-lol version does have a CSEL (https://developer.arm.com/documentation/dui0802/b/CSEL) which is totally missing from the lol version.

Non-lol https://godbolt.org/z/ds1raTYc9

lol https://godbolt.org/z/c3afrb6bG

Re: Print(“lol”) doubled the speed of my Go function

#15
post #8

I'm a noob. Looking at the disasm: https://godbolt.org/z/766aPTPc3 It turns a CMOVQLT to a JLT. Is the blog saying CMOVQLT don't have branch predication? I don't get it.

Your disasm is for x86-64. The benchmarks in the blog were run on an M1 MacBook Pro, which is an ARM64.

Sorry. My bad. But looking at ARM64 https://godbolt.org/z/YEjGKce1Y The difference is CSEL and BLT. The question still stands. Does CSEL have no branch predication?

Re: Print(“lol”) doubled the speed of my Go function

#16

Earlier quoted context omitted.

> The processor only does this prediction with conditional branches This sounds... wrong? Unless ARM64 is designed in an absurd way? I'd love to see the full disassembly; something seems funny here. If it was x86 I would say it's a conditional move causing this, but I don't know what's going on on ARM.

It's interesting that you say conditional move here. I am confused by this behaviour, and although I definitely don't know what the answer is here; the non-lol version does have a CSEL ( https://developer.arm.com/documentation/dui0802/b/CSEL ) which is totally missing from the lol version. Non-lol https://godbolt.org/z/ds1raTYc9 lol https://godbolt.org/z/c3afrb6bG

Ah there you go, that's the conditional move on ARM. Yeah, those are slow.

Re: Print(“lol”) doubled the speed of my Go function

#17

Earlier quoted context omitted.

It's interesting that you say conditional move here. I am confused by this behaviour, and although I definitely don't know what the answer is here; the non-lol version does have a CSEL ( https://developer.arm.com/documentation/dui0802/b/CSEL ) which is totally missing from the lol version. Non-lol https://godbolt.org/z/ds1raTYc9 lol https://godbolt.org/z/c3afrb6bG

Ah there you go, that's the conditional move on ARM. Yeah, those are slow.

Yeah, after reading the blog post I felt reasonably confident that this is a compiler bug (in terms of perf).

Hopefully someone with a deeper understanding can verify or discredit this here. I'm curious to see the fix for this (I assume it will generate a fix).

Re: Print(“lol”) doubled the speed of my Go function

#18

Earlier quoted context omitted.

Your disasm is for x86-64. The benchmarks in the blog were run on an M1 MacBook Pro, which is an ARM64.

Sorry. My bad. But looking at ARM64 https://godbolt.org/z/YEjGKce1Y The difference is CSEL and BLT. The question still stands. Does CSEL have no branch predication?

It appears so. https://developer.arm.com/documentation/102374/0101/Program-...

"So far, we have seen examples that use branches to handle decisions. The A64 instruction set also provides conditional select instructions. In many cases, these instructions can be used as an alternative to branches."

Seems CSEL is not a branch.

Re: Print(“lol”) doubled the speed of my Go function

#19
post #6

I read it and I still don't get it, can someone (re-)explain what the presence of the print() is doing that is helpful for branch prediction (or any other aspect of the CPU)? Update: It seems to be the conditional move, see https://news.ycombinator.com/item?id=37245325

I read it three or four times. It's never explained. If the print("lol") version has a branch-less-than, what does the regular version have? It must either be a branch or a conditional move, but we aren't shown that part of the assembly. You can't reach any conclusions about why one version is faster if you don't know what you're comparing to.

Re: Print(“lol”) doubled the speed of my Go function

#20

Earlier quoted context omitted.

Ah there you go, that's the conditional move on ARM. Yeah, those are slow.

Yeah, after reading the blog post I felt reasonably confident that this is a compiler bug (in terms of perf). Hopefully someone with a deeper understanding can verify or discredit this here. I'm curious to see the fix for this (I assume it will generate a fix).

Confused, why do you think this is a compiler bug? You should definitely expect a predictable branch to be faster than a conditional move, and the insertion of a conditional move in the original is totally sensible (albeit not intuitive if you haven't seen it).
Post reply on HN