1
Fork 0
galene/estimator/estimator.go

104 lines
2.3 KiB
Go
Raw Normal View History

2021-01-19 20:40:19 +01:00
// Package estimator implements a packet and byte rate estimator.
2020-04-30 20:15:52 +02:00
package estimator
import (
2022-04-20 21:27:34 +02:00
"sync"
2020-04-30 20:15:52 +02:00
"time"
2020-12-19 17:37:48 +01:00
"github.com/jech/galene/rtptime"
2020-04-30 20:15:52 +02:00
)
type Estimator struct {
2022-04-20 21:27:34 +02:00
interval uint64
mu sync.Mutex
time uint64
bytes uint32
packets uint32
2022-04-20 21:27:34 +02:00
totalBytes uint64
totalPackets uint64
2020-05-31 23:54:55 +02:00
rate uint32
packetRate uint32
2020-04-30 20:15:52 +02:00
}
2021-01-19 20:40:19 +01:00
// New creates a new estimator that estimates rate over the last interval.
2020-04-30 20:15:52 +02:00
func New(interval time.Duration) *Estimator {
2022-04-20 21:27:34 +02:00
return new(rtptime.Now(rtptime.JiffiesPerSec), interval)
}
func new(now uint64, interval time.Duration) *Estimator {
2020-04-30 20:15:52 +02:00
return &Estimator{
interval: uint64(
rtptime.FromDuration(interval, rtptime.JiffiesPerSec),
),
2022-04-20 21:27:34 +02:00
time: now,
2020-04-30 20:15:52 +02:00
}
}
2022-04-20 21:27:34 +02:00
// called locked
func (e *Estimator) swap(now uint64) {
2022-04-20 21:27:34 +02:00
jiffies := now - e.time
bytes := e.bytes
e.bytes = 0
packets := e.packets
e.packets = 0
e.totalBytes += uint64(bytes)
e.totalPackets += uint64(packets)
var rate, packetRate uint32
if jiffies >= rtptime.JiffiesPerSec/1000 {
rate = uint32((uint64(bytes)*rtptime.JiffiesPerSec + jiffies/2) / jiffies)
packetRate = uint32((uint64(packets)*rtptime.JiffiesPerSec + jiffies/2) / jiffies)
2020-04-30 20:15:52 +02:00
}
2022-04-20 21:27:34 +02:00
e.rate = rate
e.packetRate = packetRate
e.time = now
2020-04-30 20:15:52 +02:00
}
2021-01-19 20:40:19 +01:00
// Accumulate records one packet of size bytes
func (e *Estimator) Accumulate(bytes uint32) {
2022-04-20 21:27:34 +02:00
e.mu.Lock()
if e.bytes < ^uint32(0)-bytes {
e.bytes += bytes
}
if e.packets < ^uint32(0)-1 {
e.packets += 1
}
e.mu.Unlock()
2020-04-30 20:15:52 +02:00
}
2022-04-20 21:27:34 +02:00
// called locked
func (e *Estimator) estimate(now uint64) (uint32, uint32) {
2022-04-20 21:27:34 +02:00
if now < e.time {
// time went backwards
if e.time-now > e.interval {
e.time = now
e.packets = 0
e.bytes = 0
}
} else if now-e.time >= e.interval {
2020-04-30 20:15:52 +02:00
e.swap(now)
}
2022-04-20 21:27:34 +02:00
return e.rate, e.packetRate
2020-04-30 20:15:52 +02:00
}
2021-01-19 20:40:19 +01:00
// Estimate returns an estimate of the rate over the last interval.
// It starts a new interval if the last interval is larger than the value
// passed to New. It returns the byte rate and the packet rate, in units
// per second.
func (e *Estimator) Estimate() (uint32, uint32) {
2022-04-20 21:27:34 +02:00
e.mu.Lock()
defer e.mu.Unlock()
return e.estimate(rtptime.Now(rtptime.JiffiesPerSec))
2020-04-30 20:15:52 +02:00
}
2020-05-31 23:54:55 +02:00
2021-01-19 20:40:19 +01:00
// Totals returns the total number of bytes and packets accumulated.
2022-04-20 21:27:34 +02:00
func (e *Estimator) Totals() (uint64, uint64) {
e.mu.Lock()
defer e.mu.Unlock()
return e.totalPackets + uint64(e.packets),
e.totalBytes + uint64(e.bytes)
2020-05-31 23:54:55 +02:00
}