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