1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package stack provides support for parsing standard goroutine stack traces.
13 // Dump is a raw set of goroutines and their stacks.
16 // Goroutine is a single parsed goroutine dump.
17 type Goroutine struct {
18 State string // state that the goroutine is in.
19 ID int // id of the goroutine.
20 Stack Stack // call frames that make up the stack
23 // Stack is a set of frames in a callstack.
26 // Frame is a point in a call stack.
32 // Function is the function called at a frame.
33 type Function struct {
34 Package string // package name of function if known
35 Type string // if set function is a method of this type
36 Name string // function name of the frame
39 // Position is the file position for a frame.
40 type Position struct {
41 Filename string // source filename
42 Line int // line number within file
45 // Summary is a set of stacks processed and collated into Calls.
47 Total int // the total count of goroutines in the summary
48 Calls []Call // the collated stack traces
51 // Call is set of goroutines that all share the same callstack.
52 // They will be grouped by state.
54 Stack Stack // the shared callstack information
55 Groups []Group // the sets of goroutines with the same state
58 // Group is a set of goroutines with the same stack that are in the same state.
60 State string // the shared state of the goroutines
61 Goroutines []Goroutine // the set of goroutines in this group
64 // Delta represents the difference between two stack dumps.
66 Before Dump // The goroutines that were only in the before set.
67 Shared Dump // The goroutines that were in both sets.
68 After Dump // The goroutines that were only in the after set.
71 func (s Stack) equal(other Stack) bool {
72 if len(s) != len(other) {
75 for i, frame := range s {
76 if !frame.equal(other[i]) {
83 func (s Stack) less(other Stack) bool {
84 for i, frame := range s {
88 if frame.less(other[i]) {
91 if !frame.equal(other[i]) {
95 return len(s) < len(other)
98 func (f Frame) equal(other Frame) bool {
99 return f.Position.equal(other.Position)
102 func (f Frame) less(other Frame) bool {
103 return f.Position.less(other.Position)
106 func (p Position) equal(other Position) bool {
107 return p.Filename == other.Filename && p.Line == other.Line
110 func (p Position) less(other Position) bool {
111 if p.Filename < other.Filename {
114 if p.Filename > other.Filename {
117 return p.Line < other.Line
120 func (s Summary) Format(w fmt.State, r rune) {
121 tw := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
122 for i, c := range s.Calls {
124 fmt.Fprintf(tw, "\n\n")
130 if s.Total > 0 && w.Flag('+') {
131 fmt.Fprintf(w, "\n\n%d goroutines, %d unique", s.Total, len(s.Calls))
135 func (c Call) Format(w fmt.State, r rune) {
136 for i, g := range c.Groups {
142 for _, f := range c.Stack {
143 fmt.Fprintf(w, "\n%v", f)
147 func (g Group) Format(w fmt.State, r rune) {
148 fmt.Fprintf(w, "[%v]: ", g.State)
149 for i, gr := range g.Goroutines {
153 fmt.Fprintf(w, "$%d", gr.ID)
157 func (f Frame) Format(w fmt.State, c rune) {
158 fmt.Fprintf(w, "%v:\t%v", f.Position, f.Function)
161 func (f Function) Format(w fmt.State, c rune) {
163 fmt.Fprintf(w, "(%v).", f.Type)
165 fmt.Fprintf(w, "%v", f.Name)
168 func (p Position) Format(w fmt.State, c rune) {
169 fmt.Fprintf(w, "%v:%v", p.Filename, p.Line)