Jump to content
  • Advertisement
Sign in to follow this  
Cydriic

Is there a way for me to see my game`s performance or frame rate?

This topic is 1511 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi Everyone,

 

I ran into a performance issue last time when I had to work on my game from my laptop (which is a little bit less powerful then my desktop computer). I immediately noticed that my game was slower then on the other computer.

 

I got me to work on my collision system to make it a uniform grid collision system instead of going through all my vectors constantly like a total noob.

 

But now that this has been implemented, it got me interested in knowing about my frame rate better.

 

Is there a way to actually know about my frame rate? Is there an application that I can run at the same time as my game and tell me at what frame rate i`m running?

 

 

Thanks!

 

Share this post


Link to post
Share on other sites
Advertisement

In any serious project, I build a performance measurement system into the game. I categorize sections of the draw and update loops and can pop up a display in game that shows how long each section took, or any spikes that took place recently.

 

From there, I can get a better idea of what to look at: if I need to use a CPU profiler to get more info about a section of game code, or if I should use a GPU profiler (e.g. Intel GPA) to see what's up.

Share this post


Link to post
Share on other sites

I always write the same FPS counting code into any engine where I'm doing graphics and want it to be as responsive as possible. Some engines calculate the framerate from the frametime (framerate = 1000 / frametime_in_milliseconds, or framerate = 1 / frametime_in_seconds). This is cool but I don't like the flickering framerate as numbers change every single frame. I like a steady display, so usually I have a little function at the end of all my rendering that literally counts the frames until a whole second has passed. Every second I copy the counter to a FPS variable and reset the counter to zero and wait for another second to pass by. This literally counts the frames per second, and produces a steady value output on the screen that changes every second.

 

To speed up responsiveness I have also used smaller times, a half a second, a third, etc... and multiplied the counted frames. You could also use the frametime method but smooth it out.

 

Having some sort of output for your framerate makes it very easy to see what's lagging your game the hardest without having to run any analysis software. I am a stickler for responsiveness in games (as a player who cringes at the feel of 100 fps) and aim to keep things as smooth as possible.

Share this post


Link to post
Share on other sites

I wrote up a quick class to measure performance and draw a real time graph of it. Here is that complete class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

using EricsLib.MathLib;
using EricsLib.ContentDatabases;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace EricsLib
{
    /// <summary>
    /// This class is used for measuring the performance of various parts of your game.
    /// It contains a few handy high performance timers for measuring how long something takes.
    /// </summary>
    public class PerfMonitor
    {
        /*Usage: Create a new performance monitor, give it a name, and then start and stop it to capture performance metrics on a section of code.
         Display: Call the "DrawGraph" method with a rectangle to draw within.*/
        Stopwatch m_timer0;
        string m_name = "";

        //Keep a history of each performance counter:
        Queue<double> m_TimerHist;

        Range m_TimerRange;

        const int m_historySize = 300;
        const int m_targetFPS = 60;

        const float m_green = 1000f / m_targetFPS;
        const float m_yellow = 1000f / (m_targetFPS - 10);

        int m_drawMode = 1;


        public PerfMonitor(string name)
        {
            m_name = name;
            m_timer0 = new Stopwatch();
            m_TimerHist = new Queue<double>(m_historySize);
            m_TimerRange = new Range(0, 0);
        }

        /// <summary>
        /// Starts a stopwatch
        /// </summary>
        public void Start()
        {
            m_timer0.Reset();
            m_timer0.Start();
        }

        /// <summary>
        /// Stops the stopwatch and records the duration into a history queue.
        /// If you need the duration of the last cycle, use the Time accessor.
        /// </summary>
        public void Stop()
        {
            while (m_TimerHist.Count > m_historySize) m_TimerHist.Dequeue();

            m_TimerHist.Enqueue(m_timer0.Elapsed.TotalMilliseconds);

            if (m_timer0.Elapsed.TotalMilliseconds > m_TimerRange.Max)
                m_TimerRange.Max = (float)m_timer0.Elapsed.TotalMilliseconds;

            
            m_TimerRange.Current = (float)m_timer0.Elapsed.TotalMilliseconds;

            m_timer0.Stop();
        }



        public TimeSpan Time
        {
            get { return m_timer0.Elapsed; }
        }

        /// <summary>
        /// Draws a bar graph indicating performance over time. This is good for performance which changes over time.
        /// </summary>
        /// <param name="region"></param>
        public void DrawGraph(Rectangle region)
        {
            if (m_TimerHist.Count > 0)
            {
                BaseSettings.DrawString(m_name + " FPS: " + (int)(1000f / m_TimerRange.Current), new Vector2(region.X, region.Y), Color.White); //15px height
                int y = region.Y + 15;
                //Draw a bunch of line graphs for each monitor


                //draw a white background
                BaseSettings.SpriteBatch.Draw(BaseSettings.Solid, new Rectangle(region.X, y, region.Width, region.Height), Color.White);

                //draw bar graphs
                float graphX = region.X;
                float width = region.Width / m_historySize;
                int graphY = y + region.Height;
                Color c = Color.Green;
                foreach (double val in m_TimerHist)
                {
                    float proportion = (float)val / m_TimerRange.Max;
                    //(proportion * region.Height)
                    if (val > m_green) c = Color.Yellow;
                    if (val > m_yellow) c = Color.Red;
                    BaseSettings.DrawLine(new Vector2(graphX, graphY), new Vector2(graphX, graphY - (proportion * region.Height)), c, (int)width);
                    graphX += width;
                }
            }
        }

        /// <summary>
        /// Writes some stats to the screen. This is good for monitors which ran once and will never update again.
        /// </summary>
        /// <param name="pos"></param>
        public void DrawStatus(Vector2 pos)
        {
            string status = m_name + " FPS: " + (int)(1000f / m_TimerHist.Peek());
            status += "\nMax: " + m_TimerRange.Max;
            status += "\nCurrent: " + m_TimerRange.Current;
            BaseSettings.DrawString(status, pos, Color.White); //15px height
        }

        /// <summary>
        /// You can give the group of performance timers a friendly name
        /// </summary>
        public string Name
        {
            get { return m_name; }
            set { m_name = value; }
        }

        /// <summary>
        /// 0 - No draw
        /// 1 - Draw graph
        /// 2 - Draw Status
        /// </summary>
        public int DrawMode
        {
            set { m_drawMode = value; }
            get { return m_drawMode; }
        }
        

        public override string ToString()
        {
            return "Timer " + m_name;
        }

    }
}

