Server CPU Load Measuring

Roblox gives you many tools in Studio to monitor many aspects of your game while testing like how much memory it is using, how much bandwidth, and how much CPU time each scripts is using, etc. That’s great when you are doing a team test or testing solo, but in a public server you don’t have that luxury. If something is causing a CPU time overload in a public server, you aren’t there to see it or even know about until you start getting complaints from players. As far as I have been about to find in my research, Roblox does not provide any functions to get the “whole” server CPU load of your game while it is running. That is where this script becomes very useful.

This script uses clock measurements to calculate how fast your server is running and generate a rounded number between 0 and 100 to represent a percentage of how busy it is. This number is stored directly into the game as an attribute that can be accessed by any server or client script. Using that number, you can create your own monitoring system that can be used with throttling functions for example. The same data could be used to create a CPU graph of how busy your server is, another example. This is very useful information for developers trying to maximize their game speed as a whole or pinpoint situations that cause server crashing due to CPU usage overload.

How to setup for your Server:
First, create a script in your “ServerScriptService”, name is something that makes sense to you. I use “ServerCPUMonitor” for mine, but you can name it whatever you like. Put this code into in and save. Now you have real-time “whole” CPU server usage stored in an updating attribute that you can access from any server or client script.

Server CPU Load Measuring Script:

local runService = game:GetService("RunService")
local iTick
local iCPUStart
local iCPUTime
local iPhysicsTime

while true do
	iTick = 60
	iCPUStart = os.clock()

	while iTick > 0 do
		runService.Heartbeat:Wait()
		iTick -= 1			
	end

	iCPUTime = math.round(((1 - ((60 / (os.clock() - iCPUStart))) / 60)) * 100)
	iPhysicsTime = math.round(((1 - (workspace:GetRealPhysicsFPS()) / 60)) * 100)

	if iCPUTime + iPhysicsTime < 1 then
		iCPUTime = 0
	elseif iCPUTime + iPhysicsTime > 100 then
		iCPUTime = 100
	else
		iCPUTime += iPhysicsTime
	end

	-- Save CPU Time
	game.Workspace:SetAttribute("ServerCPULoad", iCPUTime)
end

How to setup for your Client:
First, create a LocalScript in your “StarterPlayerScripts” folder, name is something that makes sense to you. I use “ClientCPUMonitor” for mine, but you can name it whatever you like. Put this code into in and save. Now you have real-time “whole” CPU client usage stored in an updating attribute that you can access from client scripts only.

Client CPU Load Measuring Script:

local runService = game:GetService("RunService")
local oLocalPlayer = game:GetService("Players").LocalPlayer -- Get The Player

local iTick
local iCPUStart
local iCPUTime
local iPhysicsTime

while true do
	iTick = 60
	iCPUStart = os.clock()

	while iTick > 0 do
		runService.Heartbeat:Wait()
		iTick -= 1			
	end

	iCPUTime = math.round(((1 - ((60 / (os.clock() - iCPUStart))) / 60)) * 100)
	iPhysicsTime = math.round(((1 - (workspace:GetRealPhysicsFPS()) / 60)) * 100)
	
	if iCPUTime + iPhysicsTime < 1 then
		iCPUTime = 0
	elseif iCPUTime + iPhysicsTime > 100 then
		iCPUTime = 100
	else
		iCPUTime += iPhysicsTime
	end
	
	oLocalPlayer:SetAttribute("ClientCPULoad", iCPUTime)
end

Q&A
1. What performance hit does running this do to my game?
You can check the script analyzer yourself, should be near 0.000% usage most of the time.

2. Why did you do a loop within a loop?
It’s necessary to get accurate measurements and make it as efficient as possible.

3. Why does this work, is it magic?
It’s measuring how fast your server can generate frames. Anything less than 60 FPS is the result of the server becoming more busy. Knowing that, you can extrapolate a load reading and then scale it from 0 to 100. So if your server is running at 59 FPS, that would mean about 2% of it’s speed is going towards keeping your game running. I use rounded numbers for ease of use, but you can remove the rounding function if you want long, exact numbers instead.

4. Doesn’t Roblox Already Give You This With (insert function here)?
If it does, please share! :sweat_smile:

5. How do I access this information in real-time within my game?
A simple script print example:

local iCPULoad

while true do
	iCPULoad = workspace:GetAttribute("ServerCPULoad") or 0
	
	print("Server CPU: " .. tostring(iCPULoad) .. "%")
	task.wait(1)
end

Edit: VortextColor has shown me that workspace:GetRealPhysicsFPS() provides the Physics FPS and that it works independent from the rest of the server. After some testing, this also has an effect on server load and thus I’ve updated the script above to include it in the load calculations. Even though the two are calculated independently, if either one is maxed out, it still results in a server slowdown for the players.

