Live data from Hacker News

How much do amd64 microarchitecture levels help in Go?

lemire.me

21–30 of 50 posts

Re: How much do amd64 microarchitecture levels help in Go?

#21

> That is a 43% reduction, and it is free: no source change, just a compiler flag. It's not entirely free; the cost is that the resulting binary will no longer run on processors that lack the instruction. Which, admittedly, is ≈2007 or older. But still! I have a 2012 CPU still in service, and as much as I'd love to obsolete it, gestures at the price tag of RAM these days . … a 2012 CPU is surprisingly competitive rel…

My main problem was that our hosting company offers cheap Linux servers, but with a shared CPU that even doesn't support v2. We pay more now, but you could still run into that problem.

Re: How much do amd64 microarchitecture levels help in Go?

#22

I think the more critical question is how well compiler writers can update the heuristics which identify the instruction sequences that benefit from the architectural features. Last I looked, Intel has several thousand intrinsics which must be explicitly invoked to make use of specific features. I suspect that heavily optimised code either uses intrinsics or carefully written assembler code.

Newer (relatively speaking) x86-64 instruction sets support many three-operand instructions, which are actually easier to use for compilers than instructions with overwritten source operands or hard register constraints. Pattern matching for instructions that do not have a direct C representation (such as NAND) is also pretty standard in compilers. Auto-vectorization is more tricky (especially when you want code to actually run faster …), but some of the new ISAs are impactful without it. And of course there are expanders for fixed-size memcpy and memset that can use wider vector instructions quite easily. Those operations are quite common.

Re: How much do amd64 microarchitecture levels help in Go?

#23
post #5

Earlier quoted context omitted.

I've long been surprised there isn't more multiversion stuff built right into every language compiler; I would have thought Intel would be very motivated to get more binaries lighting up the features they add to their expensive top line CPUs. But yeah no, on the whole cost of the checks and duplicated binary size aren't seen as worth it, so instead it's piecemeal implementations mostly in numeric packages like eigen…

> so instead it's piecemeal implementations mostly in numeric packages like eigen and lapack. Because that’s where the user-noticeable gains can be made. Using popcount in code you run once is going to shave off, maybe, 100 cycles. That isn’t worth the extra cycles of that approach. Also, FTA: “and arguably the whole scheme should be replaced by finer-grained feature detection” . Such feature detection would lead to…

POPCNT is an interesting example. Runtime dispatch (with a conditional branch) would actually make sense for it because it's comparatively difficult to implement from scratch. PDEP and PEXT might be similar (but I don't think compilers pattern-match for it, unlike POPCNT). AArch64 uses localized run-time dispatch extensively because LL/SC atomics are so very bad on current cores, but there isn't anything comparable in the x86-64 space (POPCNT isn't that frequent).

For many other things, like using a YMM register to copy a 32-byte struct or a variable shift, run-time dispatch just not make sense. You will only see a benefit if you generate this code unconditionally. For FMA, you wouldn't even get bit-identical output, leading to testing concerns.

Re: How much do amd64 microarchitecture levels help in Go?

#24
post #21

> That is a 43% reduction, and it is free: no source change, just a compiler flag. It's not entirely free; the cost is that the resulting binary will no longer run on processors that lack the instruction. Which, admittedly, is ≈2007 or older. But still! I have a 2012 CPU still in service, and as much as I'd love to obsolete it, gestures at the price tag of RAM these days . … a 2012 CPU is surprisingly competitive rel…

My main problem was that our hosting company offers cheap Linux servers, but with a shared CPU that even doesn't support v2. We pay more now, but you could still run into that problem.

It's likely this is a hypervisor misconfiguration. Either way, one has to wonder what kind of mitigations for cross-tenant leakage they are missing.

Re: How much do amd64 microarchitecture levels help in Go?

#25
post #14
post #9

Nothing, because this is a compiler question, not a language one.

One of Go's selling points is performance. Another is easy deployment on a lot of platforms. This post is interesting from that perspective. Edit: to address your literal remark: so even the title is correct, if you think of a programming language as more than its syntax.

Language !== Implementation, so no the title isn't correct.

Go's selling point is definitely not performance.

Re: How much do amd64 microarchitecture levels help in Go?

#26
post #5

Earlier quoted context omitted.

> so instead it's piecemeal implementations mostly in numeric packages like eigen and lapack. Because that’s where the user-noticeable gains can be made. Using popcount in code you run once is going to shave off, maybe, 100 cycles. That isn’t worth the extra cycles of that approach. Also, FTA: “and arguably the whole scheme should be replaced by finer-grained feature detection” . Such feature detection would lead to…

> Also, FTA: “and arguably the whole scheme should be replaced by finer-grained feature detection”. Such feature detection would lead to a combinatorial explosion of different binaries. the thread is about runtime detection tbf

Ok, then it will be an explosion of binary size, if you have several code blocks optimized for each architecture level - I'm not very familiar with the subject, but I imagine it would have to be relatively large chunks of code, otherwise the constant branching would eat up the speed advantage.

Re: How much do amd64 microarchitecture levels help in Go?

#27
post #24
post #21

Earlier quoted context omitted.

My main problem was that our hosting company offers cheap Linux servers, but with a shared CPU that even doesn't support v2. We pay more now, but you could still run into that problem.

It's likely this is a hypervisor misconfiguration. Either way, one has to wonder what kind of mitigations for cross-tenant leakage they are missing.

Or on purpose, because the CPUs with AVX are more expensive. Or historical: the hardware for this kind of service may have been old, and you can't tell people that if you buy today you get a processor with AVX, but tomorrow you may get one without. I haven't checked if they upgraded their low-cost options in a while.

Re: How much do amd64 microarchitecture levels help in Go?

#28
This measurement is very focused on bit-related instructions. A few months ago we did some work on our (RemObjects) toolchain, and it showed very similar results, where our published benchmarks were for floating point.[0] I did some rough internal measurements showing the same for integer-related instructions too.

The same conclusion: v2 as baseline, v3 where possible.

I'm really surprised it's not standard in every toolchain to support arch levels like this today.

Some compilers like Clang allow multiple arch versions in one binary, runtime dispatched. I would love to implement this in our toolchain too.

[0] Please forgive the SEO-style title, it's, well, to get search engines to recognise what's in the article: https://blogs.remobjects.com/2026/01/26/fast-math-in-six-lan...

Re: How much do amd64 microarchitecture levels help in Go?

#29
post #26

Earlier quoted context omitted.

> Also, FTA: “and arguably the whole scheme should be replaced by finer-grained feature detection”. Such feature detection would lead to a combinatorial explosion of different binaries. the thread is about runtime detection tbf

Ok, then it will be an explosion of binary size, if you have several code blocks optimized for each architecture level - I'm not very familiar with the subject, but I imagine it would have to be relatively large chunks of code, otherwise the constant branching would eat up the speed advantage.

These are usually pretty tight loops or constructs based on specific features.

An unspecialised popcnt is half the dozen instructions, for specialised versions it’s 4 implementations ranging from half a dozen to two dozen bytes.

Post reply on HN