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