Edit2: Only makes sense to post up the client code I use too. Basically works the same way, but gives you a client attribute that you can access from the client only. If you want to throttle functions that your client is processing for example. Useful for low end devices like phones and tablets if you don’t want to over-load them with too many client special fx as another example.

List of Tools & GUIs Made by Community Members:

15 Likes

You can also use workspace:GetRealPhysicsFPS() to get teh server FPS.

1 Like

Really thanks for this! I have a question:

What if my game runs at more/less than 60 FPS? Do I simply change the iTick = ??

When I will get home I will try to create a toggle le GUI for the Owner of the game so they can see it in real-time (in case there’s something that is destroying the CPU)

This is measuring from the server, so unless Roblox changes something in the core (say they up sever speeds to 90 FPS), this number should remain constant. Is there a function to change the core speed of the server in Roblox? :melting_face:

I don’t know, I was only asking, thanks for answering, when I can I’m gonna post here an open-source GUI+script for checking the CPU while in game, if you are gonna include it in your post could you credit me pls?

Rendering physics can be anything higher than 60.
Physics FPS, heartbeat FPS and network FPS can be 60 or lower (though they can go higher than 60 if the game needs to speed up after lag).

But anyways if your script needs to depend on the FPS then it’s bad code and invalid. It’s always a good idea to design code so that FPS doesn’t affect it drastically.

I was hopeful when you posted this because that is what I was looking for, so I put in into a quick test. At first it looked great, I was getting FPS readings for the server. Then I turned off all the throttling functions I use in my game to max out the server CPU and while my script was showing +99% CPU (and the server was grinding to a halt speed wise), this function was still reporting 59.9999 FPS which I knew wasn’t right because I could see the game slowing down on a public Roblux server. This function could have really simplified my script above, but unfortunately, it does not seem to be measuring the server as a whole? :neutral_face:

1 Like

Then it means that the server FPS still runs at that count.

Are you sure you are doing this on the server. As the client and the server have different FPSes.

Actually the opposite, using FPS is the only way to determine how busy it is. If a server is being CPU capped there is no way for the game to determine that itself as Roblox controls this.

Yes thats true. But what I meant was that if a script needs the FPS to be specific to function properly then the script is improperly written.

This is what was running on the server, let me know if I did wrong.

while true do
	print("FPS: " .. tostring(workspace:GetRealPhysicsFPS()))
	task.wait(1)
end
1 Like

How so? If all Roblox servers are running at 60 FPS, how else do you determine the max within the game itself? How is the game suppose to know what Roblox is capping it at?


image

Oh I see what you mean. It appears that the physics FPS runs faster than the render & heartbeat FPS.

It appears that you were right. In this case you need to use .HeartBeat if you need to know the script FPS. But the workspace:GetRealPhysicsFPS() returns the physics FPS, apparently they can be independet of each other which i did not know lol.

Like.

Let’s take an example

This script which moves a part:

while true do
	task.wait()
	part.Position += Vector3.new(0.05, 0, 0.01)
end

is a bad script because it’s effect depends on how fast the FPS is.

A much better script would be with using delta time

local start = os.clock()
local startpos = part.Position

while true do
	part.Position = startpos + (Vector3.new(0.05, 0, 0.01) * ((os.clock() - start) / (1/60)))
	task.wait()
end

because the second script doesnt depend on the server FPS

1 Like

Thanks for checking, I was hopeful you found a way I could optimize this script better. Mainly, it’s goal is to take in the server as a whole, hence why I found that only the heartbeat would work for that in testing.

Yeah, that’s fine. I was going to include something like that in my original post (I created such a GUI last year for my game to show server and client CPU usage in a public server), but wanted to keep things simple as this was my first time posting in this forum. So if you want to create an awesome CPU gui, I’ll be glad to give credit as long as it goes both ways. :grinning:

The thing is taht I’m not an artist so it will not be awesome, but the best thing of GUIs is that they’re customisable, so tecnichally people could just take the script and customise the GUI, but I’m gonna do my best! (Also yes this time you replied to the right post)

Hi I’ve seen that you’ve added a LocalCPU, how would I require it?

To access that attribute on the Client, only scripts running on the Client would be able to.

So using the same print example for the server, but running on the Client would look like.

local oLocalPlayer = game:GetService("Players").LocalPlayer -- Get The Player
local iCPULoad

while true do
	iCPULoad = oLocalPlayer:GetAttribute("ClientCPULoad") or 0
	
	print("Client CPU: " .. tostring(iCPULoad) .. "%")
	task.wait(1)
end
1 Like

Yeah sorry, I figured taht out by myself by looking a little in the script, thanks for the explanation tho!