FPS Counter (683389)

Hello everybody.

I have made myself this simple fps counter script that display’s the current frame count in a simple ui text. So my question is kind of weird, but does this script display’s accurate frame rate? Or are there any better ways checking the current frame rate? I just want to make sure I’m not seeing false thing on my screen. Cause sometimes I see pretty high fps and I just want to make sure it’s actually true or not. Thank you.

The Script:

using UnityEngine;
using UnityEngine.UI;

public class FPSDisplay : MonoBehaviour
{
    public int avgFrameRate;
    public Text display_Text;

    public void Update ()
    {
        float current = 0;
        current = Time.frameCount / Time.time;
        avgFrameRate = (int)current;
        display_Text.text = avgFrameRate.ToString() + " FPS";
    }
}
8 Likes

This should do it.

current = (int)(1f / Time.unscaledDeltaTime);

Here’s a full script. Just drag in your own Text (Legacy) component.

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FPSCounter : MonoBehaviour
{
    public Text Text;

    private Dictionary<int, string> CachedNumberStrings = new();
    private int[] _frameRateSamples;
    private int _cacheNumbersAmount = 300;
    private int _averageFromAmount = 30;
    private int _averageCounter = 0;
    private int _currentAveraged;
 
    void Awake()
    {
        // Cache strings and create array
        {
            for (int i = 0; i < _cacheNumbersAmount; i++) {
                CachedNumberStrings[i] = i.ToString();
            }
            _frameRateSamples = new int[_averageFromAmount];
        }
    }
    void Update()
    {
        // Sample
        {
            var currentFrame = (int)Math.Round(1f / Time.smoothDeltaTime); // If your game modifies Time.timeScale, use unscaledDeltaTime and smooth manually (or not).
            _frameRateSamples[_averageCounter] = currentFrame;
        }

        // Average
        {
            var average = 0f;

            foreach (var frameRate in _frameRateSamples) {
                average += frameRate;
            }

            _currentAveraged = (int)Math.Round(average / _averageFromAmount);
            _averageCounter = (_averageCounter + 1) % _averageFromAmount;
        }

        // Assign to UI
        {
            Text.text = _currentAveraged switch
            {
                var x when x >= 0 && x < _cacheNumbersAmount => CachedNumberStrings[x],
                var x when x >= _cacheNumbersAmount => $"> {_cacheNumbersAmount}",
                var x when x < 0 => "< 0",
                _ => "?"
            };
        }
    }
}
16 Likes

Thank you for the response! The fps seems definitely more accurate now.

6 Likes

Thanks for making this script it has really helped me track my fps

2 Likes

This will display the FPS in UI.Text updated once per second. Tweak the HudRefreshRate to refresh the FPS text in a different rate:

using UnityEngine;
using UnityEngine.UI;

public class FpsCounter : MonoBehaviour
{
    [SerializeField] private Text _fpsText;
    [SerializeField] private float _hudRefreshRate = 1f;

    private float _timer;

    private void Update()
    {
        if (Time.unscaledTime > _timer)
        {
            int fps = (int)(1f / Time.unscaledDeltaTime);
            _fpsText.text = "FPS: " + fps;
            _timer = Time.unscaledTime + _hudRefreshRate;
        }
    }
}
9 Likes

This one’s similar to the others with a minor difference in format. I feel like any of these work really well, lots of great coders out there! This one in particular allows an easy edit to string format, refresh rate, and time-lapse lets you switch between deltaTime, smoothDeltaTime of fixedDeltaTime to see the difference. It’s not any better than other examples, just another fun option with more to play around with. :slight_smile:

public class FPSCounter : MonoBehaviour
{

    public float timer, refresh, avgFramerate;
    string display = "{0} FPS";
    private Text m_Text;

    private void Start()
    {
        m_Text = GetComponent<Text>();
    }


