Skip to content

Instantly share code, notes, and snippets.

@lysu
Created March 17, 2016 17:47
Show Gist options
  • Save lysu/242e958a21d6e2331c51 to your computer and use it in GitHub Desktop.
Save lysu/242e958a21d6e2331c51 to your computer and use it in GitHub Desktop.
package metrics
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
type counter struct {
c *uint64
}
func newCounter() counter {
cc := uint64(0)
return counter{
c: &cc,
}
}
func (c *counter) increase() {
atomic.AddUint64(c.c, 1)
}
func (c *counter) reset() {
atomic.StoreUint64(c.c, 0)
}
type Metrics struct {
startTime time.Time
epoch int64
windows []counter
windowSize int
duration time.Duration
lock sync.Locker
}
func NewMetrics(size int, duration time.Duration) *Metrics {
start := time.Now()
m := &Metrics{
startTime: start,
epoch: 0,
windows: make([]counter, 0, size),
windowSize: size,
duration: duration,
lock: &sync.RWMutex{},
}
for i := 0; i < size; i++ {
m.windows = append(m.windows, newCounter())
}
return m
}
func (m *Metrics) RecordOne() {
current := time.Now()
perWindowNano := m.duration.Nanoseconds() / int64(m.windowSize)
currentEpoch := current.Sub(m.startTime).Nanoseconds() / perWindowNano
m.lock.Lock()
if currentEpoch > m.epoch {
resetCount := 0
for e := m.epoch + 1; e <= currentEpoch; e++ {
resetIdx := int(e % int64(m.windowSize))
m.windows[resetIdx].reset()
resetCount++
if resetCount >= m.windowSize {
break
}
}
m.epoch = currentEpoch
}
m.lock.Unlock()
idx := int(currentEpoch % int64(m.windowSize))
m.windows[idx].increase()
}
func (m *Metrics) QPS() float64 {
var total uint64
var ss []uint64
for _, counter := range m.windows {
c := atomic.LoadUint64(counter.c)
total += c
ss = append(ss, c)
}
fmt.Println(ss)
return float64(total) / m.duration.Seconds()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment