...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package report
16
17 import (
18 "crypto/sha256"
19 "encoding/binary"
20 "fmt"
21 "regexp"
22
23 "github.com/google/pprof/internal/measurement"
24 "github.com/google/pprof/profile"
25 )
26
27
28
29
30
31 type StackSet struct {
32 Total int64
33 Scale float64
34 Type string
35 Unit string
36 Stacks []Stack
37 Sources []StackSource
38 }
39
40
41 type Stack struct {
42 Value int64
43 Sources []int
44 }
45
46
47 type StackSource struct {
48 FullName string
49 FileName string
50 UniqueName string
51 Inlined bool
52
53
54
55 Display []string
56
57
58 RE string
59
60
61
62
63
64
65
66
67
68 Places []StackSlot
69
70
71 Self int64
72
73
74
75 Color int
76 }
77
78
79 type StackSlot struct {
80 Stack int
81 Pos int
82 }
83
84
85 func (rpt *Report) Stacks() StackSet {
86
87 scale, unit := measurement.Scale(1, rpt.options.SampleUnit, "default")
88 if unit == "default" {
89 unit = ""
90 }
91 if rpt.options.Ratio > 0 {
92 scale *= rpt.options.Ratio
93 }
94 s := &StackSet{
95 Total: rpt.total,
96 Scale: scale,
97 Type: rpt.options.SampleType,
98 Unit: unit,
99 Stacks: []Stack{},
100 Sources: []StackSource{},
101 }
102 s.makeInitialStacks(rpt)
103 s.fillPlaces()
104 s.assignColors()
105 return *s
106 }
107
108 func (s *StackSet) makeInitialStacks(rpt *Report) {
109 type key struct {
110 line profile.Line
111 inlined bool
112 }
113 srcs := map[key]int{}
114 seenFunctions := map[string]bool{}
115 unknownIndex := 1
116 getSrc := func(line profile.Line, inlined bool) int {
117 k := key{line, inlined}
118 if i, ok := srcs[k]; ok {
119 return i
120 }
121 x := StackSource{Places: []StackSlot{}}
122 if fn := line.Function; fn != nil {
123 x.FullName = fn.Name
124 x.FileName = fn.Filename
125 if !seenFunctions[fn.Name] {
126 x.UniqueName = fn.Name
127 seenFunctions[fn.Name] = true
128 } else {
129
130 x.UniqueName = fmt.Sprint(fn.Name, "#", fn.ID)
131 }
132 } else {
133 x.FullName = fmt.Sprintf("?%d?", unknownIndex)
134 x.UniqueName = x.FullName
135 unknownIndex++
136 }
137 x.Inlined = inlined
138 x.RE = "^" + regexp.QuoteMeta(x.UniqueName) + "$"
139 x.Display = shortNameList(x.FullName)
140 s.Sources = append(s.Sources, x)
141 srcs[k] = len(s.Sources) - 1
142 return len(s.Sources) - 1
143 }
144
145
146 s.Sources = []StackSource{{
147 FullName: "root",
148 Display: []string{"root"},
149 Places: []StackSlot{},
150 }}
151
152 for _, sample := range rpt.prof.Sample {
153 value := rpt.options.SampleValue(sample.Value)
154 stack := Stack{Value: value, Sources: []int{0}}
155
156
157 for i := len(sample.Location) - 1; i >= 0; i-- {
158 loc := sample.Location[i]
159 for j := len(loc.Line) - 1; j >= 0; j-- {
160 line := loc.Line[j]
161 inlined := (j != len(loc.Line)-1)
162 stack.Sources = append(stack.Sources, getSrc(line, inlined))
163 }
164 }
165
166 leaf := stack.Sources[len(stack.Sources)-1]
167 s.Sources[leaf].Self += value
168 s.Stacks = append(s.Stacks, stack)
169 }
170 }
171
172 func (s *StackSet) fillPlaces() {
173 for i, stack := range s.Stacks {
174 seenSrcs := map[int]bool{}
175 for j, src := range stack.Sources {
176 if seenSrcs[src] {
177 continue
178 }
179 seenSrcs[src] = true
180 s.Sources[src].Places = append(s.Sources[src].Places, StackSlot{i, j})
181 }
182 }
183 }
184
185 func (s *StackSet) assignColors() {
186
187 const numColors = 1048576
188 for i, src := range s.Sources {
189 pkg := packageName(src.FullName)
190 h := sha256.Sum256([]byte(pkg))
191 index := binary.LittleEndian.Uint32(h[:])
192 s.Sources[i].Color = int(index % numColors)
193 }
194 }
195
View as plain text