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.
15 // Capture get the current stack traces from the runtime.
17 buf := make([]byte, 2<<20)
18 buf = buf[:runtime.Stack(buf, true)]
19 scanner := NewScanner(bytes.NewReader(buf))
20 dump, _ := Parse(scanner)
24 // Summarize a dump for easier consumption.
25 // This collates goroutines with equivalent stacks.
26 func Summarize(dump Dump) Summary {
30 for _, gr := range dump {
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)
41 dump, err := Parse(scanner)
42 summary := Summarize(dump)
45 fmt.Fprintf(out, "%+v\n\n", summary)
51 // must have been a line that is not part of a dump
52 fmt.Fprintln(out, scanner.Next())
57 // Diff calculates the delta between two dumps.
58 func Diff(before, after Dump) Delta {
60 processed := make(map[int]bool)
61 for _, gr := range before {
62 processed[gr.ID] = false
64 for _, gr := range after {
65 if _, found := processed[gr.ID]; found {
66 result.Shared = append(result.Shared, gr)
68 result.After = append(result.After, gr)
70 processed[gr.ID] = true
72 for _, gr := range before {
73 if done := processed[gr.ID]; !done {
74 result.Before = append(result.Before, gr)
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)
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{
95 // merge the goroutine into the matched call
96 s.Calls[index].merge(gr)
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)
108 c.Groups = append(c.Groups, Group{
110 Goroutines: []Goroutine{gr},