How to calculate FPS(Frames Per Second)

Hello, this is my first tutorial. Dunno if this is worth making a tutorial about but I decided why not since I had a couple friends ask me how I calculate FPS, which is pretty simple. This is just a lesson on the formula of FPS and how to accurately calculate it. This same formula applies to other languages like Java, Python, etc.

The way we will be calculating FPS is with a counter. Pretty simple to learn. All we’re doing is counting the number of frames rendered in X amount of seconds, which is 1.

The only requirement for this is that you have a basic understanding of os.clock() and RunService. As well as RenderStepped and Heartbeat, since that is what we will be using in this tutorial. Here is a link to os. Here is a link to RunService, RenderStepped, and HeartBeat

I don’t think you need me to tell you how to make a textlabel in a screengui. BUT, this belongs in a LOCAL script. Since we’re obviously calculating the clients FPS.

The formula is pretty simple. Just sound out Frames Per Second.

Formula

Frames PER Second, So we divide Frames and Second
Frames / 1 Second
The # of Frames Passed / In a Single Second

  • To translate into code
FPS = Frames / (currentTime - startTime)
--[[
Frames is the counter // This as I said before, counts the number of frames that have been rendered in X amount of seconds, which is 1. So you divide the counter by the current and start time
currentTime IS os.clock() // This is the currentTime you have started to count the # of FPS
startTime EQUALS os.clock() // The initial time recorded
]]
-- Thus
FPS = Counter / (os.clock() - startTime) -- The actual formula

Now that we know the formula, we need the proper way to write/accurately calculate it.

Another thing is we also reset the counter and initial time recorded. If you don’t, the FPS won’t be measured. Always reset the counter back to 0 and startTime back to os.clock(). In literal terms it’s the FPS. Since we already recorded how many frames rendered in a single second, we reset to to record it again.

Sorry if that is confusing I suck at explaining myself

The Code
-- Services
local RunService = game:GetService("RunService")

-- Variables
local startTime = os.clock() -- Record initial time
local X = 1 -- This is important you will see why. It also doesn't have to be a variable. 
local FPS_Counter = 0

local RenderStepped = RunService.RenderStepped -- Outputs same as Heartbeat
local Heartbeat = RunService.Heartbeat -- Outputs same as RenderStepped
local FPSLabel = script.Parent


-- Function
local function GetFPS()
	FPS_Counter+=1
	if (os.clock() - startTime) >= X  then -- Notice how we are using the formula for recording the amount of time passed. It's in the link above. os
		local fps = math.floor(FPS_Counter / (os.clock() - startTime))
		FPSLabel.Text = fps
		FPS_Counter = 0 -- Here is where the reset comes in
		startTime = os.clock()
	end
end

--[[
The reason for the if statement and the X variable is to put simply, it accurately tells us
the # of frames passed in a single second. 

Just duplicate the script and remove the if statement, you'll see what I mean

Basically, it only updates every single second. If I set X = 10,
then it would tell me my FPS every 10 seconds. But we don't want that do we now? 

P.S. You don't have to floor the fps, unless you want decimals.
]]
Heartbeat:Connect(GetFPS) -- Self explanatory 

FPSExample.rbxl (24.4 KB)

The place file to test yourself.

I know there’s other posts on the devforum on how to calculate FPS. But I found none of them to be as accurate as my way. If there is something on the devforum that goes in depth about this, lemme know.

Hope you enjoyed the tutorial. Feedback appreciated.

13 Likes

Since RunService connections pass deltaTime as one of their arguments, couldn’t you achieve the same by just using 1/deltaTime inside the connection and avoiding having to keep track of time yourself?

7 Likes

Doing that doesn’t really give me that accurate of a measurement for FPS. Keeping track of it ourselves I found outputs the most accurate FPS. If you compare the 2 mine shows more accurate frames as opposed to 1/deltatime.

If that makes sense. I assume you’re talking about something like this,

local RunService = game:GetService("RunService")

local label = script.Parent


local function onRenderStep(deltaTime)
	local fps = math.floor(1 /deltaTime)
	label.Text = ''..fps..'' 
end

RunService.RenderStepped:Connect(onRenderStep)

And while that kinda works, you can notice the FPS jump from 60-80 when that’s not the actual FPS of the client. As opposed to mine which I explained before, outputs accurate FPS.

You might have forgotten to remove two sets of quotes

What do you mean by that? That’s how you write it? Are you saying I could’ve wrote

FPSLabel.Text = fps

cause I put quotes there in case I wanted to put 60 FPS

You could have just done FPSLabel.Text = fps

Yeah, you’re right. I left it there when I wrote the string a different way.

This doesn’t seem to be the case for Stepped, which consistently gives me the correct value.

2 Likes

Could you show me the code possibly? Curious as to how you’re getting the correct value.

I set up a text label and then set its contents as such:

RunService.Stepped:Connect(function(_, dt)
    text_label.Text = math.ceil(1 / dt)
end)
3 Likes

Weird. After I ran multiple tests, yours was consistent the first 2 times, then after the 3rd test, it wasn’t as accurate and gave me FPS of 80-120 at times.

For me it gave me something between 5 and 30