diff options
| author | Eric Daniels <eric@erdaniels.com> | 2018-04-03 21:35:46 -0400 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2018-04-13 20:42:38 +0000 |
| commit | d9b006a7057d4666cb4fa9c421f2360ef3994b0f (patch) | |
| tree | c164e0e3b0f5c10fa391ba1e25456e52c1dfa365 /src/runtime/testdata | |
| parent | 115b1cd192609624a898954b9759fcd90247badc (diff) | |
| download | go-d9b006a7057d4666cb4fa9c421f2360ef3994b0f.tar.xz | |
runtime/traceback: support tracking goroutine ancestor tracebacks with GODEBUG="tracebackancestors=N"
Currently, collecting a stack trace via runtime.Stack captures the stack for the
immediately running goroutines. This change extends those tracebacks to include
the tracebacks of their ancestors. This is done with a low memory cost and only
utilized when debug option tracebackancestors is set to a value greater than 0.
Resolves #22289
Change-Id: I7edacc62b2ee3bd278600c4a21052c351f313f3a
Reviewed-on: https://go-review.googlesource.com/70993
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/testdata')
| -rw-r--r-- | src/runtime/testdata/testprog/traceback_ancestors.go | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprog/traceback_ancestors.go b/src/runtime/testdata/testprog/traceback_ancestors.go new file mode 100644 index 0000000000..fe57c1c157 --- /dev/null +++ b/src/runtime/testdata/testprog/traceback_ancestors.go @@ -0,0 +1,53 @@ +// Copyright 2018 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. + +package main + +import ( + "fmt" + "runtime" +) + +func init() { + register("TracebackAncestors", TracebackAncestors) +} + +const numGoroutines = 3 +const numFrames = 2 + +func TracebackAncestors() { + w := make(chan struct{}) + recurseThenCallGo(w, numGoroutines, numFrames) + <-w + printStack() + close(w) +} + +func printStack() { + buf := make([]byte, 1024) + for { + n := runtime.Stack(buf, true) + if n < len(buf) { + fmt.Print(string(buf[:n])) + return + } + buf = make([]byte, 2*len(buf)) + } +} + +func recurseThenCallGo(w chan struct{}, frames int, goroutines int) { + if frames == 0 { + // Signal to TracebackAncestors that we are done recursing and starting goroutines. + w <- struct{}{} + <-w + return + } + if goroutines == 0 { + // Start the next goroutine now that there are no more recursions left + // for this current goroutine. + go recurseThenCallGo(w, frames-1, numFrames) + return + } + recurseThenCallGo(w, frames, goroutines-1) +} |
