gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

probes.go (2810B)


      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 
      5 package libc // import "modernc.org/libc"
      6 
      7 import (
      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 
     20 type PerfCounter struct {
     21 	a      []int32
     22 	labels []string
     23 
     24 	enabled bool
     25 }
     26 
     27 func NewPerfCounter(labels []string) *PerfCounter {
     28 	return &PerfCounter{
     29 		a:       make([]int32, len(labels)),
     30 		labels:  labels,
     31 		enabled: true,
     32 	}
     33 }
     34 
     35 func (c *PerfCounter) Disable() { c.enabled = false }
     36 func (c *PerfCounter) Enable()  { c.enabled = true }
     37 
     38 func (c *PerfCounter) Clear() {
     39 	for i := range c.a {
     40 		c.a[i] = 0
     41 	}
     42 }
     43 
     44 func (c *PerfCounter) Inc(n int) {
     45 	if c.enabled {
     46 		atomic.AddInt32(&c.a[n], 1)
     47 	}
     48 }
     49 
     50 func (c *PerfCounter) IncN(n, m int) {
     51 	if c.enabled {
     52 		atomic.AddInt32(&c.a[n], int32(m))
     53 	}
     54 }
     55 
     56 func (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 
     72 func 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 
     92 type StackCapture struct {
     93 	sync.Mutex
     94 	m map[string]int
     95 
     96 	depth int
     97 
     98 	enabled bool
     99 }
    100 
    101 func NewStackCapture(depth int) *StackCapture {
    102 	return &StackCapture{
    103 		m:       map[string]int{},
    104 		depth:   depth,
    105 		enabled: true,
    106 	}
    107 }
    108 
    109 func (c *StackCapture) Disable() { c.enabled = false }
    110 func (c *StackCapture) Enable()  { c.enabled = true }
    111 
    112 func (c *StackCapture) Clear() {
    113 	c.Lock()
    114 
    115 	defer c.Unlock()
    116 	c.m = map[string]int{}
    117 }
    118 
    119 var (
    120 	stackCapturePrefix = []byte("\n\t")
    121 )
    122 
    123 func (c *StackCapture) Record() {
    124 	if !c.enabled {
    125 		return
    126 	}
    127 
    128 	b := debug.Stack()
    129 	var s strings.Builder
    130 out:
    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 
    154 func (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 }