Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/go: GOAMD64=local to compile for local machine #60338

Open
Jorropo opened this issue May 22, 2023 · 17 comments
Open

cmd/go: GOAMD64=local to compile for local machine #60338

Jorropo opened this issue May 22, 2023 · 17 comments

Comments

@Jorropo
Copy link
Member

Jorropo commented May 22, 2023

Rational:

I am using go install to deploy code to a cluster since the go compiler compiles really fast and this save me from having to manage building and distributing binaries.
It would be nice if I could also take advantage of the small performance gain of newer instructions sets available with GOAMD64, v2 and above however my cluster is made of heterogeneous machines and CPUs which not all support the latest features making it impossible or sub optimal to hardcode a level in my deploy script.


Proposal:

Add GOAMD64=local level to the toolchain, the toolchain will at compile-time find what would be the highest compatible micro-architecture level of the compiling host's CPU and compile the binary as usual using the equivalent microarchitecture level.
Thus running GOAMD64=local go build . (or other building command) on a compiling host that supports at most GOAMD64=v2 will produce an identical result as running GOAMD64=v2 go build ., same for all architecture levels on CPU that would support at most thoses respectively.

If a command of the toolchain that might be GOAMD64 dependent for results is invoked with GOAMD64=local while the toolchain is built with runtime.GOARCH != "amd64" the invocation fails. (go install, go build ... but not things like go env or go help)

I am not proposing that GOAMD64=local become defaults, just that it exists, by default the toolchain will continue to emit GOAMD64=v1 for GOARCH=amd64 binaries (even for go install as spuriously changing the micro architecture level invalidates different level build caches which would make a go build . shortly followed by go install . much slower).

@gopherbot gopherbot added this to the Proposal milestone May 22, 2023
@seankhliao
Copy link
Member

Isn't this already somewhat the case?

The Go toolchain may also generate newer instructions, but guarded by dynamic checks to ensure they're only executed on capable processors. For example, with GOAMD64=v1, math/bits.OnesCount will still use the POPCNT instruction if CPUID reports that it's available. Otherwise, it falls back to a generic implementation.

@Jorropo
Copy link
Member Author

Jorropo commented May 22, 2023

@seankhliao this would happen at compile time allowing the compiler to omit the dynamic check, the thing you linked compiles to a runtime check:
https://godbolt.org/z/8az84vv6x (left side is GOAMD64=v1, right side is GOAMD64=v3)

Note: this already exists, however you have to precisely tell the compiler which level you are targeting, what I am asking for is a level that is whatever best the current host supports.

@Jorropo
Copy link
Member Author

Jorropo commented May 22, 2023

FWIW gcc and clang have the same feature with -march=native.

@ianlancetaylor
Copy link
Contributor

CC @golang/runtime

@apparentlymart
Copy link

When I first read this I reached the same conclusion as @seankhliao that this behavior is already the default, but I think both of us misunderstood what you were proposing.

I think what's implied in your proposal is that you want "native" to mean "whatever architecture is available on the system where the compiler is running", because you assume that the computer where the program will eventually run will either be the same computer or will have an identical CPU. Is that right?

I think others typically build one binary and ship it to many different servers to run, and so the runtime detection is what they want. It sounds like you are instead planning to build and run the executables on the same computer, and so you're intending to ask the compiler to assume that's true and look for opportunities to optimize based on what it can learn about the CPU that's running the compiler.

@Jorropo
Copy link
Member Author

Jorropo commented May 22, 2023

@apparentlymart exact, I'll try adding "the compiler will ..." to the proposal hopping to make it clearer.

Maybe if I just described the proposal as GOAMD64=local go build do like clang -march=native it would have helped more.
(actually they are slightly different because the clang backend is more granular than v1, v2, v3, v4, here this limits to the microarchitecture compilation support already existing)

@ianlancetaylor
Copy link
Contributor

