aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTolya Korniltsev <korniltsev.anatoly@gmail.com>2023-12-04 17:53:29 +0700
committerGopher Robot <gobot@golang.org>2024-01-04 17:22:01 +0000
commitad1ec60a5bae4e8afef7a5ee68fac80a758e4395 (patch)
tree4d29f2e9214ec5889d730555679205d3fc85eb98
parentbbab863ada264642e2755f123ef3f84a6b3451d0 (diff)
downloadgo-ad1ec60a5bae4e8afef7a5ee68fac80a758e4395.tar.gz
go-ad1ec60a5bae4e8afef7a5ee68fac80a758e4395.zip
[release-branch.go1.21] runtime/pprof: fix generics function names
profileBuilder is using Frame->Function as key for checking if we already emitted a function. However for generics functions it has dots there [...], so sometimes for different functions with different generics types, the profileBuilder emits wrong functions. For #64528 For #64609 Change-Id: I8b39245e0b18f4288ce758c912c6748f87cba39a Reviewed-on: https://go-review.googlesource.com/c/go/+/546815 Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> (cherry picked from commit 20a03fc7130d8d99b513071c7e413b436ea649a2) Reviewed-on: https://go-review.googlesource.com/c/go/+/549535 Auto-Submit: Matthew Dempsky <mdempsky@google.com>
-rw-r--r--src/runtime/pprof/proto.go7
-rw-r--r--src/runtime/pprof/protomem_test.go62
2 files changed, 66 insertions, 3 deletions
diff --git a/src/runtime/pprof/proto.go b/src/runtime/pprof/proto.go
index cdc4bd7c80d..db9384eb214 100644
--- a/src/runtime/pprof/proto.go
+++ b/src/runtime/pprof/proto.go
@@ -611,13 +611,14 @@ func (b *profileBuilder) emitLocation() uint64 {
b.pb.uint64Opt(tagLocation_Address, uint64(firstFrame.PC))
for _, frame := range b.deck.frames {
// Write out each line in frame expansion.
- funcID := uint64(b.funcs[frame.Function])
+ funcName := runtime_FrameSymbolName(&frame)
+ funcID := uint64(b.funcs[funcName])
if funcID == 0 {
funcID = uint64(len(b.funcs)) + 1
- b.funcs[frame.Function] = int(funcID)
+ b.funcs[funcName] = int(funcID)
newFuncs = append(newFuncs, newFunc{
id: funcID,
- name: runtime_FrameSymbolName(&frame),
+ name: funcName,
file: frame.File,
startLine: int64(runtime_FrameStartLine(&frame)),
})
diff --git a/src/runtime/pprof/protomem_test.go b/src/runtime/pprof/protomem_test.go
index 156f6286a92..505c323d686 100644
--- a/src/runtime/pprof/protomem_test.go
+++ b/src/runtime/pprof/protomem_test.go
@@ -6,8 +6,11 @@ package pprof
import (
"bytes"
+ "fmt"
"internal/profile"
"runtime"
+ "slices"
+ "strings"
"testing"
)
@@ -82,3 +85,62 @@ func TestConvertMemProfile(t *testing.T) {
})
}
}
+
+func genericAllocFunc[T interface{ uint32 | uint64 }](n int) []T {
+ return make([]T, n)
+}
+
+func profileToString(p *profile.Profile) []string {
+ var res []string
+ for _, s := range p.Sample {
+ var funcs []string
+ for i := len(s.Location) - 1; i >= 0; i-- {
+ loc := s.Location[i]
+ for j := len(loc.Line) - 1; j >= 0; j-- {
+ line := loc.Line[j]
+ funcs = append(funcs, line.Function.Name)
+ }
+ }
+ res = append(res, fmt.Sprintf("%s %v", strings.Join(funcs, ";"), s.Value))
+ }
+ return res
+}
+
+// This is a regression test for https://go.dev/issue/64528 .
+func TestGenericsHashKeyInPprofBuilder(t *testing.T) {
+ previousRate := runtime.MemProfileRate
+ runtime.MemProfileRate = 1
+ defer func() {
+ runtime.MemProfileRate = previousRate
+ }()
+ for _, sz := range []int{128, 256} {
+ genericAllocFunc[uint32](sz / 4)
+ }
+ for _, sz := range []int{32, 64} {
+ genericAllocFunc[uint64](sz / 8)
+ }
+
+ runtime.GC()
+ buf := bytes.NewBuffer(nil)
+ if err := WriteHeapProfile(buf); err != nil {
+ t.Fatalf("writing profile: %v", err)
+ }
+ p, err := profile.Parse(buf)
+ if err != nil {
+ t.Fatalf("profile.Parse: %v", err)
+ }
+
+ actual := profileToString(p)
+ expected := []string{
+ "testing.tRunner;runtime/pprof.TestGenericsHashKeyInPprofBuilder;runtime/pprof.genericAllocFunc[go.shape.uint32] [1 128 0 0]",
+ "testing.tRunner;runtime/pprof.TestGenericsHashKeyInPprofBuilder;runtime/pprof.genericAllocFunc[go.shape.uint32] [1 256 0 0]",
+ "testing.tRunner;runtime/pprof.TestGenericsHashKeyInPprofBuilder;runtime/pprof.genericAllocFunc[go.shape.uint64] [1 32 0 0]",
+ "testing.tRunner;runtime/pprof.TestGenericsHashKeyInPprofBuilder;runtime/pprof.genericAllocFunc[go.shape.uint64] [1 64 0 0]",
+ }
+
+ for _, l := range expected {
+ if !slices.Contains(actual, l) {
+ t.Errorf("profile = %v\nwant = %v", strings.Join(actual, "\n"), l)
+ }
+ }
+}