315. Main fps counter

Add a simple periodic FPS counter to main.py.

Lesson 315 of 356 · tests/chapter_10_performance/test_315_main_fps_counter.py

File to update

main.py

Why this step exists

Before optimizing pygame rendering or emulator speed, the manual runner should show a simple end-to-end FPS signal in the terminal.

The FPS counter should measure the complete manual frame path

Console.step_until_next_frame()
Console.render_framebuffer()
draw_framebuffer(...)
pygame.display.flip()

Suggested implementation example

import time

FPS_REPORT_INTERVAL_SECONDS = 1.0

...

running = True
last_fps_report_time = time.perf_counter()
frames_since_last_report = 0

while running:
    ...

    executed = console.step_until_next_frame()
    framebuffer = console.render_framebuffer()
    draw_framebuffer(window, framebuffer, SCALE)
    pygame.display.flip()

    frames_since_last_report += 1
    now = time.perf_counter()
    elapsed = now - last_fps_report_time

    if elapsed >= FPS_REPORT_INTERVAL_SECONDS:
        fps = frames_since_last_report / elapsed
        print(f"fps={fps:.1f}")
        frames_since_last_report = 0
        last_fps_report_time = now

Important

This is intentionally simple. It does not separate emulation time from render time. It only gives a visible terminal signal before optimization work.

Why source-shape tests? main.py opens pygame and runs a manual loop. Automated tests must not call main(), open a window, or require a commercial ROM.

Out of scope

  • optimizing pygame drawing
  • frame pacing / speed cap
  • profiling individual subsystems
  • launching PyPy
  • calling main() from pytest

Run this lesson

uv run pytest tests/chapter_10_performance/test_315_main_fps_counter.py -v