    private void Update()
    {
        //Change smoothDeltaTime to deltaTime or fixedDeltaTime to see the difference
        float timelapse = Time.smoothDeltaTime;
        timer = timer <= 0 ? refresh : timer -= timelapse;

        if(timer <= 0) avgFramerate = (int) (1f / timelapse);
        m_Text.text = string.Format(display,avgFramerate.ToString());
    }
}
7 Likes

You can just use invoke to call every 1 second, a little easier
7272520--878359--upload_2021-6-25_17-35-1.png

7272520--878356--upload_2021-6-25_17-34-32.png

4 Likes
//Below is slightly more solid (Just being nitpicky, sorry)
InvokeRepeating(nameof(GetFPS), 1,1);
1 Like

Hi, thanks for share your codes, i did it but the editor shows 150 fps while the script is showing 90 fps, so, is this script accurate?

Editor shows “fake” FPS because it subtracts editor overhead time, this script shows actual FPS in editor window. But your FPS in build will be closer to the stats window FPS.

1 Like

this is a way to make a good performance gor your game guys

int fps
fps = bla bla bla

Time.timeScale = _fps / 60;

if (Time.timeScale > 1)
{
Time.timeScale = 1;
}

//thats mean if fps > 60 the speed if the game will be 1 wich mean normal speed
and if fps < 60 the speed will be fps count / 60

and that let the cpu and gpu do his process in a easy way

he show the fps of
the engine not the game

That doesn’t improve performance at all, it just makes things move slow for no reason

3 Likes

maybe yes but in some situations its really help on performance maybe not your project it could be any project

It doesn’t improve performance at all, unless you’re doing a lot of FixedUpdate calculations.
https://discussions.unity.com/t/387813

1 Like

Since InvokeRepeating is generally not recommended, you can use IEnumertor Start() instead

using System.Collections;
using UnityEngine;

namespace Tools
{

    public class FpsCounter : MonoBehaviour
    {
 
        public int Fps { get; private set; }
        [SerializeField] private float fpsRefreshTime = 1f;

        private WaitForSecondsRealtime _waitForSecondsRealtime;

        private void OnValidate()
        {

            SetWaitForSecondsRealtime();
        }

        private IEnumerator Start()
        {

            SetWaitForSecondsRealtime();

            while (true)
            {

                Fps = (int)(1 / Time.unscaledDeltaTime);
                yield return _waitForSecondsRealtime;
            }
        }

        private void SetWaitForSecondsRealtime()
        {

            _waitForSecondsRealtime = new WaitForSecondsRealtime(fpsRefreshTime);
        }
    }
}

This script shows it accurately, it works on mobile, it uses the GUI.
It divides the framecount by the time passed, it can be configure to update at any interval.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShowFPSMobile : MonoBehaviour
{
    // provided by Niter88
    private string fps = "";

    private WaitForSecondsRealtime waitForFrequency;

    GUIStyle style = new GUIStyle();
    Rect rect;

    bool isInicialized = false;


    private void Awake()
    {
        //float fraction = 0.5f; // Render at half the resolution of current screen
        //float fraction = 0.8f;
        //float fraction = 1f;
        //Screen.SetResolution((int)(Screen.currentResolution.width * fraction), (int)(Screen.currentResolution.height * fraction), true);

        //don't use vsync on mobile, limit fps instead

        // Sync framerate to monitors refresh rate
        //Use 'Don't Sync' (0) to not wait for VSync. Value must be 0, 1, 2, 3, or 4
        QualitySettings.vSyncCount = 0;

        // Disable screen dimming
        Screen.sleepTimeout = SleepTimeout.NeverSleep;

        //Inicialize(true); //use for testing on editor
    }

    private IEnumerator FPS()
    {
        int lastFrameCount;
        float lastTime;
        float timeSpan;
        int frameCount;
        for (; ; )
        {
            // Capture frame-per-second
            lastFrameCount = Time.frameCount;
            lastTime = Time.realtimeSinceStartup;
            yield return waitForFrequency;
            timeSpan = Time.realtimeSinceStartup - lastTime;
            frameCount = Time.frameCount - lastFrameCount;

            fps = string.Format("FPS: {0}", Mathf.RoundToInt(frameCount / timeSpan));
        }
    }

  
    void OnGUI()
    {
        // Display
        GUI.Label(rect, fps, style);
        //GUI.Label(new Rect(Screen.width - 110, 5, 0, Screen.height * 2 / 100), fps, style);

        //GUI.Label(new Rect(10, 10, Screen.width, Screen.height * 2 / 100), fps, style);
        //GUI.Label(new Rect(Screen.width - 100, 10, 150, 20), fps, style);
    }

    private void Inicialize(bool showFps)
    {
        isInicialized = true;

        style.alignment = TextAnchor.UpperLeft;
        style.fontSize = Screen.height * 3 / 100;
        style.normal.textColor = new Color32(0, 200, 0, 255);
        rect = new Rect(Screen.width * 90 / 100, 5, 0, Screen.height * 2 / 100);

        if(showFps)
            StartCoroutine(FPS());
    }
  

    public void SetNewConfig(GraphicSettingsMB gSettings)
    {
        Application.targetFrameRate = gSettings.targetFrameRate;

        waitForFrequency = new WaitForSecondsRealtime(gSettings.testFpsFrequency);

        if (!isInicialized) Inicialize(gSettings.showFps);

        if (!gSettings.showFps)
            Destroy(this.gameObject);
    }
}

