golang.org/x/tools@v0.21.0/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  }