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()
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 func (w traceWriter) refill() traceWriter {
82 systemstack(func() {
83 lock(&trace.lock)
84 if w.traceBuf != nil {
85 traceBufFlush(w.traceBuf, w.gen)
86 }
87 if trace.empty != nil {
88 w.traceBuf = trace.empty
89 trace.empty = w.traceBuf.link
90 unlock(&trace.lock)
91 } else {
92 unlock(&trace.lock)
93 w.traceBuf = (*traceBuf)(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys))
94 if w.traceBuf == nil {
95 throw("trace: out of memory")
96 }
97 }
98 })
99
100 ts := traceClockNow()
101 if ts <= w.traceBuf.lastTime {
102 ts = w.traceBuf.lastTime + 1
103 }
104 w.traceBuf.lastTime = ts
105 w.traceBuf.link = nil
106 w.traceBuf.pos = 0
107
108
109 mID := ^uint64(0)
110 if w.mp != nil {
111 mID = uint64(w.mp.procid)
112 }
113
114
115 w.byte(byte(traceEvEventBatch))
116 w.varint(uint64(w.gen))
117 w.varint(uint64(mID))
118 w.varint(uint64(ts))
119 w.traceBuf.lenPos = w.varintReserve()
120 return w
121 }
122
123
124 type traceBufQueue struct {
125 head, tail *traceBuf
126 }
127
128
129 func (q *traceBufQueue) push(buf *traceBuf) {
130 buf.link = nil
131 if q.head == nil {
132 q.head = buf
133 } else {
134 q.tail.link = buf
135 }
136 q.tail = buf
137 }
138
139
140 func (q *traceBufQueue) pop() *traceBuf {
141 buf := q.head
142 if buf == nil {
143 return nil
144 }
145 q.head = buf.link
146 if q.head == nil {
147 q.tail = nil
148 }
149 buf.link = nil
150 return buf
151 }
152
153 func (q *traceBufQueue) empty() bool {
154 return q.head == nil
155 }
156
157
158 type traceBufHeader struct {
159 link *traceBuf
160 lastTime traceTime
161 pos int
162 lenPos int
163 }
164
165
166
167
168 type traceBuf struct {
169 _ sys.NotInHeap
170 traceBufHeader
171 arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte
172 }
173
174
175 func (buf *traceBuf) byte(v byte) {
176 buf.arr[buf.pos] = v
177 buf.pos++
178 }
179
180
181 func (buf *traceBuf) varint(v uint64) {
182 pos := buf.pos
183 arr := buf.arr[pos : pos+traceBytesPerNumber]
184 for i := range arr {
185 if v < 0x80 {
186 pos += i + 1
187 arr[i] = byte(v)
188 break
189 }
190 arr[i] = 0x80 | byte(v)
191 v >>= 7
192 }
193 buf.pos = pos
194 }
195
196
197
198
199 func (buf *traceBuf) varintReserve() int {
200 p := buf.pos
201 buf.pos += traceBytesPerNumber
202 return p
203 }
204
205
206 func (buf *traceBuf) stringData(s string) {
207 buf.pos += copy(buf.arr[buf.pos:], s)
208 }
209
210 func (buf *traceBuf) available(size int) bool {
211 return len(buf.arr)-buf.pos >= size
212 }
213
214
215
216
217
218 func (buf *traceBuf) varintAt(pos int, v uint64) {
219 for i := 0; i < traceBytesPerNumber; i++ {
220 if i < traceBytesPerNumber-1 {
221 buf.arr[pos] = 0x80 | byte(v)
222 } else {
223 buf.arr[pos] = byte(v)
224 }
225 v >>= 7
226 pos++
227 }
228 if v != 0 {
229 throw("v could not fit in traceBytesPerNumber")
230 }
231 }
232
233
234
235
236
237
238 func traceBufFlush(buf *traceBuf, gen uintptr) {
239 assertLockHeld(&trace.lock)
240
241
242
243
244
245
246
247
248
249 buf.varintAt(buf.lenPos, uint64(buf.pos-(buf.lenPos+traceBytesPerNumber)))
250 trace.full[gen%2].push(buf)
251
252
253
254 if !trace.workAvailable.Load() {
255 trace.workAvailable.Store(true)
256 }
257 }
258
View as plain text