package runtime
import (
"runtime/internal/sys"
"unsafe"
)
const traceBytesPerNumber = 10
type traceWriter struct {
traceLocker
*traceBuf
}
func (tl traceLocker ) writer () traceWriter {
return traceWriter {traceLocker : tl , traceBuf : tl .mp .trace .buf [tl .gen %2 ]}
}
func unsafeTraceWriter (gen uintptr , buf *traceBuf ) traceWriter {
return traceWriter {traceLocker : traceLocker {gen : gen }, traceBuf : buf }
}
func (w traceWriter ) end () {
if w .mp == nil {
return
}
w .mp .trace .buf [w .gen %2 ] = w .traceBuf
}
func (w traceWriter ) ensure (maxSize int ) (traceWriter , bool ) {
refill := w .traceBuf == nil || !w .available (maxSize )
if refill {
w = w .refill (traceNoExperiment )
}
return w , refill
}
func (w traceWriter ) flush () traceWriter {
systemstack (func () {
lock (&trace .lock )
if w .traceBuf != nil {
traceBufFlush (w .traceBuf , w .gen )
}
unlock (&trace .lock )
})
w .traceBuf = nil
return w
}
func (w traceWriter ) refill (exp traceExperiment ) traceWriter {
systemstack (func () {
lock (&trace .lock )
if w .traceBuf != nil {
traceBufFlush (w .traceBuf , w .gen )
}
if trace .empty != nil {
w .traceBuf = trace .empty
trace .empty = w .traceBuf .link
unlock (&trace .lock )
} else {
unlock (&trace .lock )
w .traceBuf = (*traceBuf )(sysAlloc (unsafe .Sizeof (traceBuf {}), &memstats .other_sys ))
if w .traceBuf == nil {
throw ("trace: out of memory" )
}
}
})
ts := traceClockNow ()
if ts <= w .traceBuf .lastTime {
ts = w .traceBuf .lastTime + 1
}
w .traceBuf .lastTime = ts
w .traceBuf .link = nil
w .traceBuf .pos = 0
mID := ^uint64 (0 )
if w .mp != nil {
mID = uint64 (w .mp .procid )
}
if exp == traceNoExperiment {
w .byte (byte (traceEvEventBatch ))
} else {
w .byte (byte (traceEvExperimentalBatch ))
w .byte (byte (exp ))
}
w .varint (uint64 (w .gen ))
w .varint (uint64 (mID ))
w .varint (uint64 (ts ))
w .traceBuf .lenPos = w .varintReserve ()
return w
}
type traceBufQueue struct {
head , tail *traceBuf
}
func (q *traceBufQueue ) push (buf *traceBuf ) {
buf .link = nil
if q .head == nil {
q .head = buf
} else {
q .tail .link = buf
}
q .tail = buf
}
func (q *traceBufQueue ) pop () *traceBuf {
buf := q .head
if buf == nil {
return nil
}
q .head = buf .link
if q .head == nil {
q .tail = nil
}
buf .link = nil
return buf
}
func (q *traceBufQueue ) empty () bool {
return q .head == nil
}
type traceBufHeader struct {
link *traceBuf
lastTime traceTime
pos int
lenPos int
}
type traceBuf struct {
_ sys .NotInHeap
traceBufHeader
arr [64 <<10 - unsafe .Sizeof (traceBufHeader {})]byte
}
func (buf *traceBuf ) byte (v byte ) {
buf .arr [buf .pos ] = v
buf .pos ++
}
func (buf *traceBuf ) varint (v uint64 ) {
pos := buf .pos
arr := buf .arr [pos : pos +traceBytesPerNumber ]
for i := range arr {
if v < 0x80 {
pos += i + 1
arr [i ] = byte (v )
break
}
arr [i ] = 0x80 | byte (v )
v >>= 7
}
buf .pos = pos
}
func (buf *traceBuf ) varintReserve () int {
p := buf .pos
buf .pos += traceBytesPerNumber
return p
}
func (buf *traceBuf ) stringData (s string ) {
buf .pos += copy (buf .arr [buf .pos :], s )
}
func (buf *traceBuf ) available (size int ) bool {
return len (buf .arr )-buf .pos >= size
}
func (buf *traceBuf ) varintAt (pos int , v uint64 ) {
for i := 0 ; i < traceBytesPerNumber ; i ++ {
if i < traceBytesPerNumber -1 {
buf .arr [pos ] = 0x80 | byte (v )
} else {
buf .arr [pos ] = byte (v )
}
v >>= 7
pos ++
}
if v != 0 {
throw ("v could not fit in traceBytesPerNumber" )
}
}
func traceBufFlush (buf *traceBuf , gen uintptr ) {
assertLockHeld (&trace .lock )
buf .varintAt (buf .lenPos , uint64 (buf .pos -(buf .lenPos +traceBytesPerNumber )))
trace .full [gen %2 ].push (buf )
if !trace .workAvailable .Load () {
trace .workAvailable .Store (true )
}
}
The pages are generated with Golds v0.7.6 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .