Use a rolling time-window queue of frame timestamps, not a fixed frame count, to get a consistent FPS measurement that doesn’t depend on its own output values.
Key Takeaways
Methods 1 and 2 (single-frame or N-frame averages) are flawed: N-frame windows have variable time coverage, making the FPS graph inconsistent across periods of fast vs. slow frames.
The correct approach (Method 4/5) stores a queue of recent frame timestamps or {timestamp, processingTime} structs, evicting entries older than the window duration each tick.
Window size and display update frequency are independent knobs: a 1-second window can refresh the UI every 100ms, or every 500ms, without changing the measurement.
Method 5 extends naturally to average frame time, worst-frame tracking, and standard deviation – all from the same rolling queue of FrameEvent structs.
For low-memory or allocation-sensitive contexts, a fixed-capacity circular buffer works; size it large enough that eviction is rare, and track the actual covered duration for correctness.
Use SDL_GetPerformanceCounter/SDL_GetPerformanceFrequency or std::chrono::high_resolution_clock – coarse timers will corrupt short frame-time measurements.