Subscribe

RSS Feed (xml)

Powered By

Powered by Blogger

Google
 
xnahelp.blogspot.com

Kamis, 03 April 2008

Creating a Benchmark

To get a baseline for our game loop we will start with a new Windows game project. We
can call this project PerformanceBenchmark. We will add a frame rate counter and
update our window title to show just how many frames per second we are getting “out
of the box.”
Now we can set the following properties inside of the constructor:
//Do not synch our Draw method with the Vertical Retrace of our monitor
graphics.SynchronizeWithVerticalRetrace = false;
//Call our Update method at the default rate of 1/60 of a second.
IsFixedTimeStep = true;
The template creates the GraphicsDeviceManager for us. We set the
SynchronizeWithVerticalRetrace property of the manager to false. The default of this
property is true. As the name suggests, this property synchronizes the call to the Draw
method from inside of the XNA Framework’s game loop to coincide with the monitor’s
refresh rate. If the monitor has a refresh rate of 60 Hz, it refreshes every 1/60 seconds or
60 times every second. By default XNA draws to the screen at the same time the monitor
refreshes to keep the scene from appearing jerky. This is typically what we want. However,
Measure, Measure, Measure 37
3
when measuring the change a piece of code has on our frame rate it is difficult to determine
how we are affecting it if we are always drawing 60 fps. We would not know
anything was wrong until we did something that dropped us below that margin keeping
XNA from calling the Draw method fast enough.
We also set the fixed time step property (IsFixedTimeStep) to true. This is the default
value of this property. This property lets XNA know if it should call the Update method
immediately after drawing to the screen (false) or only after a fixed amount of time has
passed (true). This fixed amount of time is 1/60 second and is stored in the property
TargetElapsedTime, which we can change. At this point we do not need the framework
to call Update as often as possible. For this application it does not really matter because
we are not doing anything inside of our Update method.
Let’s add the following private member fields to our Game1.cs file:
private float fps;
private float updateInterval = 1.0f;
private float timeSinceLastUpdate = 0.0f;
private float framecount = 0;
Finally, let’s add the frame rate calculation inside of our Draw method.
float elapsed = (float)gameTime.ElapsedRealTime.TotalSeconds;
framecount++;
timeSinceLastUpdate += elapsed;
if (timeSinceLastUpdate > updateInterval)
{
fps = framecount / timeSinceLastUpdate; //mean fps over updateIntrval
Window.Title = “FPS: “ + fps.ToString() + “ - RT: “ +
gameTime.ElapsedRealTime.TotalSeconds.ToString() + “ - GT: “ +
gameTime.ElapsedGameTime.TotalSeconds.ToString();
framecount = 0;
timeSinceLastUpdate -= updateInterval;
}
The first thing we are doing with the code is storing the elapsed time since the last time
the Draw method was executed. We then increment our frame count along with the variable
that is keeping a running total of the time. We check to see if enough time has passed,
at which point we update our frame rate. We have the updateInterval set at 1 second, but
we can tweak that number if we would like. Once enough time has passed for us to recalculate
our frame rate, we do just that by taking the number of frames and dividing it by
the time it took us to get inside of this condition. We then update the title of the window
with our fps. We also write out the ElapsedRealTime along with the ElapsedGameTime. To
calculate our fps we used the real time. Play with the first two properties we set to see the
effect it has on the time. Remember the SynchronizeWithVerticalRetrace property determines
how often the Draw method gets called and the IsFixedTimeStep property determines
how often the Update method gets called. We can see that the ElapsedRealTime is
associated to the time it took to call our Draw method while the ElapsedGameTime is associated
with the time it took to call our Update method.
CHAPTER 3 38 Performance Considerations
Finally, we reset our frame count along with the timeSinceLastUpdate variable. Let’s run
the application so we can get our baseline for how our machine is performing.
Now that we have our base number we want to make a note of it. This could be done in
an Excel spreadsheet where we can easily track the changes in our performance. We
should always try to run our performance tests under the same conditions. Ideally,
nothing except the game should be run during all of the benchmark testing.
As an example, let’s add the following code inside of the Draw method:
//bad code that shoud not be replicated
Matrix m = Matrix.Identity;
Vector3 v2;
for (int i = 0; i < 1; i++)
{
m = Matrix.CreateRotationX(MathHelper.PiOver4);
m *= Matrix.CreateTranslation(new Vector3(5.0f));
Vector3 v = m.Translation - Vector3.One;
v2 = v + Vector3.One;
}
It does not do anything other than some 3D math that has absolutely no purpose. The
reason we are going through this exercise is to see how our frame rate will drop as we
increment the upper limit of our for loop. The point is that when we start writing real
functionality inside of the Draw method we can measure how our frame rate is handling
the addition of code. On the included CD, this example is called PerformanceTest1.

0 komentar: