mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 21:32:24 -06:00 
			
		
		
		
	
		
			
	
	
		
			170 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			170 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// 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()
							 | 
						||
| 
								 | 
							
								}
							 |