runtime: add execution tracing functionality

This is first patch of series of patches that implement tracing functionality.
Design doc:
https://docs.google.com/document/u/1/d/1FP5apqzBgr7ahCCgFO-yoVhk4YZrNIDNf9RybngBc14/pub
Full change:
https://codereview.appspot.com/146920043

Change-Id: I84588348bb05a6f6a102c230f3bca6380a3419fe
Reviewed-on: https://go-review.googlesource.com/1450
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 697ff69..f0f8c1a 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -213,6 +213,7 @@
 	sigcode1     uintptr
 	sigpc        uintptr
 	gopc         uintptr // pc of go statement that created this goroutine
+	startpc      uintptr // pc of goroutine function
 	racectx      uintptr
 	waiting      *sudog // sudog structures this g is waiting on (that have a valid elem ptr)
 }
@@ -324,6 +325,8 @@
 	gfree    *g
 	gfreecnt int32
 
+	tracebuf *traceBuf
+
 	pad [64]byte
 }
 
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
new file mode 100644
index 0000000..17d0298
--- /dev/null
+++ b/src/runtime/trace.go
@@ -0,0 +1,790 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go execution tracer.
+// The tracer captures a wide range of execution events like goroutine
+// creation/blocking/unblocking, syscall enter/exit/block, GC-related events,
+// changes of heap size, processor start/stop, etc and writes them to a buffer
+// in a compact form. A precise nanosecond-precision timestamp and a stack
+// trace is captured for most events.
+// See http://golang.org/s/go15trace for more info.
+
+package runtime
+
+import "unsafe"
+
+// Event types in the trace, args are given in square brackets.
+const (
+	traceEvNone           = 0  // unused
+	traceEvBatch          = 1  // start of per-P batch of events [pid, timestamp]
+	traceEvFrequency      = 2  // contains tracer timer frequency [frequency (ticks per second)]
+	traceEvStack          = 3  // stack [stack id, number of PCs, array of PCs]
+	traceEvGomaxprocs     = 4  // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
+	traceEvProcStart      = 5  // start of P [timestamp]
+	traceEvProcStop       = 6  // stop of P [timestamp]
+	traceEvGCStart        = 7  // GC start [timestamp, stack id]
+	traceEvGCDone         = 8  // GC done [timestamp]
+	traceEvGCScanStart    = 9  // GC scan start [timestamp]
+	traceEvGCScanDone     = 10 // GC scan done [timestamp]
+	traceEvGCSweepStart   = 11 // GC sweep start [timestamp, stack id]
+	traceEvGCSweepDone    = 12 // GC sweep done [timestamp]
+	traceEvGoCreate       = 13 // goroutine creation [timestamp, new goroutine id, start PC, stack id]
+	traceEvGoStart        = 14 // goroutine starts running [timestamp, goroutine id]
+	traceEvGoEnd          = 15 // goroutine ends [timestamp]
+	traceEvGoStop         = 16 // goroutine stops (like in select{}) [timestamp, stack]
+	traceEvGoSched        = 17 // goroutine calls Gosched [timestamp, stack]
+	traceEvGoPreempt      = 18 // goroutine is preempted [timestamp, stack]
+	traceEvGoSleep        = 19 // goroutine calls Sleep [timestamp, stack]
+	traceEvGoBlock        = 20 // goroutine blocks [timestamp, stack]
+	traceEvGoUnblock      = 21 // goroutine is unblocked [timestamp, goroutine id, stack]
+	traceEvGoBlockSend    = 22 // goroutine blocks on chan send [timestamp, stack]
+	traceEvGoBlockRecv    = 23 // goroutine blocks on chan recv [timestamp, stack]
+	traceEvGoBlockSelect  = 24 // goroutine blocks on select [timestamp, stack]
+	traceEvGoBlockSync    = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
+	traceEvGoBlockCond    = 26 // goroutine blocks on Cond [timestamp, stack]
+	traceEvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
+	traceEvGoSysCall      = 28 // syscall enter [timestamp, stack]
+	traceEvGoSysExit      = 29 // syscall exit [timestamp, goroutine id]
+	traceEvGoSysBlock     = 30 // syscall blocks [timestamp, stack]
+	traceEvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
+	traceEvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
+	traceEvHeapAlloc      = 33 // memstats.heap_alloc change [timestamp, heap_alloc]
+	traceEvNextGC         = 34 // memstats.next_gc change [timestamp, next_gc]
+	traceEvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
+	traceEvCount          = 36
+)
+
+const (
+	// Timestamps in trace are cputicks/traceTickDiv.
+	// This makes absolute values of timestamp diffs smaller,
+	// and so they are encoded in less number of bytes.
+	// 64 is somewhat arbitrary (one tick is ~20ns on a 3GHz machine).
+	traceTickDiv = 64
+	// Maximum number of PCs in a single stack trace.
+	// Since events contain only stack id rather than whole stack trace,
+	// we can allow quite large values here.
+	traceStackSize = 128
+	// Identifier of a fake P that is used when we trace without a real P.
+	traceGlobProc = -1
+	// Maximum number of bytes to encode uint64 in base-128.
+	traceBytesPerNumber = 10
+	// Shift of the number of arguments in the first event byte.
+	traceArgCountShift = 6
+)
+
+// trace is global tracing context.
+var trace struct {
+	lock          mutex     // protects the following members
+	lockOwner     *g        // to avoid deadlocks during recursive lock locks
+	enabled       bool      // when set runtime traces events
+	shutdown      bool      // set when we are waiting for trace reader to finish after setting enabled to false
+	headerWritten bool      // whether ReadTrace has emitted trace header
+	footerWritten bool      // whether ReadTrace has emitted trace footer
+	shutdownSema  uint32    // used to wait for ReadTrace completion
+	ticksStart    int64     // cputicks when tracing was started
+	ticksEnd      int64     // cputicks when tracing was stopped
+	timeStart     int64     // nanotime when tracing was started
+	timeEnd       int64     // nanotime when tracing was stopped
+	reading       *traceBuf // buffer currently handed off to user
+	empty         *traceBuf // stack of empty buffers
+	fullHead      *traceBuf // queue of full buffers
+	fullTail      *traceBuf
+	reader        *g              // goroutine that called ReadTrace, or nil
+	stackTab      traceStackTable // maps stack traces to unique ids
+
+	bufLock mutex     // protects buf
+	buf     *traceBuf // global trace buffer, used when running without a p
+}
+
+// traceBufHeader is per-P tracing buffer.
+type traceBufHeader struct {
+	link      *traceBuf               // in trace.empty/full
+	lastTicks uint64                  // when we wrote the last event
+	buf       []byte                  // trace data, always points to traceBuf.arr
+	stk       [traceStackSize]uintptr // scratch buffer for traceback
+}
+
+// traceBuf is per-P tracing buffer.
+type traceBuf struct {
+	traceBufHeader
+	arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf
+}
+
+// StartTrace enables tracing for the current process.
+// While tracing, the data will be buffered and available via ReadTrace.
+// StartTrace returns an error if tracing is already enabled.
+// Most clients should use the runtime/pprof package or the testing package's
+// -test.trace flag instead of calling StartTrace directly.
+func StartTrace() error {
+	// Stop the world, so that we can take a consistent snapshot
+	// of all goroutines at the beginning of the trace.
+	semacquire(&worldsema, false)
+	_g_ := getg()
+	_g_.m.gcing = 1
+	systemstack(stoptheworld)
+
+	// We are in stop-the-world, but syscalls can finish and write to trace concurrently.
+	// Exitsyscall could check trace.enabled long before and then suddenly wake up
+	// and decide to write to trace at a random point in time.
+	// However, such syscall will use the global trace.buf buffer, because we've
+	// acquired all p's by doing stop-the-world. So this protects us from such races.
+	lock(&trace.bufLock)
+
+	if trace.enabled || trace.shutdown {
+		unlock(&trace.bufLock)
+		_g_.m.gcing = 0
+		semrelease(&worldsema)
+		systemstack(starttheworld)
+		return errorString("tracing is already enabled")
+	}
+
+	trace.ticksStart = cputicks()
+	trace.timeStart = nanotime()
+	trace.enabled = true
+	trace.headerWritten = false
+	trace.footerWritten = false
+
+	for _, gp := range allgs {
+		status := readgstatus(gp)
+		if status != _Gdead {
+			traceGoCreate(gp, gp.startpc)
+		}
+		if status == _Gwaiting {
+			traceEvent(traceEvGoWaiting, false, uint64(gp.goid))
+		}
+		if status == _Gsyscall {
+			traceEvent(traceEvGoInSyscall, false, uint64(gp.goid))
+		}
+	}
+	traceProcStart()
+	traceGoStart()
+
+	unlock(&trace.bufLock)
+
+	_g_.m.gcing = 0
+	semrelease(&worldsema)
+	systemstack(starttheworld)
+	return nil
+}
+
+// StopTrace stops tracing, if it was previously enabled.
+// StopTrace only returns after all the reads for the trace have completed.
+func StopTrace() {
+	// Stop the world so that we can collect the trace buffers from all p's below,
+	// and also to avoid races with traceEvent.
+	semacquire(&worldsema, false)
+	_g_ := getg()
+	_g_.m.gcing = 1
+	systemstack(stoptheworld)
+
+	// See the comment in StartTrace.
+	lock(&trace.bufLock)
+
+	if !trace.enabled {
+		unlock(&trace.bufLock)
+		_g_.m.gcing = 0
+		semrelease(&worldsema)
+		systemstack(starttheworld)
+		return
+	}
+
+	traceGoSched()
+	traceGoStart()
+
+	for _, p := range &allp {
+		if p == nil {
+			break
+		}
+		buf := p.tracebuf
+		if buf != nil {
+			traceFullQueue(buf)
+			p.tracebuf = nil
+		}
+	}
+	if trace.buf != nil && len(trace.buf.buf) != 0 {
+		buf := trace.buf
+		trace.buf = nil
+		traceFullQueue(buf)
+	}
+
+	trace.ticksEnd = cputicks()
+	trace.timeEnd = nanotime()
+	trace.enabled = false
+	trace.shutdown = true
+	trace.stackTab.dump()
+
+	unlock(&trace.bufLock)
+
+	_g_.m.gcing = 0
+	semrelease(&worldsema)
+	systemstack(starttheworld)
+
+	// The world is started but we've set trace.shutdown, so new tracing can't start.
+	// Wait for the trace reader to flush pending buffers and stop.
+	semacquire(&trace.shutdownSema, false)
+
+	// The lock protects us from races with StartTrace/StopTrace because they do stop-the-world.
+	lock(&trace.lock)
+	for _, p := range &allp {
+		if p == nil {
+			break
+		}
+		if p.tracebuf != nil {
+			throw("trace: non-empty trace buffer in proc")
+		}
+	}
+	if trace.buf != nil {
+		throw("trace: non-empty global trace buffer")
+	}
+	if trace.fullHead != nil || trace.fullTail != nil {
+		throw("trace: non-empty full trace buffer")
+	}
+	if trace.reading != nil || trace.reader != nil {
+		throw("trace: reading after shutdown")
+	}
+	for trace.empty != nil {
+		buf := trace.empty
+		trace.empty = buf.link
+		sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf), &memstats.other_sys)
+	}
+	trace.shutdown = false
+	unlock(&trace.lock)
+}
+
+// ReadTrace returns the next chunk of binary tracing data, blocking until data
+// is available. If tracing is turned off and all the data accumulated while it
+// was on has been returned, ReadTrace returns nil. The caller must copy the
+// returned data before calling ReadTrace again.
+// ReadTrace must be called from one goroutine at a time.
+func ReadTrace() []byte {
+	// This function may need to lock trace.lock recursively
+	// (goparkunlock -> traceGoPark -> traceEvent -> traceFlush).
+	// To allow this we use trace.lockOwner.
+	// Also this function must not allocate while holding trace.lock:
+	// allocation can call heap allocate, which will try to emit a trace
+	// event while holding heap lock.
+	lock(&trace.lock)
+	trace.lockOwner = getg()
+
+	if trace.reader != nil {
+		// More than one goroutine reads trace. This is bad.
+		// But we rather do not crash the program because of tracing,
+		// because tracing can be enabled at runtime on prod servers.
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		println("runtime: ReadTrace called from multiple goroutines simultaneously")
+		return nil
+	}
+	// Recycle the old buffer.
+	if buf := trace.reading; buf != nil {
+		buf.link = trace.empty
+		trace.empty = buf
+		trace.reading = nil
+	}
+	// Write trace header.
+	if !trace.headerWritten {
+		trace.headerWritten = true
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		return []byte("gotrace\x00")
+	}
+	// Wait for new data.
+	if trace.fullHead == nil && !trace.shutdown {
+		trace.reader = getg()
+		goparkunlock(&trace.lock, "trace reader (blocked)" /*, traceEvGoBlock*/)
+		lock(&trace.lock)
+	}
+	// Write a buffer.
+	if trace.fullHead != nil {
+		buf := traceFullDequeue()
+		trace.reading = buf
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		return buf.buf
+	}
+	// Write footer with timer frequency.
+	if !trace.footerWritten {
+		trace.footerWritten = true
+		// Use float64 because (trace.ticksEnd - trace.ticksStart) * 1e9 can overflow int64.
+		freq := float64(trace.ticksEnd-trace.ticksStart) * 1e9 / float64(trace.timeEnd-trace.timeStart) / traceTickDiv
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		var data []byte
+		data = append(data, traceEvFrequency|0<<traceArgCountShift)
+		data = traceAppend(data, uint64(freq))
+		if timers.gp != nil {
+			data = append(data, traceEvTimerGoroutine|0<<traceArgCountShift)
+			data = traceAppend(data, uint64(timers.gp.goid))
+		}
+		return data
+	}
+	// Done.
+	if trace.shutdown {
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		// trace.enabled is already reset, so can call traceable functions.
+		semrelease(&trace.shutdownSema)
+		return nil
+	}
+	// Also bad, but see the comment above.
+	trace.lockOwner = nil
+	unlock(&trace.lock)
+	println("runtime: spurious wakeup of trace reader")
+	return nil
+}
+
+// traceReader returns the trace reader that should be woken up, if any.
+func traceReader() *g {
+	if trace.reader == nil || (trace.fullHead == nil && !trace.shutdown) {
+		return nil
+	}
+	lock(&trace.lock)
+	if trace.reader == nil || (trace.fullHead == nil && !trace.shutdown) {
+		unlock(&trace.lock)
+		return nil
+	}
+	gp := trace.reader
+	trace.reader = nil
+	unlock(&trace.lock)
+	return gp
+}
+
+// traceProcFree frees trace buffer associated with pp.
+func traceProcFree(pp *p) {
+	buf := pp.tracebuf
+	pp.tracebuf = nil
+	if buf == nil {
+		return
+	}
+	lock(&trace.lock)
+	traceFullQueue(buf)
+	unlock(&trace.lock)
+}
+
+// traceFullQueue queues buf into queue of full buffers.
+func traceFullQueue(buf *traceBuf) {
+	buf.link = nil
+	if trace.fullHead == nil {
+		trace.fullHead = buf
+	} else {
+		trace.fullTail.link = buf
+	}
+	trace.fullTail = buf
+}
+
+// traceFullDequeue dequeues from queue of full buffers.
+func traceFullDequeue() *traceBuf {
+	buf := trace.fullHead
+	if buf == nil {
+		return nil
+	}
+	trace.fullHead = buf.link
+	if trace.fullHead == nil {
+		trace.fullTail = nil
+	}
+	buf.link = nil
+	return buf
+}
+
+// traceEvent writes a single event to trace buffer, flushing the buffer if necessary.
+// ev is event type.
+// If stack, write current stack id as the last argument.
+func traceEvent(ev byte, stack bool, args ...uint64) {
+	mp, pid, bufp := traceAcquireBuffer()
+	// Double-check trace.enabled now that we've done m.locks++ and acquired bufLock.
+	// This protects from races between traceEvent and StartTrace/StopTrace.
+
+	// The caller checked that trace.enabled == true, but trace.enabled might have been
+	// turned off between the check and now. Check again. traceLockBuffer did mp.locks++,
+	// StopTrace does stoptheworld, and stoptheworld waits for mp.locks to go back to zero,
+	// so if we see trace.enabled == true now, we know it's true for the rest of the function.
+	// Exitsyscall can run even during stoptheworld. The race with StartTrace/StopTrace
+	// during tracing in exitsyscall is resolved by locking trace.bufLock in traceLockBuffer.
+	if !trace.enabled {
+		traceReleaseBuffer(pid)
+		return
+	}
+	buf := *bufp
+	const maxSize = 2 + 4*traceBytesPerNumber // event type, length, timestamp, stack id and two add params
+	if buf == nil || cap(buf.buf)-len(buf.buf) < maxSize {
+		buf = traceFlush(buf)
+		*bufp = buf
+	}
+
+	ticks := uint64(cputicks()) / traceTickDiv
+	tickDiff := ticks - buf.lastTicks
+	if len(buf.buf) == 0 {
+		data := buf.buf
+		data = append(data, traceEvBatch|1<<traceArgCountShift)
+		data = traceAppend(data, uint64(pid))
+		data = traceAppend(data, ticks)
+		buf.buf = data
+		tickDiff = 0
+	}
+	buf.lastTicks = ticks
+	narg := byte(len(args))
+	if stack {
+		narg++
+	}
+	// We have only 2 bits for number of arguments.
+	// If number is >= 3, then the event type is followed by event length in bytes.
+	if narg > 3 {
+		narg = 3
+	}
+	data := buf.buf
+	data = append(data, ev|narg<<traceArgCountShift)
+	var lenp *byte
+	if narg == 3 {
+		// Reserve the byte for length assuming that length < 128.
+		data = append(data, 0)
+		lenp = &data[len(data)-1]
+	}
+	data = traceAppend(data, tickDiff)
+	for _, a := range args {
+		data = traceAppend(data, a)
+	}
+	if stack {
+		_g_ := getg()
+		gp := mp.curg
+		if gp == nil && ev == traceEvGoSysBlock {
+			gp = _g_
+		}
+		var nstk int
+		if gp == _g_ {
+			nstk = callers(1, &buf.stk[0], len(buf.stk))
+		} else if gp != nil {
+			nstk = gcallers(mp.curg, 1, &buf.stk[0], len(buf.stk))
+		}
+		id := trace.stackTab.put(buf.stk[:nstk])
+		data = traceAppend(data, uint64(id))
+	}
+	evSize := len(data) - len(buf.buf)
+	if evSize > maxSize {
+		throw("invalid length of trace event")
+	}
+	if lenp != nil {
+		// Fill in actual length.
+		*lenp = byte(evSize - 2)
+	}
+	buf.buf = data
+	traceReleaseBuffer(pid)
+}
+
+// traceAcquireBuffer returns trace buffer to use and, if necessary, locks it.
+func traceAcquireBuffer() (mp *m, pid int32, bufp **traceBuf) {
+	mp = acquirem()
+	if p := mp.p; p != nil {
+		return mp, p.id, &p.tracebuf
+	}
+	lock(&trace.bufLock)
+	return mp, traceGlobProc, &trace.buf
+}
+
+// traceReleaseBuffer releases a buffer previously acquired with traceAcquireBuffer.
+func traceReleaseBuffer(pid int32) {
+	if pid == traceGlobProc {
+		unlock(&trace.bufLock)
+	}
+	releasem(getg().m)
+}
+
+// traceFlush puts buf onto stack of full buffers and returns an empty buffer.
+func traceFlush(buf *traceBuf) *traceBuf {
+	owner := trace.lockOwner
+	dolock := owner == nil || owner != getg().m.curg
+	if dolock {
+		lock(&trace.lock)
+	}
+	if buf != nil {
+		if &buf.buf[0] != &buf.arr[0] {
+			throw("trace buffer overflow")
+		}
+		traceFullQueue(buf)
+	}
+	if trace.empty != nil {
+		buf = trace.empty
+		trace.empty = buf.link
+	} else {
+		buf = (*traceBuf)(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys))
+		if buf == nil {
+			throw("trace: out of memory")
+		}
+	}
+	buf.link = nil
+	buf.buf = buf.arr[:0]
+	buf.lastTicks = 0
+	if dolock {
+		unlock(&trace.lock)
+	}
+	return buf
+}
+
+// traceAppend appends v to buf in little-endian-base-128 encoding.
+func traceAppend(buf []byte, v uint64) []byte {
+	for ; v >= 0x80; v >>= 7 {
+		buf = append(buf, 0x80|byte(v))
+	}
+	buf = append(buf, byte(v))
+	return buf
+}
+
+// traceStackTable maps stack traces (arrays of PC's) to unique uint32 ids.
+// It is lock-free for reading.
+type traceStackTable struct {
+	lock mutex
+	seq  uint32
+	mem  traceAlloc
+	tab  [1 << 13]*traceStack
+}
+
+// traceStack is a single stack in traceStackTable.
+type traceStack struct {
+	link *traceStack
+	hash uintptr
+	id   uint32
+	n    int
+	stk  [0]uintptr // real type [n]uintptr
+}
+
+// stack returns slice of PCs.
+func (ts *traceStack) stack() []uintptr {
+	return (*[traceStackSize]uintptr)(unsafe.Pointer(&ts.stk))[:ts.n]
+}
+
+// put returns a unique id for the stack trace pcs and caches it in the table,
+// if it sees the trace for the first time.
+func (tab *traceStackTable) put(pcs []uintptr) uint32 {
+	if len(pcs) == 0 {
+		return 0
+	}
+	hash := memhash(unsafe.Pointer(&pcs[0]), uintptr(len(pcs))*unsafe.Sizeof(pcs[0]), 0)
+	// First, search the hashtable w/o the mutex.
+	if id := tab.find(pcs, hash); id != 0 {
+		return id
+	}
+	// Now, double check under the mutex.
+	lock(&tab.lock)
+	if id := tab.find(pcs, hash); id != 0 {
+		unlock(&tab.lock)
+		return id
+	}
+	// Create new record.
+	tab.seq++
+	stk := tab.newStack(len(pcs))
+	stk.hash = hash
+	stk.id = tab.seq
+	stk.n = len(pcs)
+	stkpc := stk.stack()
+	for i, pc := range pcs {
+		stkpc[i] = pc
+	}
+	part := int(hash % uintptr(len(tab.tab)))
+	stk.link = tab.tab[part]
+	atomicstorep(unsafe.Pointer(&tab.tab[part]), unsafe.Pointer(stk))
+	unlock(&tab.lock)
+	return stk.id
+}
+
+// find checks if the stack trace pcs is already present in the table.
+func (tab *traceStackTable) find(pcs []uintptr, hash uintptr) uint32 {
+	part := int(hash % uintptr(len(tab.tab)))
+Search:
+	for stk := tab.tab[part]; stk != nil; stk = stk.link {
+		if stk.hash == hash && stk.n == len(pcs) {
+			for i, stkpc := range stk.stack() {
+				if stkpc != pcs[i] {
+					continue Search
+				}
+			}
+			return stk.id
+		}
+	}
+	return 0
+}
+
+// newStack allocates a new stack of size n.
+func (tab *traceStackTable) newStack(n int) *traceStack {
+	return (*traceStack)(tab.mem.alloc(unsafe.Sizeof(traceStack{}) + uintptr(n)*ptrSize))
+}
+
+// dump writes all previously cached stacks to trace buffers,
+// releases all memory and resets state.
+func (tab *traceStackTable) dump() {
+	var tmp [(2 + traceStackSize) * traceBytesPerNumber]byte
+	buf := traceFlush(nil)
+	for _, stk := range tab.tab {
+		for ; stk != nil; stk = stk.link {
+			maxSize := 1 + (3+stk.n)*traceBytesPerNumber
+			if cap(buf.buf)-len(buf.buf) < maxSize {
+				buf = traceFlush(buf)
+			}
+			// Form the event in the temp buffer, we need to know the actual length.
+			tmpbuf := tmp[:0]
+			tmpbuf = traceAppend(tmpbuf, uint64(stk.id))
+			tmpbuf = traceAppend(tmpbuf, uint64(stk.n))
+			for _, pc := range stk.stack() {
+				tmpbuf = traceAppend(tmpbuf, uint64(pc))
+			}
+			// Now copy to the buffer.
+			data := buf.buf
+			data = append(data, traceEvStack|3<<traceArgCountShift)
+			data = traceAppend(data, uint64(len(tmpbuf)))
+			data = append(data, tmpbuf...)
+			buf.buf = data
+		}
+	}
+
+	lock(&trace.lock)
+	traceFullQueue(buf)
+	unlock(&trace.lock)
+
+	tab.mem.drop()
+	*tab = traceStackTable{}
+}
+
+// traceAlloc is a non-thread-safe region allocator.
+// It holds a linked list of traceAllocBlock.
+type traceAlloc struct {
+	head *traceAllocBlock
+	off  uintptr
+}
+
+// traceAllocBlock is a block in traceAlloc.
+type traceAllocBlock struct {
+	next *traceAllocBlock
+	data [64<<10 - ptrSize]byte
+}
+
+// alloc allocates n-byte block.
+func (a *traceAlloc) alloc(n uintptr) unsafe.Pointer {
+	n = round(n, ptrSize)
+	if a.head == nil || a.off+n > uintptr(len(a.head.data)) {
+		if n > uintptr(len(a.head.data)) {
+			throw("trace: alloc too large")
+		}
+		block := (*traceAllocBlock)(sysAlloc(unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys))
+		if block == nil {
+			throw("trace: out of memory")
+		}
+		block.next = a.head
+		a.head = block
+		a.off = 0
+	}
+	p := &a.head.data[a.off]
+	a.off += n
+	return unsafe.Pointer(p)
+}
+
+// drop frees all previously allocated memory and resets the allocator.
+func (a *traceAlloc) drop() {
+	for a.head != nil {
+		block := a.head
+		a.head = block.next
+		sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys)
+	}
+}
+
+// The following functions write specific events to trace.
+
+func traceGomaxprocs(procs int32) {
+	traceEvent(traceEvGomaxprocs, true, uint64(procs))
+}
+
+func traceProcStart() {
+	traceEvent(traceEvProcStart, false)
+}
+
+func traceProcStop(pp *p) {
+	// Sysmon and stoptheworld can stop Ps blocked in syscalls,
+	// to handle this we temporary employ the P.
+	mp := acquirem()
+	oldp := mp.p
+	mp.p = pp
+	traceEvent(traceEvProcStop, false)
+	mp.p = oldp
+	releasem(mp)
+}
+
+func traceGCStart() {
+	traceEvent(traceEvGCStart, true)
+}
+
+func traceGCDone() {
+	traceEvent(traceEvGCDone, false)
+}
+
+func traceGCScanStart() {
+	traceEvent(traceEvGCScanStart, false)
+}
+
+func traceGCScanDone() {
+	traceEvent(traceEvGCScanDone, false)
+}
+
+func traceGCSweepStart() {
+	traceEvent(traceEvGCSweepStart, true)
+}
+
+func traceGCSweepDone() {
+	traceEvent(traceEvGCSweepDone, false)
+}
+
+func traceGoCreate(newg *g, pc uintptr) {
+	traceEvent(traceEvGoCreate, true, uint64(newg.goid), uint64(pc))
+}
+
+func traceGoStart() {
+	traceEvent(traceEvGoStart, false, uint64(getg().m.curg.goid))
+}
+
+func traceGoEnd() {
+	traceEvent(traceEvGoEnd, false)
+}
+
+func traceGoSched() {
+	traceEvent(traceEvGoSched, true)
+}
+
+func traceGoPreempt() {
+	traceEvent(traceEvGoPreempt, true)
+}
+
+func traceGoStop() {
+	traceEvent(traceEvGoStop, true)
+}
+
+func traceGoPark(traceEv byte, gp *g) {
+	traceEvent(traceEv, true)
+}
+
+func traceGoUnpark(gp *g) {
+	traceEvent(traceEvGoUnblock, true, uint64(gp.goid))
+}
+
+func traceGoSysCall() {
+	traceEvent(traceEvGoSysCall, true)
+}
+
+func traceGoSysExit() {
+	traceEvent(traceEvGoSysExit, false, uint64(getg().m.curg.goid))
+}
+
+func traceGoSysBlock(pp *p) {
+	// Sysmon and stoptheworld can declare syscalls running on remote Ps as blocked,
+	// to handle this we temporary employ the P.
+	mp := acquirem()
+	oldp := mp.p
+	mp.p = pp
+	traceEvent(traceEvGoSysBlock, true)
+	mp.p = oldp
+	releasem(mp)
+}
+
+func traceHeapAlloc() {
+	traceEvent(traceEvHeapAlloc, false, memstats.heap_alloc)
+}
+
+func traceNextGC() {
+	traceEvent(traceEvNextGC, false, memstats.next_gc)
+}