104 lignes
1,6 Kio
Go
104 lignes
1,6 Kio
Go
|
package perf
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"expvar"
|
||
|
"fmt"
|
||
|
"math"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"github.com/anacrolix/missinggo"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
em = missinggo.NewExpvarIndentMap("perfBuckets")
|
||
|
mu sync.RWMutex
|
||
|
)
|
||
|
|
||
|
type Timer struct {
|
||
|
started time.Time
|
||
|
}
|
||
|
|
||
|
func NewTimer() Timer {
|
||
|
return Timer{time.Now()}
|
||
|
}
|
||
|
|
||
|
// The exponent is the upper bound of the duration in seconds.
|
||
|
func bucketExponent(d time.Duration) int {
|
||
|
e := -9
|
||
|
for d != 0 {
|
||
|
d /= 10
|
||
|
e++
|
||
|
}
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
type buckets struct {
|
||
|
mu sync.Mutex
|
||
|
buckets []int64
|
||
|
}
|
||
|
|
||
|
func (me *buckets) Add(t time.Duration) {
|
||
|
e := bucketExponent(t)
|
||
|
me.mu.Lock()
|
||
|
for e+9 >= len(me.buckets) {
|
||
|
me.buckets = append(me.buckets, 0)
|
||
|
}
|
||
|
me.buckets[e+9]++
|
||
|
me.mu.Unlock()
|
||
|
}
|
||
|
|
||
|
func humanExponent(e int) string {
|
||
|
if e == -9 {
|
||
|
return "<1ns"
|
||
|
}
|
||
|
return ">" + time.Duration(math.Pow10(e-1)).String()
|
||
|
}
|
||
|
|
||
|
func (me *buckets) String() string {
|
||
|
var b bytes.Buffer
|
||
|
fmt.Fprintf(&b, "{")
|
||
|
first := true
|
||
|
me.mu.Lock()
|
||
|
for i, count := range me.buckets {
|
||
|
if first {
|
||
|
if count == 0 {
|
||
|
continue
|
||
|
}
|
||
|
first = false
|
||
|
} else {
|
||
|
fmt.Fprintf(&b, ", ")
|
||
|
}
|
||
|
fmt.Fprintf(&b, "%q: %d", humanExponent(i), count)
|
||
|
}
|
||
|
me.mu.Unlock()
|
||
|
fmt.Fprintf(&b, "}")
|
||
|
return b.String()
|
||
|
}
|
||
|
|
||
|
var _ expvar.Var = &buckets{}
|
||
|
|
||
|
func (t *Timer) Stop(desc string) time.Duration {
|
||
|
d := time.Since(t.started)
|
||
|
t.addDuration(desc, d)
|
||
|
return d
|
||
|
}
|
||
|
|
||
|
func (t *Timer) addDuration(desc string, d time.Duration) {
|
||
|
mu.RLock()
|
||
|
_m := em.Get(desc)
|
||
|
mu.RUnlock()
|
||
|
if _m == nil {
|
||
|
mu.Lock()
|
||
|
_m = em.Get(desc)
|
||
|
if _m == nil {
|
||
|
_m = new(buckets)
|
||
|
em.Set(desc, _m)
|
||
|
}
|
||
|
mu.Unlock()
|
||
|
}
|
||
|
m := _m.(*buckets)
|
||
|
m.Add(d)
|
||
|
}
|