# Accurately measure time between calls to onDrawFrame (Android OpelGL ES 2.0)

I'm trying to sort out some timing issues within my gameloop and I've seen something that I don't understand.

The Nexus 10 is supposed to have (as far as I'm aware) a VSync on 60Hz. So that would be mean would it not that onDrawFrame is called by the system every 16.66ms?

When I try to measure it I get different readings on every iteration like so:

public void onDrawFrame(GL10 gl) {

Log.v("NewTag","Millis between this call and last: "+((System.nanoTime()-newTime)/1000000));

newTime = System.nanoTime();
}


See my results:

As you can see, it varies between 11.53ms and 21.85ms

Why is it not a constant 16.66 or is it just that nanoTime isn't acurate enough to give a more exact reading?

• How about doing your sampling over a longer period of time than a single frame. Cause the printing takes time too. I count frames and report the average time per frame every 5 seconds. If you want me to do an official answer with pseudocode let me know. – badweasel Jan 29 '15 at 4:25
• Not to mention that System.nanoTime() is probably going to be different the two times you're using it here. Be consistent and record time at the start of each frame.. timeThisRound, and timeLastRound. – badweasel Jan 29 '15 at 4:27

First, as Matthew said it's not going to be exact because of fill rates and whether the onDrawFrame' is called before or after you do your drawing.

But this would by my approach. First, I'd average over several seconds. Remember that just printing to the log takes time. You don't need to know the FPS every frame, just the average every few seconds. Second, I would only capture the time once, not multiple times. Use that captured time for everything that needs a time base.

I would do something like this:

public void onDrawFrame(GL10 gl) {
timeThisRound = System.nanoTime()/1000000.0f;  // only capture the time once in seconds
deltaTimeThisRound = timeThisRound-timeLastRound;  // to use for certain calculations
fpm++;
if(timeThisRound > lastMin + 5.0f)
{
lastMin=timeThisRound;
Log.v("NewTag","fps: " + fpm/5.0f));
fpm=0;
}
timeLastRound = timeThisRound;
}


You can change the 5.0f in both places to be whatever amount of time you want to check. Just make sure you change it in both places.

If you want to print out the average time per frame instead just swap the formula to be 5.0f/fpm`. fps is frames/time. time for one frame is time/frames.

Video frame flip times are very consistent. However, this is no guarantee that onDrawFrame is being called precisely the instant after a video flip. As you've measured, it is not particularly timely. If the system is not heavily strained, you can get an accurate measurement of the frame rate by averaging the values above. If the system is heavily strained, however you will start getting dropped frames in which the computer does not have enough time to fill the image buffer before the flip. In this case, you will start seeing multiples of 16.67 (plus random error) in your measurements. Even though the hardware frame rate is 60 Hz, there will be less than 60 frames displayed each second.