source: code/trunk/vendor/modernc.org/libc/probes.go@ 823

Last change on this file since 823 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 2.7 KB
Line 
1// Copyright 2022 The Libc 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 libc // import "modernc.org/libc"
6
7import (
8 "bytes"
9 "fmt"
10 "math"
11 "runtime/debug"
12 "sort"
13 "strings"
14 "sync"
15 "sync/atomic"
16
17 "github.com/dustin/go-humanize"
18)
19
20type PerfCounter struct {
21 a []int32
22 labels []string
23
24 enabled bool
25}
26
27func NewPerfCounter(labels []string) *PerfCounter {
28 return &PerfCounter{
29 a: make([]int32, len(labels)),
30 labels: labels,
31 enabled: true,
32 }
33}
34
35func (c *PerfCounter) Disable() { c.enabled = false }
36func (c *PerfCounter) Enable() { c.enabled = true }
37
38func (c *PerfCounter) Clear() {
39 for i := range c.a {
40 c.a[i] = 0
41 }
42}
43
44func (c *PerfCounter) Inc(n int) {
45 if c.enabled {
46 atomic.AddInt32(&c.a[n], 1)
47 }
48}
49
50func (c *PerfCounter) IncN(n, m int) {
51 if c.enabled {
52 atomic.AddInt32(&c.a[n], int32(m))
53 }
54}
55
56func (c *PerfCounter) String() string {
57 sv := c.enabled
58
59 defer func() { c.enabled = sv }()
60
61 c.enabled = false
62
63 var a []string
64 for i, v := range c.a {
65 if v != 0 {
66 a = append(a, fmt.Sprintf("%q: %s", c.labels[i], h(v)))
67 }
68 }
69 return fmt.Sprint(a)
70}
71
72func h(v interface{}) string {
73 switch x := v.(type) {
74 case int:
75 return humanize.Comma(int64(x))
76 case int32:
77 return humanize.Comma(int64(x))
78 case int64:
79 return humanize.Comma(x)
80 case uint32:
81 return humanize.Comma(int64(x))
82 case uint64:
83 if x <= math.MaxInt64 {
84 return humanize.Comma(int64(x))
85 }
86
87 return "-" + humanize.Comma(-int64(x))
88 }
89 return fmt.Sprint(v)
90}
91
92type StackCapture struct {
93 sync.Mutex
94 m map[string]int
95
96 depth int
97
98 enabled bool
99}
100
101func NewStackCapture(depth int) *StackCapture {
102 return &StackCapture{
103 m: map[string]int{},
104 depth: depth,
105 enabled: true,
106 }
107}
108
109func (c *StackCapture) Disable() { c.enabled = false }
110func (c *StackCapture) Enable() { c.enabled = true }
111
112func (c *StackCapture) Clear() {
113 c.Lock()
114
115 defer c.Unlock()
116 c.m = map[string]int{}
117}
118
119var (
120 stackCapturePrefix = []byte("\n\t")
121)
122
123func (c *StackCapture) Record() {
124 if !c.enabled {
125 return
126 }
127
128 b := debug.Stack()
129 var s strings.Builder
130out:
131 for i := 0; len(b) > 0 && i < c.depth+2; i++ {
132 l := bytes.Index(b, stackCapturePrefix)
133 if l < 0 {
134 break out
135 }
136
137 b = b[l+len(stackCapturePrefix):]
138 h := bytes.IndexByte(b, '\n')
139 if h < 0 {
140 h = len(b)
141 }
142 if i > 1 {
143 fmt.Fprintf(&s, "\n\t%s", b[:h])
144 }
145 b = b[h:]
146 }
147 c.Lock()
148
149 defer c.Unlock()
150
151 c.m[s.String()]++
152}
153
154func (c *StackCapture) String() string {
155 c.Lock()
156
157 defer c.Unlock()
158
159 var b strings.Builder
160 var a []string
161 for k := range c.m {
162 a = append(a, k)
163 }
164 sort.Slice(a, func(i, j int) bool { return c.m[a[i]] < c.m[a[j]] })
165 for _, k := range a {
166 fmt.Fprintf(&b, "%d%s\n", c.m[k], k)
167 }
168 return b.String()
169}
Note: See TracBrowser for help on using the repository browser.