init
This commit is contained in:
38
vendor/github.com/anacrolix/missinggo/perf/event.go
generated
vendored
Normal file
38
vendor/github.com/anacrolix/missinggo/perf/event.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
Mu sync.RWMutex
|
||||
Count int64
|
||||
Total time.Duration
|
||||
Min time.Duration
|
||||
Max time.Duration
|
||||
}
|
||||
|
||||
func (e *Event) Add(t time.Duration) {
|
||||
e.Mu.Lock()
|
||||
defer e.Mu.Unlock()
|
||||
if t > e.Max {
|
||||
e.Max = t
|
||||
}
|
||||
if t < e.Min {
|
||||
e.Min = t
|
||||
}
|
||||
e.Count++
|
||||
e.Total += t
|
||||
}
|
||||
|
||||
func (e *Event) MeanTime() time.Duration {
|
||||
e.Mu.RLock()
|
||||
defer e.Mu.RUnlock()
|
||||
return e.Total / time.Duration(e.Count)
|
||||
}
|
||||
|
||||
func (e *Event) Init() {
|
||||
e.Min = math.MaxInt64
|
||||
}
|
47
vendor/github.com/anacrolix/missinggo/perf/events.go
generated
vendored
Normal file
47
vendor/github.com/anacrolix/missinggo/perf/events.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"sync"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.RWMutex
|
||||
events = map[string]*Event{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
http.HandleFunc("/debug/perf", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=UTF-8")
|
||||
WriteEventsTable(w)
|
||||
})
|
||||
}
|
||||
|
||||
func WriteEventsTable(w io.Writer) {
|
||||
tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprint(tw, "description\ttotal\tcount\tmin\tmean\tmax\n")
|
||||
type t struct {
|
||||
d string
|
||||
e Event
|
||||
}
|
||||
mu.RLock()
|
||||
es := make([]t, 0, len(events))
|
||||
for d, e := range events {
|
||||
e.Mu.RLock()
|
||||
es = append(es, t{d, *e})
|
||||
e.Mu.RUnlock()
|
||||
}
|
||||
mu.RUnlock()
|
||||
sort.Slice(es, func(i, j int) bool {
|
||||
return es[i].e.Total > es[j].e.Total
|
||||
})
|
||||
for _, el := range es {
|
||||
e := el.e
|
||||
fmt.Fprintf(tw, "%s\t%v\t%v\t%v\t%v\t%v\n", el.d, e.Total, e.Count, e.Min, e.MeanTime(), e.Max)
|
||||
}
|
||||
tw.Flush()
|
||||
}
|
48
vendor/github.com/anacrolix/missinggo/perf/mutex.go
generated
vendored
Normal file
48
vendor/github.com/anacrolix/missinggo/perf/mutex.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
type TimedLocker struct {
|
||||
L sync.Locker
|
||||
Desc string
|
||||
}
|
||||
|
||||
func (me *TimedLocker) Lock() {
|
||||
tr := NewTimer()
|
||||
me.L.Lock()
|
||||
tr.Mark(me.Desc)
|
||||
}
|
||||
|
||||
func (me *TimedLocker) Unlock() {
|
||||
me.L.Unlock()
|
||||
}
|
||||
|
||||
type TimedRWLocker struct {
|
||||
RWL missinggo.RWLocker
|
||||
WriteDesc string
|
||||
ReadDesc string
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) Lock() {
|
||||
tr := NewTimer()
|
||||
me.RWL.Lock()
|
||||
tr.Mark(me.WriteDesc)
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) Unlock() {
|
||||
me.RWL.Unlock()
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) RLock() {
|
||||
tr := NewTimer()
|
||||
me.RWL.RLock()
|
||||
tr.Mark(me.ReadDesc)
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) RUnlock() {
|
||||
me.RWL.RUnlock()
|
||||
}
|
39
vendor/github.com/anacrolix/missinggo/perf/scope.go
generated
vendored
Normal file
39
vendor/github.com/anacrolix/missinggo/perf/scope.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func ScopeTimer(opts ...timerOpt) func() {
|
||||
t := NewTimer(CallerName(1))
|
||||
return func() { t.Mark("returned") }
|
||||
}
|
||||
|
||||
func ScopeTimerOk(ok *bool) func() {
|
||||
t := NewTimer(CallerName(1))
|
||||
return func() { t.MarkOk(*ok) }
|
||||
}
|
||||
|
||||
func ScopeTimerErr(err *error) func() {
|
||||
t := NewTimer(CallerName(1))
|
||||
return func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
t.Mark("panic")
|
||||
panic(r)
|
||||
}
|
||||
t.MarkErr(*err)
|
||||
}
|
||||
}
|
||||
|
||||
func CallerName(skip int) timerOpt {
|
||||
return Name(getCallerName(skip))
|
||||
}
|
||||
|
||||
func getCallerName(skip int) string {
|
||||
var pc [1]uintptr
|
||||
runtime.Callers(3+skip, pc[:])
|
||||
fs := runtime.CallersFrames(pc[:])
|
||||
f, _ := fs.Next()
|
||||
return f.Func.Name()
|
||||
}
|
104
vendor/github.com/anacrolix/missinggo/perf/timer.go
generated
vendored
Normal file
104
vendor/github.com/anacrolix/missinggo/perf/timer.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Timer struct {
|
||||
started time.Time
|
||||
log bool
|
||||
name string
|
||||
marked bool
|
||||
}
|
||||
|
||||
func NewTimer(opts ...timerOpt) (t *Timer) {
|
||||
t = &Timer{
|
||||
started: time.Now(),
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(t)
|
||||
}
|
||||
if t.log && t.name != "" {
|
||||
log.Printf("starting timer %q", t.name)
|
||||
}
|
||||
runtime.SetFinalizer(t, func(t *Timer) {
|
||||
if t.marked {
|
||||
return
|
||||
}
|
||||
log.Printf("timer %#v was never marked", t)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
type timerOpt func(*Timer)
|
||||
|
||||
func Log(t *Timer) {
|
||||
t.log = true
|
||||
}
|
||||
|
||||
func Name(name string) func(*Timer) {
|
||||
return func(t *Timer) {
|
||||
t.name = name
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timer) Mark(events ...string) time.Duration {
|
||||
d := time.Since(t.started)
|
||||
if len(events) == 0 {
|
||||
if t.name == "" {
|
||||
panic("no name or events specified")
|
||||
}
|
||||
t.addDuration(t.name, d)
|
||||
} else {
|
||||
for _, e := range events {
|
||||
if t.name != "" {
|
||||
e = t.name + "/" + e
|
||||
}
|
||||
t.addDuration(e, d)
|
||||
}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (t *Timer) MarkOk(ok bool) {
|
||||
if ok {
|
||||
t.Mark("ok")
|
||||
} else {
|
||||
t.Mark("not ok")
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timer) MarkErr(err error) {
|
||||
if err == nil {
|
||||
t.Mark("success")
|
||||
} else {
|
||||
t.Mark("error")
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timer) addDuration(desc string, d time.Duration) {
|
||||
t.marked = true
|
||||
mu.RLock()
|
||||
e := events[desc]
|
||||
mu.RUnlock()
|
||||
if e == nil {
|
||||
mu.Lock()
|
||||
e = events[desc]
|
||||
if e == nil {
|
||||
e = new(Event)
|
||||
e.Init()
|
||||
events[desc] = e
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
e.Add(d)
|
||||
if t.log {
|
||||
if t.name != "" {
|
||||
log.Printf("timer %q got event %q after %s", t.name, desc, d)
|
||||
} else {
|
||||
log.Printf("marking event %q after %s", desc, d)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user