-
-
Save korniltsev/f6c639c68c7c40e1ead5db6012abed92 to your computer and use it in GitHub Desktop.
generic inline location bug reproducer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "bytes" | |
| "fmt" | |
| "runtime" | |
| "runtime/pprof" | |
| "strings" | |
| "testing" | |
| "github.com/google/pprof/profile" | |
| ) | |
| type opAlloc struct { | |
| buf [128]byte | |
| } | |
| type opCall struct { | |
| } | |
| func storeAlloc() { | |
| l = new(string) | |
| } | |
| func nonRecursiveGenericAllocFunction[CurrentOp any, OtherOp any](alloc bool) { | |
| if alloc { | |
| storeAlloc() | |
| } else { | |
| nonRecursiveGenericAllocFunction[OtherOp, CurrentOp](true) | |
| } | |
| } | |
| //go:noinline | |
| func test() { | |
| nonRecursiveGenericAllocFunction[opAlloc, opCall](true) | |
| nonRecursiveGenericAllocFunction[opCall, opAlloc](false) | |
| } | |
| var l *string | |
| func profileToString(p *profile.Profile) []string { | |
| var res []string | |
| for _, s := range p.Sample { | |
| res = append(res, sampleToString(s)) | |
| } | |
| return res | |
| } | |
| func sampleToString(s *profile.Sample) string { | |
| var funcs []string | |
| for i := len(s.Location) - 1; i >= 0; i-- { | |
| loc := s.Location[i] | |
| funcs = locationToStrings(loc, funcs) | |
| } | |
| return fmt.Sprintf("%s %v", strings.Join(funcs, ";"), s.Value) | |
| } | |
| func locationToStrings(loc *profile.Location, funcs []string) []string { | |
| for j := range loc.Line { | |
| line := loc.Line[len(loc.Line)-1-j] | |
| funcs = append(funcs, line.Function.Name) | |
| } | |
| return funcs | |
| } | |
| func TestGenericsBug(t *testing.T) { | |
| previousRate := runtime.MemProfileRate | |
| runtime.MemProfileRate = 1 | |
| defer func() { | |
| runtime.MemProfileRate = previousRate | |
| l = nil | |
| }() | |
| test() | |
| runtime.GC() | |
| buf := bytes.NewBuffer(nil) | |
| if err := pprof.WriteHeapProfile(buf); err != nil { | |
| t.Fatalf("writing profile: %v", err) | |
| } | |
| p, err := profile.Parse(buf) | |
| if err != nil { | |
| t.Fatalf("profile.Parse: %v", err) | |
| } | |
| const expectedSample = "testing.tRunner;p1.TestGenericsBug;p1.test;p1.nonRecursiveGenericAllocFunction[go.shape.struct {},go.shape.struct { p1.buf [128]uint8 }];p1.nonRecursiveGenericAllocFunction[go.shape.struct { p1.buf [128]uint8 },go.shape.struct {}];p1.storeAlloc [1 16 1 16]" | |
| const expectedLocation = "p1.nonRecursiveGenericAllocFunction[go.shape.struct {},go.shape.struct { p1.buf [128]uint8 }];p1.nonRecursiveGenericAllocFunction[go.shape.struct { p1.buf [128]uint8 },go.shape.struct {}];p1.storeAlloc" | |
| var s *profile.Sample | |
| for _, sample := range p.Sample { | |
| if sampleToString(sample) == expectedSample { | |
| s = sample | |
| break | |
| } | |
| } | |
| if s == nil { | |
| t.Fatalf("expected \n%s\ngot\n%s", expectedSample, strings.Join(profileToString(p), "\n")) | |
| } | |
| loc := s.Location[0] | |
| actual := strings.Join(locationToStrings(loc, nil), ";") | |
| if expectedLocation != actual { | |
| t.Errorf("expected a location with 3 functions ( 2 inlined )\n%s\ngot\n%s\n", expectedLocation, actual) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment