Search Unity

FPS Counter

Discussion in 'Scripting' started by Rukas90, Nov 20, 2017.

  1. Rukas90

    Rukas90

    Joined:
    Sep 20, 2015
    Posts:
    169
    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:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3.  
    4. public class FPSDisplay : MonoBehaviour
    5. {
    6.     public int avgFrameRate;
    7.     public Text display_Text;
    8.  
    9.     public void Update ()
    10.     {
    11.         float current = 0;
    12.         current = Time.frameCount / Time.time;
    13.         avgFrameRate = (int)current;
    14.         display_Text.text = avgFrameRate.ToString() + " FPS";
    15.     }
    16. }
     
  2. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    This should do it.

    Code (csharp):
    1. current = (int)(1f / Time.unscaledDeltaTime);
    Here's a full script. Just drag in your own Text (Legacy) component.
    https://gist.github.com/st4rdog/80057b406bfd00f44c8ec8796a071a13
    Code (csharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class FPSCounter : MonoBehaviour
    7. {
    8.     public Text Text;
    9.  
    10.     private Dictionary<int, string> CachedNumberStrings = new();
    11.     private int[] _frameRateSamples;
    12.     private int _cacheNumbersAmount = 300;
    13.     private int _averageFromAmount = 30;
    14.     private int _averageCounter = 0;
    15.     private int _currentAveraged;
    16.  
    17.     void Awake()
    18.     {
    19.         // Cache strings and create array
    20.         {
    21.             for (int i = 0; i < _cacheNumbersAmount; i++) {
    22.                 CachedNumberStrings[i] = i.ToString();
    23.             }
    24.             _frameRateSamples = new int[_averageFromAmount];
    25.         }
    26.     }
    27.     void Update()
    28.     {
    29.         // Sample
    30.         {
    31.             var currentFrame = (int)Math.Round(1f / Time.smoothDeltaTime); // If your game modifies Time.timeScale, use unscaledDeltaTime and smooth manually (or not).
    32.             _frameRateSamples[_averageCounter] = currentFrame;
    33.         }
    34.  
    35.         // Average
    36.         {
    37.             var average = 0f;
    38.  
    39.             foreach (var frameRate in _frameRateSamples) {
    40.                 average += frameRate;
    41.             }
    42.  
    43.             _currentAveraged = (int)Math.Round(average / _averageFromAmount);
    44.             _averageCounter = (_averageCounter + 1) % _averageFromAmount;
    45.         }
    46.  
    47.         // Assign to UI
    48.         {
    49.             Text.text = _currentAveraged switch
    50.             {
    51.                 var x when x >= 0 && x < _cacheNumbersAmount => CachedNumberStrings[x],
    52.                 var x when x >= _cacheNumbersAmount => $"> {_cacheNumbersAmount}",
    53.                 var x when x < 0 => "< 0",
    54.                 _ => "?"
    55.             };
    56.         }
    57.     }
    58. }
     
    Last edited: Aug 29, 2023
  3. Rukas90

    Rukas90

    Joined:
    Sep 20, 2015
    Posts:
    169
    Thank you for the response! The fps seems definitely more accurate now.
     
  4. kyranclancy

    kyranclancy

    Joined:
    Jun 10, 2018
    Posts:
    1
    Thanks for making this script it has really helped me track my fps
     
    lyingturkey and gabearts like this.
  5. kubajs

    kubajs

    Joined:
    Apr 18, 2015
    Posts:
    58
    This will display the FPS in UI.Text updated once per second. Tweak the HudRefreshRate to refresh the FPS text in a different rate:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3.  
    4. public class FpsCounter : MonoBehaviour
    5. {
    6.     [SerializeField] private Text _fpsText;
    7.     [SerializeField] private float _hudRefreshRate = 1f;
    8.  
    9.     private float _timer;
    10.  
    11.     private void Update()
    12.     {
    13.         if (Time.unscaledTime > _timer)
    14.         {
    15.             int fps = (int)(1f / Time.unscaledDeltaTime);
    16.             _fpsText.text = "FPS: " + fps;
    17.             _timer = Time.unscaledTime + _hudRefreshRate;
    18.         }
    19.     }
    20. }
     
  6. gabearts

    gabearts

    Joined:
    Jun 30, 2014
    Posts:
    10
    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. :)

    Code (CSharp):
    1.  
    2. public class FPSCounter : MonoBehaviour
    3. {
    4.  
    5.     public float timer, refresh, avgFramerate;
    6.     string display = "{0} FPS";
    7.     private Text m_Text;
    8.  
    9.     private void Start()
    10.     {
    11.         m_Text = GetComponent<Text>();
    12.     }
    13.  
    14.  
    15.     private void Update()
    16.     {
    17.         //Change smoothDeltaTime to deltaTime or fixedDeltaTime to see the difference
    18.         float timelapse = Time.smoothDeltaTime;
    19.         timer = timer <= 0 ? refresh : timer -= timelapse;
    20.  
    21.         if(timer <= 0) avgFramerate = (int) (1f / timelapse);
    22.         m_Text.text = string.Format(display,avgFramerate.ToString());
    23.     }
    24. }
    25.  
     
  7. gersonbellodegoes

    gersonbellodegoes

    Joined:
    Jun 17, 2018
    Posts:
    2
    You can just use invoke to call every 1 second, a little easier
    upload_2021-6-25_17-35-1.png
     

    Attached Files:

    Last edited: Jun 25, 2021
  8. thephoenix007

    thephoenix007

    Joined:
    Nov 29, 2018
    Posts:
    7
    Code (CSharp):
    1. //Below is slightly more solid (Just being nitpicky, sorry)
    2. InvokeRepeating(nameof(GetFPS), 1,1);
     
    Azebakh likes this.
  9. impheris

    impheris

    Joined:
    Dec 30, 2009
    Posts:
    1,667
    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?
     
  10. Genebris

    Genebris

    Joined:
    Mar 18, 2013
    Posts:
    144
    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.
     
    herofille likes this.
  11. herofille

    herofille

    Joined:
    Jul 12, 2020
    Posts:
    6
    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
     
  12. herofille

    herofille

    Joined:
    Jul 12, 2020
    Posts:
    6
    he show the fps of
    the engine not the game
     
  13. Genebris

    Genebris

    Joined:
    Mar 18, 2013
    Posts:
    144
    That doesn't improve performance at all, it just makes things move slow for no reason
     
    Bunny83, herofille and Ryiah like this.
  14. herofille

    herofille

    Joined:
    Jul 12, 2020
    Posts:
    6
    maybe yes but in some situations its really help on performance maybe not your project it could be any project
     
  15. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,647
    lyingturkey likes this.
  16. RaveBox

    RaveBox

    Joined:
    Oct 28, 2022
    Posts:
    27
    Since InvokeRepeating is generally not recommended, you can use IEnumertor Start() instead

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3.  
    4. namespace Tools
    5. {
    6.  
    7.     public class FpsCounter : MonoBehaviour
    8.     {
    9.  
    10.         public int Fps { get; private set; }
    11.         [SerializeField] private float fpsRefreshTime = 1f;
    12.  
    13.         private WaitForSecondsRealtime _waitForSecondsRealtime;
    14.  
    15.         private void OnValidate()
    16.         {
    17.  
    18.             SetWaitForSecondsRealtime();
    19.         }
    20.  
    21.         private IEnumerator Start()
    22.         {
    23.  
    24.             SetWaitForSecondsRealtime();
    25.  
    26.             while (true)
    27.             {
    28.  
    29.                 fps = (int)(1 / Time.unscaledDeltaTime);
    30.                 yield return _waitForSecondsRealtime;
    31.             }
    32.         }
    33.  
    34.         private void SetWaitForSecondsRealtime()
    35.         {
    36.  
    37.             _waitForSecondsRealtime = new WaitForSecondsRealtime(fpsRefreshTime);
    38.         }
    39.     }
    40. }
    41.  
     
    Last edited: Dec 7, 2022
  17. Niter88

    Niter88

    Joined:
    Jul 24, 2019
    Posts:
    112
    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.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ShowFPSMobile : MonoBehaviour
    6. {
    7.     // provided by Niter88
    8.     private string fps = "";
    9.  
    10.     private WaitForSecondsRealtime waitForFrequency;
    11.  
    12.     GUIStyle style = new GUIStyle();
    13.     Rect rect;
    14.  
    15.     bool isInicialized = false;
    16.  
    17.  
    18.     private void Awake()
    19.     {
    20.         //float fraction = 0.5f; // Render at half the resolution of current screen
    21.         //float fraction = 0.8f;
    22.         //float fraction = 1f;
    23.         //Screen.SetResolution((int)(Screen.currentResolution.width * fraction), (int)(Screen.currentResolution.height * fraction), true);
    24.  
    25.         //don't use vsync on mobile, limit fps instead
    26.  
    27.         // Sync framerate to monitors refresh rate
    28.         //Use 'Don't Sync' (0) to not wait for VSync. Value must be 0, 1, 2, 3, or 4
    29.         QualitySettings.vSyncCount = 0;
    30.  
    31.         // Disable screen dimming
    32.         Screen.sleepTimeout = SleepTimeout.NeverSleep;
    33.  
    34.         //Inicialize(true); //use for testing on editor
    35.     }
    36.  
    37.     private IEnumerator FPS()
    38.     {
    39.         int lastFrameCount;
    40.         float lastTime;
    41.         float timeSpan;
    42.         int frameCount;
    43.         for (; ; )
    44.         {
    45.             // Capture frame-per-second
    46.             lastFrameCount = Time.frameCount;
    47.             lastTime = Time.realtimeSinceStartup;
    48.             yield return waitForFrequency;
    49.             timeSpan = Time.realtimeSinceStartup - lastTime;
    50.             frameCount = Time.frameCount - lastFrameCount;
    51.  
    52.             fps = string.Format("FPS: {0}", Mathf.RoundToInt(frameCount / timeSpan));
    53.         }
    54.     }
    55.  
    56.  
    57.     void OnGUI()
    58.     {
    59.         // Display
    60.         GUI.Label(rect, fps, style);
    61.         //GUI.Label(new Rect(Screen.width - 110, 5, 0, Screen.height * 2 / 100), fps, style);
    62.  
    63.         //GUI.Label(new Rect(10, 10, Screen.width, Screen.height * 2 / 100), fps, style);
    64.         //GUI.Label(new Rect(Screen.width - 100, 10, 150, 20), fps, style);
    65.     }
    66.  
    67.     private void Inicialize(bool showFps)
    68.     {
    69.         isInicialized = true;
    70.  
    71.         style.alignment = TextAnchor.UpperLeft;
    72.         style.fontSize = Screen.height * 3 / 100;
    73.         style.normal.textColor = new Color32(0, 200, 0, 255);
    74.         rect = new Rect(Screen.width * 90 / 100, 5, 0, Screen.height * 2 / 100);
    75.  
    76.         if(showFps)
    77.             StartCoroutine(FPS());
    78.     }
    79.  
    80.  
    81.     public void SetNewConfig(GraphicSettingsMB gSettings)
    82.     {
    83.         Application.targetFrameRate = gSettings.targetFrameRate;
    84.  
    85.         waitForFrequency = new WaitForSecondsRealtime(gSettings.testFpsFrequency);
    86.  
    87.         if (!isInicialized) Inicialize(gSettings.showFps);
    88.  
    89.         if (!gSettings.showFps)
    90.             Destroy(this.gameObject);
    91.     }
    92. }
    93.  
    94. [SerializeField]
    95. public class GraphicSettingsMB
    96. {
    97.     public byte targetFrameRate = 30;
    98.     public byte testFpsFrequency = 1;
    99.     public bool showFps = false;
    100. }
     
  18. Kartik_R

    Kartik_R

    Joined:
    Mar 25, 2023
    Posts:
    1
    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;
    }
    }
     
  19. Sarrus4x4

    Sarrus4x4

    Joined:
    May 8, 2023
    Posts:
    1
    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?
     
    lyingturkey likes this.
  20. lyingturkey

    lyingturkey

    Joined:
    Sep 15, 2021
    Posts:
    2
    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 :) ( 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)" )

    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using TMPro;
    7.  
    8. public class FPSCounter : MonoBehaviour
    9. {
    10.     private TextMeshProUGUI Text;
    11.     public TextMeshProUGUI FPS_Text;
    12.  
    13.     private Dictionary<int, string> CachedNumberStrings = new();
    14.     private int[] _frameRateSamples;
    15.     private int _cacheNumbersAmount = 300;
    16.     private int _averageFromAmount = 30;
    17.     private int _averageCounter = 0;
    18.     private int _currentAveraged;
    19.  
    20.     void Awake()
    21.     {
    22.         // Cache strings and create array
    23.         {
    24.             for (int i = 0; i < _cacheNumbersAmount; i++)
    25.             {
    26.                 CachedNumberStrings[i] = i.ToString();
    27.             }
    28.             _frameRateSamples = new int[_averageFromAmount];
    29.         }
    30.     }
    31.     void Update()
    32.     {
    33.         // Sample
    34.         {
    35.             var currentFrame = (int)Math.Round(1f / Time.smoothDeltaTime); // If your game modifies Time.timeScale, use unscaledDeltaTime and smooth manually (or not).
    36.             _frameRateSamples[_averageCounter] = currentFrame;
    37.         }
    38.  
    39.         // Average
    40.         {
    41.             var average = 0f;
    42.  
    43.             foreach (var frameRate in _frameRateSamples)
    44.             {
    45.                 average += frameRate;
    46.             }
    47.  
    48.             _currentAveraged = (int)Math.Round(average / _averageFromAmount);
    49.             _averageCounter = (_averageCounter + 1) % _averageFromAmount;
    50.         }
    51.  
    52.         // Assign to Private Text value
    53.         {
    54.             Text.text = _currentAveraged < _cacheNumbersAmount && _currentAveraged > 0
    55.                 ? CachedNumberStrings[_currentAveraged]
    56.                 : _currentAveraged < 0
    57.                     ? "< 0"
    58.                     : _currentAveraged > _cacheNumbersAmount
    59.                         ? $"> {_cacheNumbersAmount}"
    60.                         : "-1";
    61.         }
    62.         // Assign to UI with additional text indicator
    63.         {
    64.             FPS_Text.text = "FPS: " + Text.text;
    65.         }
    66.  
    67.     }
    68. }
    69. }
     
    Last edited: Jun 6, 2023
  21. GXMark

    GXMark

    Joined:
    Oct 13, 2012
    Posts:
    514
    This is my version which takes an average over 60 frames
    Code (CSharp):
    1.     public class FPSDisplay : MonoBehaviour
    2.     {
    3.         public TextMeshProUGUI fpsText;
    4.  
    5.         private int _frameCount;
    6.         private int _totalFPS;
    7.      
    8.         void Update()
    9.         {
    10.             _frameCount++;
    11.  
    12.             _totalFPS += (int)Math.Round(1f / Time.unscaledDeltaTime);
    13.  
    14.             if (_frameCount % 60 == 0)
    15.             {
    16.                 fpsText.text = "FPS : " + _totalFPS / _frameCount;
    17.                 _totalFPS = 0;
    18.                 _frameCount = 0;
    19.             }
    20.         }
    21.     }
     
  22. WilliamLeu

    WilliamLeu

    Joined:
    Jul 27, 2012
    Posts:
    19
    I'll throw my method in here, too. It captures the frame duration every frame but smoothes the result with recent frames having a higher weighting.

    Code (CSharp):
    1. public class FPSExample : MonoBehaviour
    2. {
    3.     // The decay needs to be above 1.0.
    4.     // The larger this value is, the faster the influence from the past will decay.
    5.     const float decayVal = 1.5f;
    6.  
    7.     float accumWt = 0.0f;
    8.     float accum = 0.0f;
    9.  
    10.     void OnGUI()
    11.     {
    12.         float wtAvgDT = accum/accumWt;
    13.         GUILayout.Label((1.0f/ wtAvgDT).ToString());
    14.     }
    15.  
    16.     private void Update()
    17.     {
    18.         // Decay the accumulations.
    19.         // The ratio of this.accum/this.accumWt doesn't change from this - but the
    20.         // values are now smaller compared to the new values we're going to add
    21.         // in - and thus have a smaller weighting.
    22.         this.accum /= decayVal;
    23.         this.accumWt /= decayVal;
    24.  
    25.         this.accum += Time.unscaledDeltaTime;
    26.         this.accumWt += 1.0f;
    27.     }
    28. }
    @Kartik_R You should probably subtract 1 from timer instead of setting it to zero, or else you're throwing away fractions of a second.
     
  23. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    1,002
    For the minimalists with good eyesight:

    Code (CSharp):
    1.     void OnGUI()
    2.     {
    3.         GUI.Label(new Rect(10, 10, 100, 20), (1/Time.smoothDeltaTime).ToString("f0"));
    4.     }