diff --git a/pkg/timing/frameStats.go b/pkg/timing/frameStats.go index 699a7be..1fbfe42 100644 --- a/pkg/timing/frameStats.go +++ b/pkg/timing/frameStats.go @@ -8,15 +8,18 @@ import ( ) type FrameStats struct { - Fps *Fps - frames map[uint32]time.Time - mutex sync.Mutex + Fps *Fps + frames map[uint32]time.Time + mutex sync.Mutex + lastTime *time.Time + deltaTimes map[uint32]time.Duration } func NewFrameStats(timeWindow time.Duration) (s *FrameStats) { s = new(FrameStats) s.Fps = NewFps(timeWindow) s.frames = map[uint32]time.Time{} + s.deltaTimes = map[uint32]time.Duration{} return s } @@ -25,6 +28,10 @@ func (s *FrameStats) Add(frameId uint32, t time.Time) { defer s.mutex.Unlock() s.frames[frameId] = t s.Fps.Inc() + if s.lastTime != nil { + s.deltaTimes[frameId] = t.Sub(*s.lastTime) + } + s.lastTime = &t } func (s *FrameStats) Prune(to time.Time) { @@ -33,6 +40,7 @@ func (s *FrameStats) Prune(to time.Time) { for frameId, t := range s.frames { if t.Before(to) { delete(s.frames, frameId) + delete(s.deltaTimes, frameId) } } } @@ -41,6 +49,7 @@ func (s *FrameStats) Clear() { s.mutex.Lock() defer s.mutex.Unlock() s.frames = map[uint32]time.Time{} + s.deltaTimes = map[uint32]time.Duration{} s.Fps.Clear() } @@ -61,6 +70,24 @@ func (s *FrameStats) Quality() float64 { return sum / float64(max-min+1) } +func (s *FrameStats) DeltaTime() (mu float64, stdDev float64) { + s.mutex.Lock() + defer s.mutex.Unlock() + var sum time.Duration + for _, dt := range s.deltaTimes { + sum += dt + } + mu = sum.Seconds() / float64(len(s.deltaTimes)) + + var sqSum float64 + for _, dt := range s.deltaTimes { + diff := mu - dt.Seconds() + sqSum += diff * diff + } + stdDev = math.Sqrt(sqSum / float64(len(s.deltaTimes))) + return +} + func (s *FrameStats) NumFrames() int { return len(s.frames) } @@ -68,5 +95,6 @@ func (s *FrameStats) NumFrames() int { func (s *FrameStats) String() string { fps := s.Fps.Float32() quality := s.Quality() - return fmt.Sprintf("%v @ %3.0f fps", colorizePercent(quality), fps) + dt, dtStdDev := s.DeltaTime() + return fmt.Sprintf("%v @ %3.0f fps | Δ %.1fms σ %.3f", colorizePercent(quality), fps, dt*1000, dtStdDev*1000) }