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/compile: possible append inside a method escape analysis optimization #54563
Comments
The other argument(s) to package main
import (
"fmt"
_ "unsafe"
)
type Builder struct {
buf []*byte
}
func (b *Builder) DoSth(n byte) {
b.buf = append2(b.buf, &n)
}
//go:noescape
//go:linkname append2 main.append2helper
func append2(buf []*byte, elems ...*byte) []*byte
func append2helper(buf []*byte, elems ...*byte) []*byte {
return append(buf, elems...)
}
func main() {
b := new(Builder)
b.DoSth(1)
b.DoSth(2)
b.DoSth(3)
for i := range b.buf {
fmt.Print(*b.buf[i])
}
fmt.Println()
} If you run this with inlining disabled ( |
Change https://go.dev/cl/425462 mentions this issue: |
I've prototyped the requested optimization in CL 425462 above. Please test it out on more realistic code bases and report back if it helps. (Beware: I'm reasonably confident that it's correct, but I wouldn't recommend using it for any production workloads yet.) Also, know that it's currently very restrictive on the expressions that can appear in the |
For example, compiling the source file below with
|
It seems to work fine. The only problem that I found is while passing the b.buf to some external function, which appends to that buf, it still escapes. type Builder struct {
buf []byte
}
func (b *Builder) DoSth(n byte) {
b.buf = doSth(b.buf, 3)
}
func doSth(msg []byte, n byte) []byte {
return append(msg, n)
}
func main() {
b := &Builder{buf: make([]byte, 0, 10)}
b.DoSth(1)
} But it is not a big deal, while using pointers the alloc is removed: func (b *Builder) DoSth2(n byte) {
doSth2(&b.buf, 3)
}
func doSth2(msg *[]byte, n byte) {
*msg = append(*msg, n)
}
func main() {
b := &Builder{buf: make([]byte, 0, 10)}
b.DoSth2(1)
} |
BenchmarkEscapes-4 48139129 37.46 ns/op 16 B/op 1 allocs/op
BenchmarkDoesNotEscape-4 1000000000 0.3443 ns/op 0 B/op 0 allocs/op
I think we might just mark the append function implicitly in compiler as noescaping.
Doing so, but explicitly, removes the allocation:
BenchmarkNoescapeAppend-4 170689034 7.031 ns/op 0 B/op 0 allocs/op
I think it is safe to do so. I can't think of any case where the slice passed to append must be forced to be heap allocated.
The text was updated successfully, but these errors were encountered: