The Python Arcade Library: Frame rate

App Window

Frame rate may refer to the average or current number of frames per second. How to calculate the amount of frames generated in time of one second? There is more than one good answer.

Basics

FPS is a number of frames generated by hardware in a time one second. The score depends on GPU, processor, memory and even monitor. Bigger resolution, more elements on the screen and even bad software optimization means less FPS. Because of that FPS is really good performance factor to have eye on while writing own software.

This is basic formula for FPS:

fps_current = 1 / (single_frame_end_time - single_frame_start_time)

As you can see. FPS change after each generation of frame. To change that we can replace “1” with counter of generated frames. This way we get changing over time average FPS.

fps_avg = counter_of_frames / (current_time - START_TIME)

The problem is that after each generation of frame there is increase of counter and current time, but start time is always the same. This is bad code, because each next result has a bigger error than the previous one. So what can we do? Samples are the answer.

import time

def fps():
    while(time.time() != 0):
        start_time = time.time()
        counter_of_frames = 0
        for generation_of_frames in range(0, 50):
            counter_of_frames += 1
# Wait to simulate generation of single frame in constans 60fps
            time.sleep(1/60)
        end_time = time.time()
        fps = counter_of_frames / float(end_time - start_time)
        return fps

while time.time != 0:
    print(fps())

Ok. So this is one way to write this. In python we have collections. It would be nice to use them in this example.

import time
import collections

class FPS:
    def __init__(self):
        self.total_time = 0.0
        self.time = time.perf_counter()
        self.frame_times = collections.deque(maxlen=60)

    def fps_tick(self):
        t1 = time.perf_counter()
        dt = t1 - self.time
        self.time = t1
        self.frame_times.append(dt)

    def get_fps(self):
        total_time = sum(self.frame_times)
        if total_time == 0:
            return 0
        else:
            return len(self.frame_times) / sum(self.frame_times)

fps = FPS()
while time.time != 0:
    fps.fps_tick()
    time.sleep(1/60)
    print(fps.get_fps())

Tests

To compare these four methods I wrote a scripts using Arcade.

0_fps_single_frame.py

/examples/02_frame_rate/0_fps_single_frame.py

Simple solution, simple score.

Pros:
+ Live FPS score
+ Easy implementation

Cons:
– Works well with constant update_rate, e.g. 60FPS. Without it score looks random.

1_fps_counter_of_frames.py

examples/02_frame_rate/1_fps_counter_of_frames.py

Each call of function on_draw is an iteration +1 of frame counter. Because there is only a time of running proces this counter is best suited to count average fps from the beginning to the end of application’s run.

Pros:
+ Easy implementation

Cons:
– It takes time to score avg value of fps, starting from 0
– Only last record counts

2_fps_loop_samples.py

/examples/02_frame_rate/2_fps_loop_samples.py

This time we use loop to count average fps of sample 20 frames. Size of samples can be changed (fps_loops = 20).

Pros:
+ Live FPS score
+Configurable counter
+ Accuracy

Cons:
– Time consuming (low optimization of code)

3_fps_collections.py

/examples/02_frame_rate/3_fps_collections

Perfection. Configurable, accurate, optimized fps script. Collections have no impact on drawing time. The best solution to use to count FPS in Arcade Library.

Pros:
+ Live FPS score
+ Configurable counter
+ Good optimization
+ Accuracy

Leave a Reply

Your email address will not be published. Required fields are marked *