123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- // Copyright 2022 The Libc Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package libc // import "modernc.org/libc"
- import (
- "bytes"
- "fmt"
- "math"
- "runtime/debug"
- "sort"
- "strings"
- "sync"
- "sync/atomic"
- "github.com/dustin/go-humanize"
- )
- type PerfCounter struct {
- a []int32
- labels []string
- enabled bool
- }
- func NewPerfCounter(labels []string) *PerfCounter {
- return &PerfCounter{
- a: make([]int32, len(labels)),
- labels: labels,
- enabled: true,
- }
- }
- func (c *PerfCounter) Disable() { c.enabled = false }
- func (c *PerfCounter) Enable() { c.enabled = true }
- func (c *PerfCounter) Clear() {
- for i := range c.a {
- c.a[i] = 0
- }
- }
- func (c *PerfCounter) Inc(n int) {
- if c.enabled {
- atomic.AddInt32(&c.a[n], 1)
- }
- }
- func (c *PerfCounter) IncN(n, m int) {
- if c.enabled {
- atomic.AddInt32(&c.a[n], int32(m))
- }
- }
- func (c *PerfCounter) String() string {
- sv := c.enabled
- defer func() { c.enabled = sv }()
- c.enabled = false
- var a []string
- for i, v := range c.a {
- if v != 0 {
- a = append(a, fmt.Sprintf("%q: %s", c.labels[i], h(v)))
- }
- }
- return fmt.Sprint(a)
- }
- func h(v interface{}) string {
- switch x := v.(type) {
- case int:
- return humanize.Comma(int64(x))
- case int32:
- return humanize.Comma(int64(x))
- case int64:
- return humanize.Comma(x)
- case uint32:
- return humanize.Comma(int64(x))
- case uint64:
- if x <= math.MaxInt64 {
- return humanize.Comma(int64(x))
- }
- return "-" + humanize.Comma(-int64(x))
- }
- return fmt.Sprint(v)
- }
- type StackCapture struct {
- sync.Mutex
- m map[string]int
- depth int
- enabled bool
- }
- func NewStackCapture(depth int) *StackCapture {
- return &StackCapture{
- m: map[string]int{},
- depth: depth,
- enabled: true,
- }
- }
- func (c *StackCapture) Disable() { c.enabled = false }
- func (c *StackCapture) Enable() { c.enabled = true }
- func (c *StackCapture) Clear() {
- c.Lock()
- defer c.Unlock()
- c.m = map[string]int{}
- }
- var (
- stackCapturePrefix = []byte("\n\t")
- )
- func (c *StackCapture) Record() {
- if !c.enabled {
- return
- }
- b := debug.Stack()
- var s strings.Builder
- out:
- for i := 0; len(b) > 0 && i < c.depth+2; i++ {
- l := bytes.Index(b, stackCapturePrefix)
- if l < 0 {
- break out
- }
- b = b[l+len(stackCapturePrefix):]
- h := bytes.IndexByte(b, '\n')
- if h < 0 {
- h = len(b)
- }
- if i > 1 {
- fmt.Fprintf(&s, "\n\t%s", b[:h])
- }
- b = b[h:]
- }
- c.Lock()
- defer c.Unlock()
- c.m[s.String()]++
- }
- func (c *StackCapture) String() string {
- c.Lock()
- defer c.Unlock()
- var b strings.Builder
- var a []string
- for k := range c.m {
- a = append(a, k)
- }
- sort.Slice(a, func(i, j int) bool { return c.m[a[i]] < c.m[a[j]] })
- for _, k := range a {
- fmt.Fprintf(&b, "%d%s\n", c.m[k], k)
- }
- return b.String()
- }
|