...
1
2
3
4
5 package stack
6
7 import (
8 "bytes"
9 "fmt"
10 "io"
11 "runtime"
12 "sort"
13 )
14
15
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
25
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
37
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
52 fmt.Fprintln(out, scanner.Next())
53 }
54 }
55 }
56
57
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
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
87 s.Calls = append(s.Calls, Call{})
88
89 copy(s.Calls[index+1:], s.Calls[index:])
90
91 s.Calls[index] = Call{
92 Stack: gr.Stack,
93 }
94 }
95
96 s.Calls[index].merge(gr)
97 }
98
99
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 }
113
View as plain text