Source file
src/runtime/pagetrace_on.go
Documentation: runtime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 package runtime
41
42 import (
43 "runtime/internal/sys"
44 "unsafe"
45 )
46
47
48
49
50
51
52
53 func pageTraceAlloc(pp *p, now int64, base, npages uintptr) {
54 if pageTrace.enabled {
55 if now == 0 {
56 now = nanotime()
57 }
58 pageTraceEmit(pp, now, base, npages, pageTraceAllocEvent)
59 }
60 }
61
62
63
64
65
66
67
68 func pageTraceFree(pp *p, now int64, base, npages uintptr) {
69 if pageTrace.enabled {
70 if now == 0 {
71 now = nanotime()
72 }
73 pageTraceEmit(pp, now, base, npages, pageTraceFreeEvent)
74 }
75 }
76
77
78
79
80
81
82
83 func pageTraceScav(pp *p, now int64, base, npages uintptr) {
84 if pageTrace.enabled {
85 if now == 0 {
86 now = nanotime()
87 }
88 pageTraceEmit(pp, now, base, npages, pageTraceScavEvent)
89 }
90 }
91
92
93 type pageTraceEventType uint8
94
95 const (
96 pageTraceSyncEvent pageTraceEventType = iota
97 pageTraceAllocEvent
98 pageTraceFreeEvent
99 pageTraceScavEvent
100 )
101
102
103
104
105
106
107 func pageTraceEmit(pp *p, now int64, base, npages uintptr, typ pageTraceEventType) {
108
109 var tbp *pageTraceBuf
110 pid := int32(-1)
111 if pp == nil {
112
113 lock(&pageTrace.lock)
114 tbp = &pageTrace.buf
115 } else {
116 tbp = &pp.pageTraceBuf
117 pid = pp.id
118 }
119
120
121 tb := *tbp
122 if tb.buf == nil {
123 tb.buf = (*pageTraceEvents)(sysAlloc(pageTraceBufSize, &memstats.other_sys))
124 tb = tb.writePid(pid)
125 }
126
127
128 if now < tb.timeBase {
129 now = tb.timeBase
130 }
131 if now-tb.timeBase >= pageTraceTimeMaxDelta {
132 tb.timeBase = now
133 tb = tb.writeSync(pid)
134 }
135
136
137 tb = tb.writeEvent(pid, now, base, npages, typ)
138
139
140 *tbp = tb
141 if pp == nil {
142 unlock(&pageTrace.lock)
143 }
144 }
145
146 const (
147 pageTraceBufSize = 32 << 10
148
149
150 pageTraceTimeLostBits = 7
151 pageTraceTimeDeltaBits = 16
152 pageTraceTimeMaxDelta = 1 << (pageTraceTimeLostBits + pageTraceTimeDeltaBits)
153 )
154
155
156 type pageTraceEvents struct {
157 _ sys.NotInHeap
158 events [pageTraceBufSize / 8]uint64
159 }
160
161
162
163 type pageTraceBuf struct {
164 buf *pageTraceEvents
165 len int
166 timeBase int64
167 finished bool
168 }
169
170
171
172
173
174
175
176
177
178 func (tb pageTraceBuf) writePid(pid int32) pageTraceBuf {
179 e := uint64(int64(pid))<<3 | 0b100 | uint64(pageTraceSyncEvent)
180 tb.buf.events[tb.len] = e
181 tb.len++
182 return tb
183 }
184
185
186
187
188
189
190 func (tb pageTraceBuf) writeSync(pid int32) pageTraceBuf {
191 if tb.len+1 > len(tb.buf.events) {
192
193 return tb.flush(pid, tb.timeBase)
194 }
195 e := ((uint64(tb.timeBase) >> pageTraceTimeLostBits) << 3) | uint64(pageTraceSyncEvent)
196 tb.buf.events[tb.len] = e
197 tb.len++
198 return tb
199 }
200
201
202
203
204
205
206
207
208
209
210
211
212 func (tb pageTraceBuf) writeEvent(pid int32, now int64, base, npages uintptr, typ pageTraceEventType) pageTraceBuf {
213 large := 0
214 np := npages
215 if npages >= 1024 {
216 large = 1
217 np = 0
218 }
219 if tb.len+1+large > len(tb.buf.events) {
220 tb = tb.flush(pid, now)
221 }
222 if base%pageSize != 0 {
223 throw("base address not page aligned")
224 }
225 e := uint64(base)
226
227 e |= uint64(typ)
228 e |= uint64(large) << 2
229 e |= uint64(np) << 3
230
231 e |= uint64((now-tb.timeBase)>>pageTraceTimeLostBits) << (64 - pageTraceTimeDeltaBits)
232 tb.buf.events[tb.len] = e
233 if large != 0 {
234
235 tb.buf.events[tb.len+1] = uint64(npages)
236 }
237 tb.len += 1 + large
238 return tb
239 }
240
241
242
243
244
245
246
247 func (tb pageTraceBuf) flush(pid int32, now int64) pageTraceBuf {
248 if !tb.finished {
249 lock(&pageTrace.fdLock)
250 writeFull(uintptr(pageTrace.fd), (*byte)(unsafe.Pointer(&tb.buf.events[0])), tb.len*8)
251 unlock(&pageTrace.fdLock)
252 }
253 tb.len = 0
254 tb.timeBase = now
255 return tb.writePid(pid).writeSync(pid)
256 }
257
258 var pageTrace struct {
259
260
261
262
263 enabled bool
264
265
266
267
268 lock mutex
269 buf pageTraceBuf
270
271
272
273
274 fdLock mutex
275 fd int32
276 }
277
278
279
280
281 func initPageTrace(env string) {
282 var value string
283 for env != "" {
284 elt, rest := env, ""
285 for i := 0; i < len(env); i++ {
286 if env[i] == ',' {
287 elt, rest = env[:i], env[i+1:]
288 break
289 }
290 }
291 env = rest
292 if hasPrefix(elt, "pagetrace=") {
293 value = elt[len("pagetrace="):]
294 break
295 }
296 }
297 pageTrace.fd = -1
298 if canCreateFile && value != "" {
299 var tmp [4096]byte
300 if len(value) != 0 && len(value) < 4096 {
301 copy(tmp[:], value)
302 pageTrace.fd = create(&tmp[0], 0o664)
303 }
304 }
305 pageTrace.enabled = pageTrace.fd >= 0
306 }
307
308
309 func finishPageTrace() {
310 if !pageTrace.enabled {
311 return
312 }
313
314 semacquire(&worldsema)
315 systemstack(func() {
316
317 pageTrace.enabled = false
318
319
320 forEachP(waitReasonPageTraceFlush, func(pp *p) {
321 if pp.pageTraceBuf.buf != nil {
322 pp.pageTraceBuf = pp.pageTraceBuf.flush(pp.id, nanotime())
323 }
324 pp.pageTraceBuf.finished = true
325 })
326
327
328 lock(&pageTrace.lock)
329 if pageTrace.buf.buf != nil {
330 pageTrace.buf = pageTrace.buf.flush(-1, nanotime())
331 }
332 pageTrace.buf.finished = true
333 unlock(&pageTrace.lock)
334
335
336 lock(&pageTrace.fdLock)
337 closefd(pageTrace.fd)
338 pageTrace.fd = -1
339 unlock(&pageTrace.fdLock)
340 })
341 semrelease(&worldsema)
342 }
343
344
345 func writeFull(fd uintptr, b *byte, bn int) {
346 for bn > 0 {
347 n := write(fd, unsafe.Pointer(b), int32(bn))
348 if n == -_EINTR || n == -_EAGAIN {
349 continue
350 }
351 if n < 0 {
352 print("errno=", -n, "\n")
353 throw("writeBytes: bad write")
354 }
355 bn -= int(n)
356 b = addb(b, uintptr(n))
357 }
358 }
359
View as plain text