runtime/pprof: unexpectedly seeing full struct definitions in function names for generics functions
S-YOU opened this issue · 6 comments
Go version
go1.20.6 linux/amd64
Output of go env in your module/workspace:
GO111MODULE='auto'
GOARCH='amd64'
GOBIN=''
GOCACHE='<HOME>/.cache/go-build'
GOENV='<HOME>/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS='-mod=readonly'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='<HOME>/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='<HOME>/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/go'
GOSUMDB='off'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/opt/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.6'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='<HOME>/go/src/r/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1751412201=/tmp/go-build -gno-record-gcc-switches'What did you do?
When I profile with pprof, func name output is too large for struct types.
Might related to this fix with 1.21.6
What did you see happen?
When you pass large struct as Type to generics functions, pprof show all if its definition like this.

What did you expect to see?
Only struct Name or with package name for Types passed to generics function, instead of full definition on pprof output.
I expected this to be fixed with Go 1.21.6. Are you trying to open a pprof captured with an old version of Go?
I don't think this is related to #64528 (the bug fixed in 1.21.6). That is about the profile containing an incorrect symbol name.
AFAICT, this issue is simply about the giant name in the profile. That name is the actual symbol name, for better or worse. The CL on #65030 (included in 1.22) uses a hashed name for these giant names to keep them small. That should make the pprof graph look less absurd, but at the expensive that it will no longer be possible to tell what the type parameters are.
I expected this to be fixed with Go 1.21.6. Are you trying to open a pprof captured with an old version of Go?
Go verison is 1.21.6 as I added go env result or is there chance that go tool pprof command calling some other binaries which is old?
That should make the pprof graph look less absurd, but at the expensive that it will no longer be possible to tell what the type parameters are.
I could undstertand that, but is there a need to treat any struct like anonymous and show its body instead? The one I am passing is the struct name itself, so it should have the name like package.Struct.
EDIT: I took a look at #65030, but it seems like a workaround for visual. Is that also mean Go does not even hold the name of the type (struct's full name) passed in generics functions?
I could undstertand that, but is there a need to treat any struct like anonymous and show its body instead? The one I am passing is the struct name itself, so it should have the name like package.Struct.
The Go toolchain uses a dictionary-based generics implementation. That doc has complete details, but the critical aspect is that the compiler does not create a unique function instantiation for every distinct type argument. A single instantiation is shared by all types that have the same shape.
You can see an example of this with this program:
package main
import (
"fmt"
)
//go:noinline
func Print[T any](v T) {
fmt.Println(v)
}
type A struct {
Foo int
}
type B struct {
Foo int
}
type C A
func main() {
var (
a A
b B
c C
)
Print(a)
Print(b)
Print(c)
}
If you look at the disassembly, you'll see that even though Print is instantiated with three different types (A, B, and C), there is only a single symbol that all three share: main.Print[go.shape.struct { Foo int }].
Thanks for the the detail explanations, seems like even I write like Print[A](a), output are the same.
Closing for now.