github.com/grafana/pyroscope@v1.18.0/pkg/og/convert/pprof/bench/utils.go (about) 1 package bench 2 3 import ( 4 "compress/gzip" 5 "fmt" 6 "io" 7 "os" 8 "slices" 9 "strings" 10 11 profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" 12 ) 13 14 func ReadGzipFile(f string) ([]byte, error) { 15 fd, err := os.Open(f) 16 if err != nil { 17 return nil, err 18 } 19 defer fd.Close() 20 g, err := gzip.NewReader(fd) 21 if err != nil { 22 return nil, err 23 } 24 return io.ReadAll(g) 25 } 26 27 func WriteGzipFile(f string, data []byte) error { 28 fd, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) 29 if err != nil { 30 return err 31 } 32 defer fd.Close() 33 g := gzip.NewWriter(fd) 34 _, err = g.Write(data) 35 if err != nil { 36 return err 37 } 38 return g.Close() 39 } 40 41 type StackCollapseOptions struct { 42 ValueIdx int 43 Scale float64 44 WithLabels bool 45 } 46 47 func StackCollapseProto(p *profilev1.Profile, valueIDX int, scale float64) []string { 48 return StackCollapseProtoWithOptions(p, StackCollapseOptions{ValueIdx: valueIDX, Scale: scale}) 49 } 50 51 func StackCollapseProtoWithOptions(p *profilev1.Profile, opt StackCollapseOptions) []string { 52 var valueIDX int = opt.ValueIdx 53 var scale float64 = opt.Scale 54 type stack struct { 55 funcs string 56 value int64 57 } 58 locMap := make(map[int64]*profilev1.Location) 59 funcMap := make(map[int64]*profilev1.Function) 60 for _, l := range p.Location { 61 locMap[int64(l.Id)] = l 62 } 63 for _, f := range p.Function { 64 funcMap[int64(f.Id)] = f 65 } 66 67 var ret []stack 68 for _, s := range p.Sample { 69 var funcs []string 70 for i := range s.LocationId { 71 locID := s.LocationId[len(s.LocationId)-1-i] 72 loc := locMap[int64(locID)] 73 for _, line := range loc.Line { 74 f := funcMap[int64(line.FunctionId)] 75 fname := p.StringTable[f.Name] 76 funcs = append(funcs, fname) 77 } 78 } 79 v := s.Value[valueIDX] 80 if scale != 1 { 81 v = int64(float64(v) * scale) 82 } 83 84 sls := "" 85 if opt.WithLabels { 86 ls := []string{} 87 for _, label := range s.Label { 88 ls = append(ls, fmt.Sprintf("(%s = %s)", p.StringTable[label.Key], p.StringTable[label.Str])) 89 } 90 sls = strings.Join(ls, ", ") + " ||| " 91 } 92 ret = append(ret, stack{ 93 funcs: sls + strings.Join(funcs, ";"), 94 value: v, 95 }) 96 } 97 slices.SortFunc(ret, func(i, j stack) int { 98 return strings.Compare(i.funcs, j.funcs) 99 }) 100 var unique []stack 101 for _, s := range ret { 102 if s.value == 0 { 103 continue 104 } 105 if len(unique) == 0 { 106 unique = append(unique, s) 107 continue 108 } 109 110 if unique[len(unique)-1].funcs == s.funcs { 111 unique[len(unique)-1].value += s.value 112 continue 113 } 114 unique = append(unique, s) 115 } 116 117 res := []string{} 118 for _, s := range unique { 119 res = append(res, fmt.Sprintf("%s %d", s.funcs, s.value)) 120 } 121 return res 122 }