21
vendor/github.com/anacrolix/missinggo/perf/LICENSE
generated
vendored
Normal file
21
vendor/github.com/anacrolix/missinggo/perf/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Matt Joiner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
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
|
||||
}
|
||||
60
vendor/github.com/anacrolix/missinggo/perf/events.go
generated
vendored
Normal file
60
vendor/github.com/anacrolix/missinggo/perf/events.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
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")
|
||||
switch r.FormValue("sort") {
|
||||
case "desc":
|
||||
writeEventsTableCustomSort(w, func(l, r NamedEvent) bool {
|
||||
return l.Name < r.Name
|
||||
})
|
||||
default:
|
||||
WriteEventsTable(w)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type NamedEvent struct {
|
||||
Name string
|
||||
Event
|
||||
}
|
||||
|
||||
func WriteEventsTable(w io.Writer) {
|
||||
writeEventsTableCustomSort(w, func(l, r NamedEvent) bool {
|
||||
return l.Total > r.Total
|
||||
})
|
||||
}
|
||||
|
||||
func writeEventsTableCustomSort(w io.Writer, less func(l, r NamedEvent) bool) {
|
||||
tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprint(tw, "description\ttotal\tcount\tmin\tmean\tmax\n")
|
||||
mu.RLock()
|
||||
es := make([]NamedEvent, 0, len(events))
|
||||
for d, e := range events {
|
||||
e.Mu.RLock()
|
||||
es = append(es, NamedEvent{d, *e})
|
||||
e.Mu.RUnlock()
|
||||
}
|
||||
mu.RUnlock()
|
||||
sort.Slice(es, func(i, j int) bool {
|
||||
return less(es[i], es[j])
|
||||
})
|
||||
for _, ne := range es {
|
||||
fmt.Fprintf(tw, "%s\t%v\t%v\t%v\t%v\t%v\n", ne.Name, ne.Total, ne.Count, ne.Min, ne.MeanTime(), ne.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