golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/internal/stack/stack.go (about) 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. 4 5 // Package stack provides support for parsing standard goroutine stack traces. 6 package stack 7 8 import ( 9 "fmt" 10 "text/tabwriter" 11 ) 12 13 // Dump is a raw set of goroutines and their stacks. 14 type Dump []Goroutine 15 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 21 } 22 23 // Stack is a set of frames in a callstack. 24 type Stack []Frame 25 26 // Frame is a point in a call stack. 27 type Frame struct { 28 Function Function 29 Position Position 30 } 31 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 37 } 38 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 43 } 44 45 // Summary is a set of stacks processed and collated into Calls. 46 type Summary struct { 47 Total int // the total count of goroutines in the summary 48 Calls []Call // the collated stack traces 49 } 50 51 // Call is set of goroutines that all share the same callstack. 52 // They will be grouped by state. 53 type Call struct { 54 Stack Stack // the shared callstack information 55 Groups []Group // the sets of goroutines with the same state 56 } 57 58 // Group is a set of goroutines with the same stack that are in the same state. 59 type Group struct { 60 State string // the shared state of the goroutines 61 Goroutines []Goroutine // the set of goroutines in this group 62 } 63 64 // Delta represents the difference between two stack dumps. 65 type Delta struct { 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. 69 } 70 71 func (s Stack) equal(other Stack) bool { 72 if len(s) != len(other) { 73 return false 74 } 75 for i, frame := range s { 76 if !frame.equal(other[i]) { 77 return false 78 } 79 } 80 return true 81 } 82 83 func (s Stack) less(other Stack) bool { 84 for i, frame := range s { 85 if i >= len(other) { 86 return false 87 } 88 if frame.less(other[i]) { 89 return true 90 } 91 if !frame.equal(other[i]) { 92 return false 93 } 94 } 95 return len(s) < len(other) 96 } 97 98 func (f Frame) equal(other Frame) bool { 99 return f.Position.equal(other.Position) 100 } 101 102 func (f Frame) less(other Frame) bool { 103 return f.Position.less(other.Position) 104 } 105 106 func (p Position) equal(other Position) bool { 107 return p.Filename == other.Filename && p.Line == other.Line 108 } 109 110 func (p Position) less(other Position) bool { 111 if p.Filename < other.Filename { 112 return true 113 } 114 if p.Filename > other.Filename { 115 return false 116 } 117 return p.Line < other.Line 118 } 119 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 { 123 if i > 0 { 124 fmt.Fprintf(tw, "\n\n") 125 tw.Flush() 126 } 127 fmt.Fprint(tw, c) 128 } 129 tw.Flush() 130 if s.Total > 0 && w.Flag('+') { 131 fmt.Fprintf(w, "\n\n%d goroutines, %d unique", s.Total, len(s.Calls)) 132 } 133 } 134 135 func (c Call) Format(w fmt.State, r rune) { 136 for i, g := range c.Groups { 137 if i > 0 { 138 fmt.Fprint(w, " ") 139 } 140 fmt.Fprint(w, g) 141 } 142 for _, f := range c.Stack { 143 fmt.Fprintf(w, "\n%v", f) 144 } 145 } 146 147 func (g Group) Format(w fmt.State, r rune) { 148 fmt.Fprintf(w, "[%v]: ", g.State) 149 for i, gr := range g.Goroutines { 150 if i > 0 { 151 fmt.Fprint(w, ", ") 152 } 153 fmt.Fprintf(w, "$%d", gr.ID) 154 } 155 } 156 157 func (f Frame) Format(w fmt.State, c rune) { 158 fmt.Fprintf(w, "%v:\t%v", f.Position, f.Function) 159 } 160 161 func (f Function) Format(w fmt.State, c rune) { 162 if f.Type != "" { 163 fmt.Fprintf(w, "(%v).", f.Type) 164 } 165 fmt.Fprintf(w, "%v", f.Name) 166 } 167 168 func (p Position) Format(w fmt.State, c rune) { 169 fmt.Fprintf(w, "%v:%v", p.Filename, p.Line) 170 }