[SerializeField]
public class GraphicSettingsMB
{
    public byte targetFrameRate = 30;
    public byte testFpsFrequency = 1;
    public bool showFps = false;
}

just run this function in Update() and you have an fps counter:

void fpsCounter()
{
if (timer < 1)
{
timer += Time.deltaTime;
frameRate += 1;
}
else
{
Debug.Log("FPS: " + frameRate.ToString());
timer = 0;
frameRate = 0;
}
}

How do i acutally use any of those scripts? I created a new one but what component of my scene should i add the script to? Or does this work differently?

1 Like

Here’s the script from the top, but i modified the text to work with TextMeshPro. Just add the script to an empty gameobject or whatever you’d like honestly, then drag a UI text from your canvas :slight_smile: ( edit: I added an additional text indicator which will now read as, “FPS: (however many frames)” ) ( another edit: I added a space to “FPS: " … I missed that somehow)” )

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class FPSCounter : MonoBehaviour
{
    private TextMeshProUGUI Text;
    public TextMeshProUGUI FPS_Text;

    private Dictionary<int, string> CachedNumberStrings = new();
    private int[] _frameRateSamples;
    private int _cacheNumbersAmount = 300;
    private int _averageFromAmount = 30;
    private int _averageCounter = 0;
    private int _currentAveraged;

    void Awake()
    {
        // Cache strings and create array
        {
            for (int i = 0; i < _cacheNumbersAmount; i++)
            {
                CachedNumberStrings[i] = i.ToString();
            }
            _frameRateSamples = new int[_averageFromAmount];
        }
    }
    void Update()
    {
        // Sample
        {
            var currentFrame = (int)Math.Round(1f / Time.smoothDeltaTime); // If your game modifies Time.timeScale, use unscaledDeltaTime and smooth manually (or not).
            _frameRateSamples[_averageCounter] = currentFrame;
        }

        // Average
        {
            var average = 0f;

            foreach (var frameRate in _frameRateSamples)
            {
                average += frameRate;
            }

            _currentAveraged = (int)Math.Round(average / _averageFromAmount);
            _averageCounter = (_averageCounter + 1) % _averageFromAmount;
        }

        // Assign to Private Text value
        {
            Text.text = _currentAveraged < _cacheNumbersAmount && _currentAveraged > 0
                ? CachedNumberStrings[_currentAveraged]
                : _currentAveraged < 0
                    ? "< 0"
                    : _currentAveraged > _cacheNumbersAmount
                        ? $"> {_cacheNumbersAmount}"
                        : "-1";
        }
        // Assign to UI with additional text indicator
        {
            FPS_Text.text = "FPS: " + Text.text;
        }

    }
}
}