1
2
3
4
5
6
7
8 package trace
9
10 import (
11 "fmt"
12 "math"
13 "strings"
14
15 "internal/trace/event"
16 "internal/trace/event/go122"
17 "internal/trace/version"
18 )
19
20
21
22
23
24
25
26 const maxArgs = 6
27
28
29
30 type timedEventArgs [maxArgs - 1]uint64
31
32
33
34 type baseEvent struct {
35 typ event.Type
36 time Time
37 args timedEventArgs
38 }
39
40
41
42 func (e *baseEvent) extra(v version.Version) []uint64 {
43 switch v {
44 case version.Go122:
45 return e.args[len(go122.Specs()[e.typ].Args)-1:]
46 }
47 panic(fmt.Sprintf("unsupported version: go 1.%d", v))
48 }
49
50
51
52 type evTable struct {
53 freq frequency
54 strings dataTable[stringID, string]
55 stacks dataTable[stackID, stack]
56 pcs map[uint64]frame
57
58
59
60
61 extraStrings []string
62 extraStringIDs map[string]extraStringID
63 nextExtra extraStringID
64
65
66
67 expData map[event.Experiment]*ExperimentalData
68 }
69
70
71
72 func (t *evTable) addExtraString(s string) extraStringID {
73 if s == "" {
74 return 0
75 }
76 if t.extraStringIDs == nil {
77 t.extraStringIDs = make(map[string]extraStringID)
78 }
79 if id, ok := t.extraStringIDs[s]; ok {
80 return id
81 }
82 t.nextExtra++
83 id := t.nextExtra
84 t.extraStrings = append(t.extraStrings, s)
85 t.extraStringIDs[s] = id
86 return id
87 }
88
89
90
91 func (t *evTable) getExtraString(id extraStringID) string {
92 if id == 0 {
93 return ""
94 }
95 return t.extraStrings[id-1]
96 }
97
98
99 type dataTable[EI ~uint64, E any] struct {
100 present []uint8
101 dense []E
102 sparse map[EI]E
103 }
104
105
106
107
108
109
110 func (d *dataTable[EI, E]) insert(id EI, data E) error {
111 if d.sparse == nil {
112 d.sparse = make(map[EI]E)
113 }
114 if existing, ok := d.get(id); ok {
115 return fmt.Errorf("multiple %Ts with the same ID: id=%d, new=%v, existing=%v", data, id, data, existing)
116 }
117 d.sparse[id] = data
118 return nil
119 }
120
121
122
123
124 func (d *dataTable[EI, E]) compactify() {
125 if d.sparse == nil || len(d.dense) != 0 {
126
127 return
128 }
129
130 maxID := EI(0)
131 minID := ^EI(0)
132 for id := range d.sparse {
133 if id > maxID {
134 maxID = id
135 }
136 if id < minID {
137 minID = id
138 }
139 }
140 if maxID >= math.MaxInt {
141
142 return
143 }
144
145 if int(maxID-minID) > max(len(d.sparse), 2*len(d.sparse)) {
146 return
147 }
148 if int(minID) > len(d.sparse) {
149 return
150 }
151 size := int(maxID) + 1
152 d.present = make([]uint8, (size+7)/8)
153 d.dense = make([]E, size)
154 for id, data := range d.sparse {
155 d.dense[id] = data
156 d.present[id/8] |= uint8(1) << (id % 8)
157 }
158 d.sparse = nil
159 }
160
161
162
163 func (d *dataTable[EI, E]) get(id EI) (E, bool) {
164 if id == 0 {
165 return *new(E), true
166 }
167 if uint64(id) < uint64(len(d.dense)) {
168 if d.present[id/8]&(uint8(1)<<(id%8)) != 0 {
169 return d.dense[id], true
170 }
171 } else if d.sparse != nil {
172 if data, ok := d.sparse[id]; ok {
173 return data, true
174 }
175 }
176 return *new(E), false
177 }
178
179
180 func (d *dataTable[EI, E]) forEach(yield func(EI, E) bool) bool {
181 for id, value := range d.dense {
182 if d.present[id/8]&(uint8(1)<<(id%8)) == 0 {
183 continue
184 }
185 if !yield(EI(id), value) {
186 return false
187 }
188 }
189 if d.sparse == nil {
190 return true
191 }
192 for id, value := range d.sparse {
193 if !yield(id, value) {
194 return false
195 }
196 }
197 return true
198 }
199
200
201
202
203 func (d *dataTable[EI, E]) mustGet(id EI) E {
204 data, ok := d.get(id)
205 if !ok {
206 panic(fmt.Sprintf("expected id %d in %T table", id, data))
207 }
208 return data
209 }
210
211
212 type frequency float64
213
214
215 func (f frequency) mul(t timestamp) Time {
216 return Time(float64(t) * float64(f))
217 }
218
219
220 type stringID uint64
221
222
223 type extraStringID uint64
224
225
226 type stackID uint64
227
228
229 type cpuSample struct {
230 schedCtx
231 time Time
232 stack stackID
233 }
234
235
236
237
238
239
240 func (s cpuSample) asEvent(table *evTable) Event {
241
242
243 e := Event{
244 table: table,
245 ctx: s.schedCtx,
246 base: baseEvent{
247 typ: go122.EvCPUSample,
248 time: s.time,
249 },
250 }
251 e.base.args[0] = uint64(s.stack)
252 return e
253 }
254
255
256 type stack struct {
257 pcs []uint64
258 }
259
260 func (s stack) String() string {
261 var sb strings.Builder
262 for _, frame := range s.pcs {
263 fmt.Fprintf(&sb, "\t%#v\n", frame)
264 }
265 return sb.String()
266 }
267
268
269 type frame struct {
270 pc uint64
271 funcID stringID
272 fileID stringID
273 line uint64
274 }
275
View as plain text