1
2
3
4
5
6
7
8 package trace
9
10 import (
11 "fmt"
12 "math"
13 "strings"
14
15 "internal/trace/tracev2"
16 "internal/trace/version"
17 )
18
19
20
21 type timedEventArgs [tracev2.MaxTimedEventArgs - 1]uint64
22
23
24
25 type baseEvent struct {
26 typ tracev2.EventType
27 time Time
28 args timedEventArgs
29 }
30
31
32
33 func (e *baseEvent) extra(v version.Version) []uint64 {
34 switch v {
35 case version.Go122:
36 return e.args[len(tracev2.Specs()[e.typ].Args)-1:]
37 }
38 panic(fmt.Sprintf("unsupported version: go 1.%d", v))
39 }
40
41
42
43 type evTable struct {
44 sync
45 strings dataTable[stringID, string]
46 stacks dataTable[stackID, stack]
47 pcs map[uint64]frame
48
49
50
51
52 extraStrings []string
53 extraStringIDs map[string]extraStringID
54 nextExtra extraStringID
55
56
57 expBatches map[tracev2.Experiment][]ExperimentalBatch
58 }
59
60
61
62 func (t *evTable) addExtraString(s string) extraStringID {
63 if s == "" {
64 return 0
65 }
66 if t.extraStringIDs == nil {
67 t.extraStringIDs = make(map[string]extraStringID)
68 }
69 if id, ok := t.extraStringIDs[s]; ok {
70 return id
71 }
72 t.nextExtra++
73 id := t.nextExtra
74 t.extraStrings = append(t.extraStrings, s)
75 t.extraStringIDs[s] = id
76 return id
77 }
78
79
80
81 func (t *evTable) getExtraString(id extraStringID) string {
82 if id == 0 {
83 return ""
84 }
85 return t.extraStrings[id-1]
86 }
87
88
89 type dataTable[EI ~uint64, E any] struct {
90 present []uint8
91 dense []E
92 sparse map[EI]E
93 }
94
95
96
97
98
99
100 func (d *dataTable[EI, E]) insert(id EI, data E) error {
101 if d.sparse == nil {
102 d.sparse = make(map[EI]E)
103 }
104 if existing, ok := d.get(id); ok {
105 return fmt.Errorf("multiple %Ts with the same ID: id=%d, new=%v, existing=%v", data, id, data, existing)
106 }
107 d.sparse[id] = data
108 return nil
109 }
110
111
112 func (d *dataTable[EI, E]) append(data E) EI {
113 if d.sparse == nil {
114 d.sparse = make(map[EI]E)
115 }
116 id := EI(len(d.sparse)) + 1
117 d.sparse[id] = data
118 return id
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: tracev2.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