Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / stack / process.go
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
6
7 import (
8         "bytes"
9         "fmt"
10         "io"
11         "runtime"
12         "sort"
13 )
14
15 // Capture get the current stack traces from the runtime.
16 func Capture() Dump {
17         buf := make([]byte, 2<<20)
18         buf = buf[:runtime.Stack(buf, true)]
19         scanner := NewScanner(bytes.NewReader(buf))
20         dump, _ := Parse(scanner)
21         return dump
22 }
23
24 // Summarize a dump for easier consumption.
25 // This collates goroutines with equivalent stacks.
26 func Summarize(dump Dump) Summary {
27         s := Summary{
28                 Total: len(dump),
29         }
30         for _, gr := range dump {
31                 s.addGoroutine(gr)
32         }
33         return s
34 }
35
36 // Process and input stream to an output stream, summarizing any stacks that
37 // are detected in place.
38 func Process(out io.Writer, in io.Reader) error {
39         scanner := NewScanner(in)
40         for {
41                 dump, err := Parse(scanner)
42                 summary := Summarize(dump)
43                 switch {
44                 case len(dump) > 0:
45                         fmt.Fprintf(out, "%+v\n\n", summary)
46                 case err != nil:
47                         return err
48                 case scanner.Done():
49                         return scanner.Err()
50                 default:
51                         // must have been a line that is not part of a dump
52                         fmt.Fprintln(out, scanner.Next())
53                 }
54         }
55 }
56
57 // Diff calculates the delta between two dumps.
58 func Diff(before, after Dump) Delta {
59         result := Delta{}
60         processed := make(map[int]bool)
61         for _, gr := range before {
62                 processed[gr.ID] = false
63         }
64         for _, gr := range after {
65                 if _, found := processed[gr.ID]; found {
66                         result.Shared = append(result.Shared, gr)
67                 } else {
68                         result.After = append(result.After, gr)
69                 }
70                 processed[gr.ID] = true
71         }
72         for _, gr := range before {
73                 if done := processed[gr.ID]; !done {
74                         result.Before = append(result.Before, gr)
75                 }
76         }
77         return result
78 }
79
80 // TODO: do we want to allow contraction of stacks before comparison?
81 func (s *Summary) addGoroutine(gr Goroutine) {
82         index := sort.Search(len(s.Calls), func(i int) bool {
83                 return !s.Calls[i].Stack.less(gr.Stack)
84         })
85         if index >= len(s.Calls) || !s.Calls[index].Stack.equal(gr.Stack) {
86                 // insert new stack, first increase the length
87                 s.Calls = append(s.Calls, Call{})
88                 // move the top part upward to make space
89                 copy(s.Calls[index+1:], s.Calls[index:])
90                 // insert the new call
91                 s.Calls[index] = Call{
92                         Stack: gr.Stack,
93                 }
94         }
95         // merge the goroutine into the matched call
96         s.Calls[index].merge(gr)
97 }
98
99 //TODO: do we want other grouping strategies?
100 func (c *Call) merge(gr Goroutine) {
101         for i := range c.Groups {
102                 canditate := &c.Groups[i]
103                 if canditate.State == gr.State {
104                         canditate.Goroutines = append(canditate.Goroutines, gr)
105                         return
106                 }
107         }
108         c.Groups = append(c.Groups, Group{
109                 State:      gr.State,
110                 Goroutines: []Goroutine{gr},
111         })
112 }