Source file
src/runtime/tracebuf.go
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "runtime/internal/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 *traceBuf
28 }
29
30
31 func (tl traceLocker) writer() traceWriter {
32 return traceWriter{traceLocker: tl, traceBuf: tl.mp.trace.buf[tl.gen%2]}
33 }
34
35
36
37
38
39
40
41
42 func unsafeTraceWriter(gen uintptr, buf *traceBuf) traceWriter {
43 return traceWriter{traceLocker: traceLocker{gen: gen}, traceBuf: buf}
44 }
45
46
47 func (w traceWriter) end() {
48 if w.mp == nil {
49
50
51 return
52 }
53 w.mp.trace.buf[w.gen%2] = w.traceBuf
54 }
55
56
57
58
59 func (w traceWriter) ensure(maxSize int) (traceWriter, bool) {
60 refill := w.traceBuf == nil || !w.available(maxSize)
61 if refill {
62 w = w.refill(traceNoExperiment)
63 }
64 return w, refill
65 }
66
67
68 func (w traceWriter) flush() traceWriter {
69 systemstack(func() {
70 lock(&trace.lock)
71 if w.traceBuf != nil {
72 traceBufFlush(w.traceBuf, w.gen)
73 }
74 unlock(&trace.lock)
75 })
76 w.traceBuf = nil
77 return w
78 }
79
80
81
82
83 func (w traceWriter) refill(exp traceExperiment) traceWriter {
84 systemstack(func() {
85 lock(&trace.lock)
86 if w.traceBuf != nil {
87 traceBufFlush(w.traceBuf, w.gen)
88 }
89 if trace.empty != nil {
90 w.traceBuf = trace.empty
91 trace.empty = w.traceBuf.link
92 unlock(&trace.lock)
93 } else {
94 unlock(&trace.lock)
95 w.traceBuf = (*traceBuf)(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys))
96 if w.traceBuf == nil {
97 throw("trace: out of memory")
98 }
99 }
100 })
101
102 ts := traceClockNow()
103 if ts <= w.traceBuf.lastTime {
104 ts = w.traceBuf.lastTime + 1
105 }
106 w.traceBuf.lastTime = ts
107 w.traceBuf.link = nil
108 w.traceBuf.pos = 0
109
110
111 mID := ^uint64(0)
112 if w.mp != nil {
113 mID = uint64(w.mp.procid)
114 }
115
116
117 if exp == traceNoExperiment {
118 w.byte(byte(traceEvEventBatch))
119 } else {
120 w.byte(byte(traceEvExperimentalBatch))
121 w.byte(byte(exp))
122 }
123 w.varint(uint64(w.gen))
124 w.varint(uint64(mID))
125 w.varint(uint64(ts))
126 w.traceBuf.lenPos = w.varintReserve()
127 return w
128 }
129
130
131 type traceBufQueue struct {
132 head, tail *traceBuf
133 }
134
135
136 func (q *traceBufQueue) push(buf *traceBuf) {
137 buf.link = nil
138 if q.head == nil {
139 q.head = buf
140 } else {
141 q.tail.link = buf
142 }
143 q.tail = buf
144 }
145
146
147 func (q *traceBufQueue) pop() *traceBuf {
148 buf := q.head
149 if buf == nil {
150 return nil
151 }
152 q.head = buf.link
153 if q.head == nil {
154 q.tail = nil
155 }
156 buf.link = nil
157 return buf
158 }
159
160 func (q *traceBufQueue) empty() bool {
161 return q.head == nil
162 }
163
164
165 type traceBufHeader struct {
166 link *traceBuf
167 lastTime traceTime
168 pos int
169 lenPos int
170 }
171
172
173
174
175 type traceBuf struct {
176 _ sys.NotInHeap
177 traceBufHeader
178 arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte
179 }
180
181
182 func (buf *traceBuf) byte(v byte) {
183 buf.arr[buf.pos] = v
184 buf.pos++
185 }
186
187
188 func (buf *traceBuf) varint(v uint64) {
189 pos := buf.pos
190 arr := buf.arr[pos : pos+traceBytesPerNumber]
191 for i := range arr {
192 if v < 0x80 {
193 pos += i + 1
194 arr[i] = byte(v)
195 break
196 }
197 arr[i] = 0x80 | byte(v)
198 v >>= 7
199 }
200 buf.pos = pos
201 }
202
203
204
205
206 func (buf *traceBuf) varintReserve() int {
207 p := buf.pos
208 buf.pos += traceBytesPerNumber
209 return p
210 }
211
212
213 func (buf *traceBuf) stringData(s string) {
214 buf.pos += copy(buf.arr[buf.pos:], s)
215 }
216
217 func (buf *traceBuf) available(size int) bool {
218 return len(buf.arr)-buf.pos >= size
219 }
220
221
222
223
224
225 func (buf *traceBuf) varintAt(pos int, v uint64) {
226 for i := 0; i < traceBytesPerNumber; i++ {
227 if i < traceBytesPerNumber-1 {
228 buf.arr[pos] = 0x80 | byte(v)
229 } else {
230 buf.arr[pos] = byte(v)
231 }
232 v >>= 7
233 pos++
234 }
235 if v != 0 {
236 throw("v could not fit in traceBytesPerNumber")
237 }
238 }
239
240
241
242
243
244
245 func traceBufFlush(buf *traceBuf, gen uintptr) {
246 assertLockHeld(&trace.lock)
247
248
249
250
251
252
253
254
255
256 buf.varintAt(buf.lenPos, uint64(buf.pos-(buf.lenPos+traceBytesPerNumber)))
257 trace.full[gen%2].push(buf)
258
259
260
261 if !trace.workAvailable.Load() {
262 trace.workAvailable.Store(true)
263 }
264 }
265
View as plain text