GoPLS Viewer

Home|gopls/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
5package stack
6
7import (
8    "bytes"
9    "fmt"
10    "io"
11    "runtime"
12    "sort"
13)
14
15// Capture get the current stack traces from the runtime.
16func Capture() Dump {
17    buf := make([]byte2<<20)
18    buf = buf[:runtime.Stack(buftrue)]
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.
26func Summarize(dump DumpSummary {
27    s := Summary{
28        Totallen(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.
38func Process(out io.Writerin io.Readererror {
39    scanner := NewScanner(in)
40    for {
41        dumperr := 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(outscanner.Next())
53        }
54    }
55}
56
57// Diff calculates the delta between two dumps.
58func Diff(beforeafter DumpDelta {
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.Sharedgr)
67        } else {
68            result.After = append(result.Aftergr)
69        }
70        processed[gr.ID] = true
71    }
72    for _gr := range before {
73        if done := processed[gr.ID]; !done {
74            result.Before = append(result.Beforegr)
75        }
76    }
77    return result
78}
79
80// TODO: do we want to allow contraction of stacks before comparison?
81func (s *SummaryaddGoroutine(gr Goroutine) {
82    index := sort.Search(len(s.Calls), func(i intbool {
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.CallsCall{})
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            Stackgr.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?
100func (c *Callmerge(gr Goroutine) {
101    for i := range c.Groups {
102        canditate := &c.Groups[i]
103        if canditate.State == gr.State {
104            canditate.Goroutines = append(canditate.Goroutinesgr)
105            return
106        }
107    }
108    c.Groups = append(c.GroupsGroup{
109        State:      gr.State,
110        Goroutines: []Goroutine{gr},
111    })
112}
113
MembersX
Call.merge.c
Call.merge.gr
sort
Capture.buf
Summarize
Process.BlockStmt.summary
Diff.result
Diff.processed
Process.BlockStmt.dump
Diff.before
Diff.RangeStmt_1407.gr
Diff.RangeStmt_1610.gr
Summarize.s
Summary.addGoroutine
bytes
Capture._
Summarize.dump
Process.BlockStmt.err
Diff
Diff.after
Capture
Summarize.RangeStmt_634.gr
Process.in
Summary.addGoroutine.gr
Summary.addGoroutine.index
Call.merge
fmt
Capture.scanner
Process.scanner
Diff.RangeStmt_1348.gr
Summary.addGoroutine.s
Call.merge.RangeStmt_2443.i
runtime
Capture.dump
Process
Process.out
Members
X