github.com/grafana/pyroscope@v1.18.0/pkg/pprof/fix_go_profile.go (about) 1 package pprof 2 3 import ( 4 "regexp" 5 "strings" 6 7 profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" 8 ) 9 10 // FixGoProfile fixes known issues with profiles collected with 11 // the standard Go profiler. 12 // 13 // Note that the function presumes that p is a Go profile and does 14 // not verify this. It is expected that the function is called 15 // very early in the profile processing chain and normalized after, 16 // regardless of the function outcome. 17 func FixGoProfile(p *profilev1.Profile) *profilev1.Profile { 18 p = DropGoTypeParameters(p) 19 // Now that the profile is normalized, we can try to repair 20 // truncated stack traces, if any. Note that repaired stacks 21 // are not deduplicated, so the caller need to normalize the 22 if PotentialTruncatedGoStacktraces(p) { 23 RepairGoTruncatedStacktraces(p) 24 } 25 return p 26 } 27 28 // DropGoTypeParameters removes of type parameters from Go function names. 29 // 30 // In go 1.21 and above, function names include type parameters, however, 31 // due to a bug, a function name could include any of the type instances 32 // regardless of the call site. Thus, e.g., x[T1].foo and x[T2].foo can't 33 // be distinguished in a profile. This leads to incorrect profiles and 34 // incorrect flame graphs, and hugely increases cardinality of stack traces. 35 // 36 // The function renames x[T1].foo and x[T2].foo to x[...].foo and normalizes 37 // the profile, if type parameters are present in the profile. Otherwise, the 38 // profile returns unchanged. 39 // 40 // See https://github.com/golang/go/issues/64528. 41 func DropGoTypeParameters(p *profilev1.Profile) *profilev1.Profile { 42 var n int 43 for i, s := range p.StringTable { 44 c := dropGoTypeParameters(s) 45 if c != s { 46 p.StringTable[i] = c 47 n++ 48 } 49 } 50 if n == 0 { 51 return p 52 } 53 // Merging with self effectively normalizes the profile: 54 // it removed duplicates, establishes order of labels, 55 // and allocates monotonic identifiers. 56 var m ProfileMerge 57 // We safely ignore the error as the only case when it can 58 // happen is when merged profiles are of different types. 59 _ = m.Merge(p, true) 60 return m.Profile() 61 } 62 63 var goStructTypeParameterRegex = regexp.MustCompile(`\[go\.shape\..*\]`) 64 65 func dropGoTypeParameters(input string) string { 66 matchesIndices := goStructTypeParameterRegex.FindAllStringIndex(input, -1) 67 if len(matchesIndices) == 0 { 68 return input 69 } 70 var modified strings.Builder 71 prevEnd := 0 72 for _, indices := range matchesIndices { 73 start, end := indices[0], indices[1] 74 modified.WriteString(input[prevEnd:start]) 75 prevEnd = end 76 } 77 modified.WriteString(input[prevEnd:]) 78 return modified.String() 79 }