Skip to content

Instantly share code, notes, and snippets.

@DanielMorsing
Last active June 16, 2019 12:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DanielMorsing/591b26c5f0dbe0d780c45be124a6c6b9 to your computer and use it in GitHub Desktop.
Save DanielMorsing/591b26c5f0dbe0d780c45be124a6c6b9 to your computer and use it in GitHub Desktop.
Patch that adds stack growth events to the trace viewer
diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go
index f39a397d0d..de8348e996 100644
--- a/src/cmd/trace/trace.go
+++ b/src/cmd/trace/trace.go
@@ -739,6 +739,8 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
ctx.emitInstant(ev, "task start", "user event")
case trace.EvUserTaskEnd:
ctx.emitInstant(ev, "task end", "user event")
+ case trace.EvGoCopyStack:
+ ctx.emitInstant(ev, "copystack", "")
}
// Emit any counter updates.
ctx.emitThreadCounters(ev)
diff --git a/src/internal/trace/parser.go b/src/internal/trace/parser.go
index c371ff3092..bf2ec56721 100644
--- a/src/internal/trace/parser.go
+++ b/src/internal/trace/parser.go
@@ -437,8 +437,11 @@ func parseEvents(ver int, rawEvents []rawEvent, strings map[uint64]string) (even
EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet,
EvGoSysBlock, EvGoBlockGC:
lastG = 0
- case EvGoSysExit, EvGoWaiting, EvGoInSyscall:
+ case EvGoSysExit, EvGoWaiting, EvGoInSyscall, EvGoCopyStack:
e.G = e.Args[0]
+ if raw.typ == EvGoCopyStack {
+ e.P = int(e.Args[1])
+ }
case EvUserTaskCreate:
// e.Args 0: taskID, 1:parentID, 2:nameID
e.SArgs = []string{strings[e.Args[2]]}
@@ -835,6 +838,11 @@ func postProcessTrace(ver int, events []*Event) error {
} else {
return fmt.Errorf("invalid user region mode: %q", ev)
}
+ case EvGoCopyStack:
+ if err := checkRunning(p, g, ev, true); err != nil {
+ return err
+ }
+ g.ev = ev
}
gs[ev.G] = g
@@ -1058,7 +1066,8 @@ const (
EvUserTaskEnd = 46 // end of task [timestamp, internal task id, stack]
EvUserRegion = 47 // trace.WithRegion [timestamp, internal task id, mode(0:start, 1:end), stack, name string]
EvUserLog = 48 // trace.Log [timestamp, internal id, key string id, stack, value string]
- EvCount = 49
+ EvGoCopyStack = 49 // copystack [timestamp, goroutine id]
+ EvCount = 50
)
var EventDescriptions = [EvCount]struct {
@@ -1117,4 +1126,5 @@ var EventDescriptions = [EvCount]struct {
EvUserTaskEnd: {"UserTaskEnd", 1011, true, []string{"taskid"}, nil},
EvUserRegion: {"UserRegion", 1011, true, []string{"taskid", "mode", "typeid"}, []string{"name"}},
EvUserLog: {"UserLog", 1011, true, []string{"id", "keyid"}, []string{"category", "message"}},
+ EvGoCopyStack: {"GoCopyStack", 1011, true, []string{"g", "pid"}, nil},
}
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index d5d09ba7d7..5e2fbc875c 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -1052,6 +1052,9 @@ func newstack() {
print("stack grow done\n")
}
casgstatus(gp, _Gcopystack, _Grunning)
+ if trace.enabled {
+ traceCopyStack(gp)
+ }
gogo(&gp.sched)
}
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index 08e92d2efe..52aa3de378 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -68,7 +68,8 @@ const (
traceEvUserTaskEnd = 46 // end of a task [timestamp, internal task id, stack]
traceEvUserRegion = 47 // trace.WithRegion [timestamp, internal task id, mode(0:start, 1:end), stack, name string]
traceEvUserLog = 48 // trace.Log [timestamp, internal task id, key string id, stack, value string]
- traceEvCount = 49
+ traceEvGoCopyStack = 49 // copystack [timestamp, goroutine id]
+ traceEvCount = 50
// Byte is used but only 6 bits are available for event type.
// The remaining 2 bits are used to specify the number of arguments.
// That means, the max event type value is 63.
@@ -609,6 +610,12 @@ func traceAcquireBuffer() (mp *m, pid int32, bufp *traceBufPtr) {
return mp, traceGlobProc, &trace.buf
}
+func traceAcquireGlobal() (mp *m, pid int32, bufp *traceBufPtr) {
+ mp = acquirem()
+ lock(&trace.bufLock)
+ return mp, traceGlobProc, &trace.buf
+}
+
// traceReleaseBuffer releases a buffer previously acquired with traceAcquireBuffer.
func traceReleaseBuffer(pid int32) {
if pid == traceGlobProc {
@@ -1219,3 +1226,19 @@ func trace_userLog(id uint64, category, message string) {
traceReleaseBuffer(pid)
}
+
+func traceCopyStack(gp *g) {
+ if !trace.enabled {
+ return
+ }
+ // we have to use the global proc buffer here
+ // in case we are copying the stack while emitting
+ // a trace event.
+ mp, pid, bufp := traceAcquireGlobal()
+ actualpid := pid
+ if p := mp.p.ptr(); p != nil {
+ actualpid = p.id
+ }
+ traceEventLocked(0, mp, pid, bufp, traceEvGoCopyStack, 1, uint64(gp.goid), uint64(actualpid))
+ traceReleaseBuffer(pid)
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment