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