Source file
src/runtime/tracebuf.go
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "internal/runtime/sys"
11 "unsafe"
12 )
13
14
15 const traceBytesPerNumber = 10
16
17
18
19
20
21
22
23
24
25 type traceWriter struct {
26 traceLocker
27 exp traceExperiment
28 *traceBuf
29 }
30
31
32
33
34
35
36
37
38
39
40
41
42 func (tl traceLocker) writer() traceWriter {
43 if debugTraceReentrancy {
44
45 gp := getg()
46 if gp == gp.m.curg {
47 tl.mp.trace.oldthrowsplit = gp.throwsplit
48 gp.throwsplit = true
49 }
50 }
51 return traceWriter{traceLocker: tl, traceBuf: tl.mp.trace.buf[tl.gen%2][traceNoExperiment]}
52 }
53
54
55
56
57
58
59
60
61
62
63 func unsafeTraceWriter(gen uintptr, buf *traceBuf) traceWriter {
64 return traceWriter{traceLocker: traceLocker{gen: gen}, traceBuf: buf}
65 }
66
67
68
69
70
71
72
73 func (w traceWriter) event(ev traceEv, args ...traceArg) traceWriter {
74
75
76
77
78 w, _ = w.ensure(1 + (len(args)+1)*traceBytesPerNumber)
79
80
81 ts := traceClockNow()
82 if ts <= w.traceBuf.lastTime {
83 ts = w.traceBuf.lastTime + 1
84 }
85 tsDiff := uint64(ts - w.traceBuf.lastTime)
86 w.traceBuf.lastTime = ts
87
88
89 w.byte(byte(ev))
90 w.varint(tsDiff)
91 for _, arg := range args {
92 w.varint(uint64(arg))
93 }
94 return w
95 }
96
97
98
99
100
101
102
103 func (w traceWriter) end() {
104 if w.mp == nil {
105
106
107 return
108 }
109 w.mp.trace.buf[w.gen%2][w.exp] = w.traceBuf
110 if debugTraceReentrancy {
111
112
113 gp := getg()
114 if gp == gp.m.curg {
115 gp.throwsplit = w.mp.trace.oldthrowsplit
116 }
117 }
118 }
119
120
121
122
123
124
125
126
127
128 func (w traceWriter) ensure(maxSize int) (traceWriter, bool) {
129 refill := w.traceBuf == nil || !w.available(maxSize)
130 if refill {
131 w = w.refill()
132 }
133 return w, refill
134 }
135
136
137
138
139
140
141
142 func (w traceWriter) flush() traceWriter {
143 systemstack(func() {
144 lock(&trace.lock)
145 if w.traceBuf != nil {
146 traceBufFlush(w.traceBuf, w.gen)
147 }
148 unlock(&trace.lock)
149 })
150 w.traceBuf = nil
151 return w
152 }
153
154
155 func (w traceWriter) refill() traceWriter {
156 systemstack(func() {
157 lock(&trace.lock)
158 if w.traceBuf != nil {
159 traceBufFlush(w.traceBuf, w.gen)
160 }
161 if trace.empty != nil {
162 w.traceBuf = trace.empty
163 trace.empty = w.traceBuf.link
164 unlock(&trace.lock)
165 } else {
166 unlock(&trace.lock)
167 w.traceBuf = (*traceBuf)(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys))
168 if w.traceBuf == nil {
169 throw("trace: out of memory")
170 }
171 }
172 })
173
174 ts := traceClockNow()
175 if ts <= w.traceBuf.lastTime {
176 ts = w.traceBuf.lastTime + 1
177 }
178 w.traceBuf.lastTime = ts
179 w.traceBuf.link = nil
180 w.traceBuf.pos = 0
181
182
183 mID := ^uint64(0)
184 if w.mp != nil {
185 mID = uint64(w.mp.procid)
186 }
187
188
189 if w.exp == traceNoExperiment {
190 w.byte(byte(traceEvEventBatch))
191 } else {
192 w.byte(byte(traceEvExperimentalBatch))
193 w.byte(byte(w.exp))
194 }
195 w.varint(uint64(w.gen))
196 w.varint(uint64(mID))
197 w.varint(uint64(ts))
198 w.traceBuf.lenPos = w.varintReserve()
199 return w
200 }
201
202
203 type traceBufQueue struct {
204 head, tail *traceBuf
205 }
206
207
208 func (q *traceBufQueue) push(buf *traceBuf) {
209 buf.link = nil
210 if q.head == nil {
211 q.head = buf
212 } else {
213 q.tail.link = buf
214 }
215 q.tail = buf
216 }
217
218
219 func (q *traceBufQueue) pop() *traceBuf {
220 buf := q.head
221 if buf == nil {
222 return nil
223 }
224 q.head = buf.link
225 if q.head == nil {
226 q.tail = nil
227 }
228 buf.link = nil
229 return buf
230 }
231
232 func (q *traceBufQueue) empty() bool {
233 return q.head == nil
234 }
235
236
237 type traceBufHeader struct {
238 link *traceBuf
239 lastTime traceTime
240 pos int
241 lenPos int
242 }
243
244
245
246
247 type traceBuf struct {
248 _ sys.NotInHeap
249 traceBufHeader
250 arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte
251 }
252
253
254
255
256
257
258
259 func (buf *traceBuf) byte(v byte) {
260 buf.arr[buf.pos] = v
261 buf.pos++
262 }
263
264
265
266
267
268
269
270 func (buf *traceBuf) varint(v uint64) {
271 pos := buf.pos
272 arr := buf.arr[pos : pos+traceBytesPerNumber]
273 for i := range arr {
274 if v < 0x80 {
275 pos += i + 1
276 arr[i] = byte(v)
277 break
278 }
279 arr[i] = 0x80 | byte(v)
280 v >>= 7
281 }
282 buf.pos = pos
283 }
284
285
286
287
288
289
290
291
292
293 func (buf *traceBuf) varintReserve() int {
294 p := buf.pos
295 buf.pos += traceBytesPerNumber
296 return p
297 }
298
299
300
301
302
303
304
305 func (buf *traceBuf) stringData(s string) {
306 buf.pos += copy(buf.arr[buf.pos:], s)
307 }
308
309
310
311
312
313 func (buf *traceBuf) available(size int) bool {
314 return len(buf.arr)-buf.pos >= size
315 }
316
317
318
319
320
321
322
323
324
325
326 func (buf *traceBuf) varintAt(pos int, v uint64) {
327 for i := 0; i < traceBytesPerNumber; i++ {
328 if i < traceBytesPerNumber-1 {
329 buf.arr[pos] = 0x80 | byte(v)
330 } else {
331 buf.arr[pos] = byte(v)
332 }
333 v >>= 7
334 pos++
335 }
336 if v != 0 {
337 throw("v could not fit in traceBytesPerNumber")
338 }
339 }
340
341
342
343
344
345
346 func traceBufFlush(buf *traceBuf, gen uintptr) {
347 assertLockHeld(&trace.lock)
348
349
350
351
352
353
354
355
356
357 buf.varintAt(buf.lenPos, uint64(buf.pos-(buf.lenPos+traceBytesPerNumber)))
358 trace.full[gen%2].push(buf)
359
360
361
362 if !trace.workAvailable.Load() {
363 trace.workAvailable.Store(true)
364 }
365 }
366
View as plain text