go: cmd/compile: 1.15 heap allocations regression when calling Write on os.Stdout
$ go version
go version go1.15.2 linux/amd64
$ uname -a
Linux gauss 5.7.0-2-amd64 #1 SMP Debian 5.7.10-1 (2020-07-26) x86_64 GNU/Linux
I have a program that shall not heap-allocate in its main loop, with a test checking that. When I re-compiled the program with Go1.15, the test started failing. This is the offending line according to mem profile data:
os.Stdout.Write([]byte("\033[2J\033[1;1H"))
Ignore the string literal cast to []byte
, it’s a red herring. Here’s a reproducer:
package p
import "os"
func f() {
os.Stdout.Write([]byte{'h', 'e', 'l', 'l', 'o'})
}
Go1.14:
$ go tool compile -m test.go
test.go:5:6: can inline f
test.go:6:24: []byte literal does not escape
Go1.15:
$ go tool compile -m test.go
test.go:5:6: can inline f
test.go:6:24: []byte literal escapes to heap
git bisect
points to 8c1db77a92b1d17d3fe07999c5f20602a2080be9, but I don’t know if that makes sense.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 31 (21 by maintainers)
Commits related to this issue
- [release-branch.go1.15] internal/poll: adjust ignoringEINTR to avoid slice escape The 1.15 compiler is not quite smart enough to see that the byte slice passed to ignoringEINTR does not escape. This ... — committed to golang/go by ianlancetaylor 4 years ago
- cmd/compile: set n.Name.Defn for inlined parameters Normally, when variables are declared and initialized using ":=", we set the variable's n.Name.Defn to point to the initialization assignment node ... — committed to golang/go by mdempsky 4 years ago
- cmd/compile: improve escape analysis of known calls Escape analysis is currently very naive about identifying calls to known functions: it only recognizes direct calls to a declared function, or dire... — committed to golang/go by mdempsky 4 years ago
- cmd/compile: use staticValue for inlining logic This CL replaces the ad hoc and duplicated logic for detecting inlinable calls with a single "inlCallee" function, which uses the "staticValue" helper ... — committed to golang/go by mdempsky 4 years ago
- test: add regression test from #41474 This issue was fixed with multiple individual compiler optimizations, each of which had their own respective test cases. This CL just adds the capstone test case... — committed to golang/go by ALTree 4 years ago
- Revert "test: add regression test from #41474" This reverts CL 263097. Reason for revert: broke the noopt builder. Change-Id: Ie36d2c3ed9449b4425732072db624c8e18f965f3 Reviewed-on: https://go-revie... — committed to golang/go by ALTree 4 years ago
- [release-branch.go1.15] internal/poll: adjust ignoringEINTR to avoid slice escape The 1.15 compiler is not quite smart enough to see that the byte slice passed to ignoringEINTR does not escape. This ... — committed to claucece/go by ianlancetaylor 4 years ago
Clearly we should replace the loops with
goto
statements.We should find and fix that bug. Inlining
goto
but notfor
creates a bit of a perverse incentive…The plan here is to try to fix this in the compiler, but if we get to the freeze without that landing, we’ll just forward-port the 1.15 fix.
Given that we’ve backported a fix for this issue to Go 1.15, I believe we should not release Go 1.16 without fixing this (or re-visiting this in some way), so marking as a release-blocker.
I’ve landed all the individual compiler optimizations to fix this, but it’s proving tedious to write a test that shows the original test case involving os.Stdout.Write has actually been fixed. E.g., js/wasm and apparently Windows also still escape, but at least js/wasm also escaped in Go 1.15. I haven’t looked into Windows.
It should be a straightforward task for someone to take CL 262678 and amend it. Probably it just needs to check
runtime.GOOS == "windows"
.