It's pretty easy to use:

 

public void GameInit()
{
PerfMonitor loadPerf = new PerfMonitor("Loading Time");

loadPerf.Start();

///game loading/init code....

loadPerf.Stop();
}

public void GameUpdate()
{
   BaseSettings.GetPerfMonitor("CPU_Load").Start();   //<-- accessed as a global object

   //game update code...

   BaseSettings.GetPerfMonitor("CPU_Load").Stop();

}


//Draw Code:
public override void Draw(GameTime gameTime)
{
            BaseSettings.GetPerfMonitor("GPU_Load").Start();


            foreach (KeyValuePair<int, Player> kvp in m_allPlayers)
            {
                kvp.Value.Draw(m_worldTime);
            }

            base.Draw(gameTime);
            BaseSettings.GetPerfMonitor("GPU_Load").Stop();

            if (m_showPerf)
            {
                BaseSettings.DrawMonitors();
            }
}

I can pretty much create a performance monitor for anything and use it as a stop watch to measure how long a particular code block takes, and I can measure that performance of that code block over time with a quick and dirty bar graph.

Share this post


Link to post
Share on other sites
I store the last N frames FPS in a circular buffer and display the average. This smooths it a bit. Though N should be lower for low FPS or it smooths too much... but for the 'normal' ranges its good enough.

Share this post


Link to post
Share on other sites


Some engines calculate the framerate from the frametime (framerate = 1000 / frametime_in_milliseconds, or framerate = 1 / frametime_in_seconds). This is cool but I don't like the flickering framerate as numbers change every single frame.

 

I love a one-second interval update showing three values with actual time spent:  min / avg / max

 

For example, you might have these microseconds:    8413 us / 9341 us / 9642 us

 

Seeing a spread of times gives a lot more insight.  For some made up illustrative examples:

 

8413 us / 9341 us / 9642 us  <-- Comfortably 100 frames per second, very consistent times each frame.

1534 us / 9458 us / 27314 us <-- Roughly 100 frames per second, but erratic timing with occasionally very slow frames.

0 us / 16000 us / 875345 us   <-- Exactly 60 frames per second, but still a slideshow since 59 frames are instant and one frame is a full second. Fire everyone.

 

Giving both the min and max let you see much more than just the average. They help identify bottlenecks and dropped frames that may not be as obvious with just an average alone.

Share this post


Link to post
Share on other sites

In any serious project, I build a performance measurement system into the game. I categorize sections of the draw and update loops and can pop up a display in game that shows how long each section took, or any spikes that took place recently.

 

From there, I can get a better idea of what to look at: if I need to use a CPU profiler to get more info about a section of game code, or if I should use a GPU profiler (e.g. Intel GPA) to see what's up.

 

Just curious, why implement it when there's already great software that does that? RenderDoc for GPU, Visual studio for CPU, I can't see how rolling your own can be better in any scenario with such advanced tools available?

Share this post


Link to post
Share on other sites

Just curious, why implement it when there's already great software that does that? RenderDoc for GPU, Visual studio for CPU, I can't see how rolling your own can be better in any scenario with such advanced tools available?

These tools, while great, have some level of inaccuracy. i.e. the CPU profilers use "sampling based profiling" which is basically statistical collection of where the program spends most of the time.
Statistics are averages and have standard error. Furthermore these tools don't work outside the dev. environment (i.e. the tool is not available to the user i.e. VTune costs money, the PDBs need to tag along, etc). Not to mention these tools may have trouble hooking up to your app if you do something weird (DRM, some problematic device driver, program is running behind a virtual machine, etc).

It also doesn't tell you how long it takes a specific component unless it's statistically relevant, which is important when you're trying to build a frame budget.

Another reason is that not all platforms can use these tools; and while it's great to have them on PC, it's not so great when you have to deal with other devices where these profilers either don't exist or have poor support.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!