Measuring FPS
In the previous entry we have created a game loop that runs at a constant speed and constant (more or less) FPS.
How can we measure it? Check the new MainThread.java class.
package net.obviam.droidz;
import java.text.DecimalFormat;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
/**
* @author impaler
*
* The Main thread which contains the game loop. The thread must have access to
* the surface view and holder to trigger events every game tick.
*/
public class MainThread extends Thread {
private static final String TAG = MainThread.class.getSimpleName();
// desired fps
private final static int MAX_FPS = 50;
// maximum number of frames to be skipped
private final static int MAX_FRAME_SKIPS = 5;
// the frame period
private final static int FRAME_PERIOD = 1000 / MAX_FPS;
// Stuff for stats */
private DecimalFormat df = new DecimalFormat("0.##"); // 2 dp
// we'll be reading the stats every second
private final static int STAT_INTERVAL = 1000; //ms
// the average will be calculated by storing
// the last n FPSs
private final static int FPS_HISTORY_NR = 10;
// last time the status was stored
private long lastStatusStore = 0;
// the status time counter
private long statusIntervalTimer = 0l;
// number of frames skipped since the game started
private long totalFramesSkipped = 0l;
// number of frames skipped in a store cycle (1 sec)
private long framesSkippedPerStatCycle = 0l;
// number of rendered frames in an interval
private int frameCountPerStatCycle = 0;
private long totalFrameCount = 0l;
// the last FPS values
private double fpsStore[];
// the number of times the stat has been read
private long statsCount = 0;
// the average FPS since the game started
private double averageFps = 0.0;
// Surface holder that can access the physical surface
private SurfaceHolder surfaceHolder;
// The actual view that handles inputs
// and draws to the surface
private MainGamePanel gamePanel;
// flag to hold game state
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
@Override
public void run() {
Canvas canvas;
Log.d(TAG, "Starting game loop");
// initialise timing elements for stat gathering
initTimingElements();
long beginTime; // the time when the cycle begun
long timeDiff; // the time it took for the cycle to execute
int sleepTime; // ms to sleep (<0 if we're behind)
int framesSkipped; // number of frames being skipped
sleepTime = 0;
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
beginTime = System.currentTimeMillis();
framesSkipped = 0; // resetting the frames skipped
// update game state
this.gamePanel.update();
// render state to the screen
// draws the canvas on the panel
this.gamePanel.render(canvas);
// calculate how long did the cycle take
timeDiff = System.currentTimeMillis() - beginTime;
// calculate sleep time
sleepTime = (int)(FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
// if sleepTime > 0 we're OK
try {
// send the thread to sleep for a short period
// very useful for battery saving
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// we need to catch up
this.gamePanel.update(); // update without rendering
sleepTime += FRAME_PERIOD; // add frame period to check if in next frame
framesSkipped++;
}
if (framesSkipped > 0) {
Log.d(TAG, "Skipped:" + framesSkipped);
}
// for statistics
framesSkippedPerStatCycle += framesSkipped;
// calling the routine to store the gathered statistics
storeStats();
}
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
/**
* The statistics - it is called every cycle, it checks if time since last
* store is greater than the statistics gathering period (1 sec) and if so
* it calculates the FPS for the last period and stores it.
*
* It tracks the number of frames per period. The number of frames since
* the start of the period are summed up and the calculation takes part
* only if the next period and the frame count is reset to 0.
*/
private void storeStats() {
frameCountPerStatCycle++;
totalFrameCount++;
// check the actual time
statusIntervalTimer += (System.currentTimeMillis() - statusIntervalTimer);
if (statusIntervalTimer >= lastStatusStore + STAT_INTERVAL) {
// calculate the actual frames pers status check interval
double actualFps = (double)(frameCountPerStatCycle / (STAT_INTERVAL / 1000));
//stores the latest fps in the array
fpsStore[(int) statsCount % FPS_HISTORY_NR] = actualFps;
// increase the number of times statistics was calculated
statsCount++;
double totalFps = 0.0;
// sum up the stored fps values
for (int i = 0; i < FPS_HISTORY_NR; i++) {
totalFps += fpsStore[i];
}
// obtain the average
if (statsCount < FPS_HISTORY_NR) {
// in case of the first 10 triggers
averageFps = totalFps / statsCount;
} else {
averageFps = totalFps / FPS_HISTORY_NR;
}
// saving the number of total frames skipped
totalFramesSkipped += framesSkippedPerStatCycle;
// resetting the counters after a status record (1 sec)
framesSkippedPerStatCycle = 0;
statusIntervalTimer = 0;
frameCountPerStatCycle = 0;
statusIntervalTimer = System.currentTimeMillis();
lastStatusStore = statusIntervalTimer;
// Log.d(TAG, "Average FPS:" + df.format(averageFps));
gamePanel.setAvgFps("FPS: " + df.format(averageFps));
}
}
private void initTimingElements() {
// initialise timing elements
fpsStore = new double[FPS_HISTORY_NR];
for (int i = 0; i < FPS_HISTORY_NR; i++) {
fpsStore[i] = 0.0;
}
Log.d(TAG + ".initTimingElements()", "Timing elements for stats initialised");
}
}
I introduced a simple measuring function. I count the number of frames every second and store them in the fpsStore[] array. The storeStats() is called every tick and if the 1 second interval (STAT_INTERVAL = 1000;) is not reached then it simply adds the number of frames to the existing count.
If the one second is hit then it takes the number of rendered frames and adds them to the array of FPSs. After this I just reset the counters for the current statistics cycle and add the results to a global counter. The average is calculated on the values stored in the last 10 seconds.
Line 171 logs the FPS every second while line 172 sets the avgFps value of the gamePanel instance to be displayed on the screen.
The MainGamePanel.java class’s render method contains the the displayFps call which just draws the text onto the top right corner of the display every time the state is rendered. It also has a private member that is set from the thread.
// the fps to be displayed
private String avgFps;
public void setAvgFps(String avgFps) {
this.avgFps = avgFps;
}
public void render(Canvas canvas) {
canvas.drawColor(Color.BLACK);
droid.draw(canvas);
// display fps
displayFps(canvas, avgFps);
}
private void displayFps(Canvas canvas, String fps) {
if (canvas != null && fps != null) {
Paint paint = new Paint();
paint.setARGB(255, 255, 255, 255);
canvas.drawText(fps, this.getWidth() - 50, 20, paint);
}
}
Try running it. You should have the FPS displayed in the top right corner.

Hi!
Can this be applied for video also, with VideoView?
It seems to me that you’re calling storeStats() every update, even when the frame was skipped. Shouldn’t skipped frames be excluded from the FPS calculation? Please correct me if I’m wrong.
thanks for your sharing.
when I import your project to eclipse, there are some compiling errors.
‘Syntax error on tokens, delete these tokens, _Speed, _Droid’
there is a under-line for every class
at last I delete the src folder & re-make them again, and everything works
Hi there! Thanks for the cool tutorial. I’m currently stuck on a modification to this game. I wanted to have a pause screen. I added an alert dialog which pops up when you press in a specific location in the onTouchEvent(), but I’m not sure how to handle effectively pausing and unpausing, or restarting the game.
Can anyone offer some insight?
Last paragraph of above article is confusing for me. Last Paragraph says:
“Because we are setting our desired FPS to 50 that means that the speed will increase by 50*speed.value every update. To have the speed of let’s say 40 pixels/second you will need to set the speed delta for every tick to 2 (40 / (1000 / 50) = 2). In other words you need the droid to advance 2 pixels every game update (when you have 50 game updates per second) to cover 40 pixels per second.”
My Doubts
1) “If desired FPS is 50, speed will increase by 50*speed.value every update” ??
Speed of droid should be constant
2) “droid to advance 2 pixels every game update (when you have 50 game updates per second) to cover 40 pixels per second” ??
If it travels 2 pixels every update and in total 50 updates happen in a second, then it will travel 2*50=100 pixels and not 40 pixels ??
Please help me understand this.
Got the downloaded code working OK.
However, what part of the code sets the droid in motion and sets its initial direction, etc?
Thanks so much for the tutorials.
I am just getting into Android programming and found that if I use your code I am only getting around 10 FPS where as on you pic it seems like you are up at 50 FPS.
I am using the Android 2.2 – API Level 8 emulator from the SDK.
Any suggestions?
Thanks in advance.
Is this line redundant?
statusIntervalTimer += (System.currentTimeMillis() – statusIntervalTimer);
I got a concurrency issue, probably caused by this code. When the code calls sleep, it’s still in the synchronized block. This means that any other thread trying to access a variable guarded by the same lock, will be put on hold. This caused an Application Not Responding in my main thread. My advice is to move the sleep code outside of the lock.
Anyhow, nice tutorial, mate!
Thanks for the comment Ben.
Looking back what I did when I was starting, I would change a lot of things.
I appreciate your comment and hopefully I will find the time to revisit the posts and optimize them based on all the good comments and learnt lessons.
Cheers,
I
i have galaxy s ii, am getting 39 FPS, is this normal ?
note: the downloaded project from this post is not working, i copied the code and modified project from previous post
Hi Impaler,
This site is great! Going through this site was fun.
I think you’ve got a mistake in the FPS calculation. the numbers just seems to good to be true, in 50, 100, 1000, 2000 MAX_FPS, they are always accurate.
i think you’ve got a double dependency on the stats average that causes the stats to be so clean.
in the storeStats() method, I’ve changed the code to
long time = System.currentTimeMillis();
// assuming that the sleep works each call to storeStats
// happens at 1000/FPS so we just add it up
statusIntervalTimer += (time – lastTime); //MainThread.FRAME_PERIOD;
instead of getting the time from the constant, i took it from the difference of last stats update from the system
this gives completely different results.
not only that, but at 1000fps, the stats don’t come out at 1sec intervals. since the 10ms time for the thread isn’t enough and is fake.
Thanks,
Koren
Thanks Koren, you are absolutely right. I will modify the code.
Nice tutorial, I modified your code a little to see if I could get it to run in my game so I could see the fps. I am using landscape mode and when I take out the collision effects it gives me a error in the displayFPS method. When I try to give the drawText actual coords it will not show up. Do you know how I could fix this to where the FPS shows.
Could you give more info? What is the error? What exactly did you change?
It might help to get an idea what is going wrong….
Cheers
I fixed it, I changed the .setRGB to setColor because when I tried to change the color using RGB values it didn’t work for some reason but it shows just fine now.
See the last tutorial, some refactoring and renaming was done. Also make sure you update the name of your onDraw() method to render().
where do u define the update method i cant get my program to compile because i cant find it
Great information here. Just curious about the following line. Am I missing something, or is this redundant?
statusIntervalTimer += (System.currentTimeMillis() – statusIntervalTimer);
@impaler
hey. i tried modifying your code to create another fixed droid and wanted to display a toast whenever a collision occurs between the 2.
but i’m not able to implement the toast thing. i tried using Handler but i think i’m doing it wrong.
cud u help me out in this part?
the 2nd droid is created at position (100,100)
so i used an if..else construct in the update() method.
if((droid.getX()>=77&&droid.getX()77&&droid.getY()<123))
{
//code to display toast
}
if((droid.getX()>=77&&droid.getX()77&&droid.getY()<123))
@impaler
great tutorial dude….
but i’m still facing a problem getting it to run. i downloaded the code and there’s no errors but when the app fires up, it crashes saying it has stopped unexpectedly and force closes.
please help me out.
Have you checked what’s in the logs?
You can use LogCat to get some information.
Please give some more data so we can help you. (Window -> Show View -> LogCat)
Found the error in the LogCat. there was some mismatch in the filename….
code runs perfectly.
brilliant job. i’m kinda new to Android programming and this helped me out a lot.
\m/
@impaler
great tutorial dude….
but i’m still facing a problem running this app on my emulator(Android 2.1-update 1).
there’s no error but when the app fires up, a dialog box appears telling the app has stopped unexpectedly and force closes.
pls help me out.
Thanks for the update. I will give it a go here in a few min.
I seem to be having a problem here. The “averageFPS” does not change… its always the same value as “MAX_FPS”.
I changed MAX_FPS to 500 and averageFPS returns 500. I really doubt my phone can do 500FPS.
Any idea?
Thanks for notifying me about it.
It seems to be a problem with the statistics gathering tick. I will revisit the code and do an update as soon as I get the time.
Thanks. I’m trying to figure it out but a little bit over my head… if i figure it out i will report back. Until then i await a fix
I have uploaded a fixed version.
The storeStats() method was called with a delay in case of a lag but the statusIntervalTimer was still incremented with the normal FRAME_PERIOD.
What needed to happen is keep the last statusStore in a variable (I have added lastStatusStore) and let the statusIntervalTimer be incremented by the number of milliseconds elapsed since the last statusStore and once the status tick is achieved (one second) the actual FPS is added to the average array and the average is being calculated.
Check the new MainThread and compare it with the old one.
Thanks for the heads up.
Where is updated code showing correct fps? When I download the above code it was not updated. I am finding difficulty to display correct fps as per above solution, please help me..
Hey sorry! Above code is updated and works fine,I was wrong..
Great Articles… keep them up.