What version of Go are you using (go version
)?
$ go version go version go1.25rc2 windows/amd64
Does this issue reproduce with the latest release?
Not on released 1.24.x or earlier
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env set AR=ar set CC=gcc set CGO_CFLAGS=-O2 -g set CGO_CPPFLAGS= set CGO_CXXFLAGS=-O2 -g set CGO_ENABLED=0 set CGO_FFLAGS=-O2 -g set CGO_LDFLAGS=-O2 -g set CXX=g++ set GCCGO=gccgo set GO111MODULE= set GOAMD64=v1 set GOARCH=amd64 set GOAUTH=netrc set GOBIN= set GOCACHE=C:\Users\Christ910185\AppData\Local\go-build set GOCACHEPROG= set GODEBUG= set GOENV=C:\Users\Christ910185\AppData\Roaming\go\env set GOEXE=.exe set GOEXPERIMENT= set GOFIPS140=off set GOFLAGS= set GOGCCFLAGS=-m64 -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\CHRIST~1\AppData\Local\Temp\go-build45565215=/tmp/go-build -gno-record-gcc-switches set GOHOSTARCH=amd64 set GOHOSTOS=windows set GOINSECURE= set GOMOD=NUL set GOMODCACHE=C:\Users\Christ910185\go\pkg\mod set GONOPROXY= set GONOSUMDB= set GOOS=windows set GOPATH=C:\Users\Christ910185\go set GOPRIVATE= set GOPROXY=https://proxy.golang.org,direct set GOROOT=C:\Users\Christ910185\lang\go\go1.25rc2 set GOSUMDB=sum.golang.org set GOTELEMETRY=off set GOTELEMETRYDIR=C:\Users\Christ910185\AppData\Roaming\go\telemetry set GOTMPDIR= set GOTOOLCHAIN=auto set GOTOOLDIR=C:\Users\Christ910185\lang\go\go1.25rc2\pkg\tool\windows_amd64 set GOVCS= set GOVERSION=go1.25rc2 set GOWORK= set PKG_CONFIG=pkg-config
What did you do?
Greatly increased compile time for programs of a certain form. Git bisect traced the performance regression to commit ed24bb4e This proggie below shows the pattern - expanding the main() function with copies of the canonical line shows the performance lag in "go build" This program as written below (N=2) runs fine in go play, but if expanded to ~4000 lines by repeating the line in the main() function, it only runs in go1.24, times out in build using Go development version in go.dev/play
here is the "small" (N=2) version, see main() function
// "go build" of this program takes much longer using go1.25rc1 (and rc2) than using go <= 1.24.4. // git bisect identified this commit as the cause, and reverting it cures the problem: // // --- // commit ed24bb4e6047890af272733c5a8bdcc43834e517 // Date: Wed Feb 12 18:55:04 2025 -0500 // // cmd/compile/internal/escape: propagate constants to interface conversions to avoid allocs // --- // // The problem is also cured by setting GOTOOLCHAIN=go1.24.4 // Procedure: go clean -cache ; go build program.go ; alter program.go source code ; time go build program.go // // Build times in Win 11 on my machine (Intel i7-1365U, 1.80 GHz, 32 GB RAM): // // Lines in main() | go1.24.4 | go1.25rc2 // + + // 4200 | ~3 sec. | 30 sec. (!) // 8400 | also ~3 sec. | 200 sec. (!!) package main // The complex data structures here are not directly involved in the performance regression, // but further simplification makes the regression less obvious. We have many programs like this. type ErrAtom string func (e ErrAtom) String() string { return "" } func (e ErrAtom) Value() float64 { return 0.0 } func (e ErrAtom) Desc() string { return "error" } type Atom interface { String() string Value() float64 Desc() string } type Block struct {} func (b Block) String() string { return "block" } func (b Block) Value() float64 { return 0.0 } func (b Block) Desc() string { return "block" } const ( NA_ERR = ErrAtom("#N/A") True_Atom = BoolAtom(true) ) type NumAtom float64 func (v NumAtom) String() string { return "" } func (v NumAtom) Value() float64 { return 0.0 } func (v NumAtom) Desc() string { return "number" } type BoolAtom bool func (b BoolAtom) Desc() string { return "bool" } func (b BoolAtom) String() string { return "bool" } func (b BoolAtom) Value() float64 { return 0.0 } type FunAtom struct { Func func() Atom } type AnyAtom interface { Desc() string } func V(a, b, c, d Atom) Atom { return NA_ERR } func main() { // This is the canonical line: _ = &FunAtom{Func: func() Atom { return V(True_Atom, Block{}, NumAtom(2), True_Atom) }} // ... add additional N-2 copies of the canonical line here to study case N ... _ = &FunAtom{Func: func() Atom { return V(True_Atom, Block{}, NumAtom(2), True_Atom) }} }
What did you expect to see?
Compile time (go build) between 2 and 3 seconds, even for very large main() functions with many repetitions of the same line.
What did you see instead?
Compile times of 30 sec for main() with 4000 lines (attached as program-4000.txt), and compile time of 3.3 min. for 8000-line version.
Comment From: chris99742
This program takes under 3 seconds to build in go1.24.4 or earlier, but takes over 30 sec with go1.25rc1 and rc2
Comment From: thepudds
Hi @chris99742, I'll take a look. Thanks for the report!
Comment From: cherrymui
cc @golang/compiler
Comment From: gopherbot
Change https://go.dev/cl/688075 mentions this issue: cmd/compile/internal/escape: make the ir.ReassignOracle cache more broadly scoped
Comment From: thepudds
Hi @chris99742, I sent https://go.dev/cl/688075, which is a test change and still WIP, but the CL does seem to restore the compile time for your program-4000.txt example, at least in a quick initial test.
Comparing go1.24 vs. go1.25rc2 vs. that CL for program-4000.txt:
build time (wall clock)
go1.24.4 ~0.5 sec
go1.25rc2 ~26.4 sec
cl-688075-ps1 ~0.5 sec
Would you be able to try that CL out locally to see if there is any improvement?
For example, one way is via the official gotip
utility:
# download and build CL 688075 (currently patchset 3):
$ go install golang.org/dl/gotip@latest
$ gotip download 688075
# get example program:
$ wget -O 4000.go https://github.com/user-attachments/files/21222862/program-4000.txt
# compile example program using CL 688075:
$ gotip tool compile 4000.go
Comment From: chris99742
Hi @thepudds, I followed your gotip instructions and the times look great, not just for the example program, but I used the resulting gotip (go version go1.25-devel_02eba975fa) to run our test suite and the overall time is the same as when running it with go1.24.4 (back to about 42 minutes). Thank you very much! I did see a related issue about ReassignOracle before I created this one, but I was not able to confidently test it. A separate thank you for the gotip instructions. If it is my responsibility to somehow close this issue or mark it resolved, I will do so (but I do hope the CL is slated for inclusion in the 1.25 release!)
Comment From: thepudds
Hi @chris99742, thanks for trying it out! And glad to hear your overall times seem to be back to Go 1.24 speeds.
If it is my responsibility to somehow close this issue or mark it resolved, I will do so
This issue will be automatically closed when a fix for it is merged, so no need for you to close it. (Hopefully that fix will be some flavor of the CL I sent, though I'm still looking at it and I'm about to tweak it some).
Comment From: thepudds
Hi @chris99742, I tweaked the implementation a bit (to make it a simpler and cleaner change).
Now that the fix is merged, would you mind trying with master/tip on your ~40 min test suite to confirm things still look good?
You can use the gotip
utility again, but this time do not supply a CL number, which means it will automatically download and build the latest Go toolchain on master.
$ gotip download