Just a note that if we do this for GOAMD64 we should presumably also do it for the GO${GOARCH} environment variables.

@mvdan
Copy link
Member

mvdan commented May 23, 2023

Given that GOAMD64 can really help in some cases like -race being ~15% faster with v3 (https://go-review.googlesource.com/c/go/+/444396), I'd like to make use of it in CI to run go test -race ./... as well. I had thought about using GOAMD64=v3, but that assumes a little too much about what CPU the shared CI machine is using. GOAMD64=native would be an easier alternative.

@rsc
Copy link
Contributor

rsc commented May 24, 2023

This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group

@rsc rsc changed the title proposal: cmd/go: GOAMD64=native proposal: cmd/go: GOAMD64=native May 24, 2023
@rsc rsc changed the title proposal: cmd/go: GOAMD64=native proposal: cmd/go: GOAMD64=local to compile for local machine May 25, 2023
@rsc
Copy link
Contributor

rsc commented May 25, 2023

According to https://developers.google.com/style/inclusive-documentation#features-and-users we should avoid "socially-charged terms" including "native". I have retitled this to GOAMD64=local (as in the local machine), which matches other uses of local in the Go toolchain such as GOTOOLCHAIN=local and the "local package" concept in the compiler and is, at least to me, clearer anyway. (Perhaps GOAMD64=native would mean the original x86 instructions, analogous to "native species", something "native to x86". If you haven't heard of GCC's -march=native, the fact that native is machine-specific is not clear. Local at least evokes something about the local machine.)

Now back to technical discussion...

@arp242
Copy link

arp242 commented May 30, 2023

Another point in favour of this proposal is that it's not so easy to figure out which "level" your CPU supports; checking Wikipedia I see stuff like "CMPXCHG16B" for v2, but I don't see that in /proc/cpuinfo (looking it up, it's included in all 64bit CPUs, but that's not very obvious). My 2021 laptop CPU also doesn't include AVX (it's a cheap Celeron), so "circa 2015: Haswell and Excavator" isn't quite as simple either.


Another way to solve this might be something like a go tool arch or go tool arch local command; then you can do GOAMD64=$(go tool arch) or even GOAMD64=$(ssh myserver 'go tool arch').

One of the nice things about this is that you can easily see what's being selected. You can check this after the build with go version -m my-go-bin and check the build GOAMD64 line, but this seems a more convenient – it just makes things a bit less opaque which can be useful when compiling for another machine (e.g. "what GOAMD64 does the server I'm compiling for support?") It might also be useful for some scripts or other things.

@rsc
Copy link
Contributor

rsc commented May 31, 2023

It would be nice if "go version -m" showed the real GOAMD64 not local.
Probably 'go env GOAMD64' needs to say local.
Some way to interrogate the meaning of local would be nice.

@rsc
Copy link
Contributor

rsc commented Jun 7, 2023

We should add the sub-arch values to the 'context' struct in go list, so that you can run
go list -f '{{context.GOAMD64}}'.

@rsc
Copy link
Contributor

rsc commented Jun 7, 2023

Based on the discussion above, this proposal seems like a likely accept.
— rsc for the proposal review group

@Jorropo
Copy link
Member Author

Jorropo commented Jun 7, 2023

@rsc does the likely accept also includes other architectures like GOARM or just GOAMD64 ?

@rsc
Copy link
Contributor

rsc commented Jun 14, 2023

@Jorropo, all the architectures.

@rsc
Copy link
Contributor

rsc commented Jun 14, 2023

No change in consensus, so accepted. 🎉
This issue now tracks the work of implementing the proposal.
— rsc for the proposal review group

@rsc rsc changed the title proposal: cmd/go: GOAMD64=local to compile for local machine cmd/go: GOAMD64=local to compile for local machine Jun 14, 2023
@rsc rsc modified the milestones: Proposal, Backlog Jun 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Accepted
Development

No branches or pull requests

8 participants