Friday, 15 May 2009

The trouble with timers

On the iPhone it seems to have become commonplace to use a NSTimer to trigger redraws on OpenGL ES applications when displaying a changing or animated scene. To run smoothly, a frame rate of 30fps or higher is generally aimed for (60fps being the maximum, limited by the iPhone hardware refresh).

Relying on a timer to fire the code that renders the frame has its pros and its cons. The pros are simplicity and having everything in the same thread of execution (or runloop) means not having to worry about concurrency issues. The cons are what I'm more interested in..

The NSTimer class reference states: A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed. Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds. If a timer’s firing time occurs while the run loop is in a mode that is not monitoring the timer or during a long callout, the timer does not fire until the next time the run loop checks the timer." Therefore, the actual time at which the timer fires potentially can be a significant period of time after the scheduled firing time.

The low resolution and the fact that a timer can misfire (skip frames) are the most worrying for me.

A frame rate of 60fps means a timer period of 1/60 = 0.016667 seconds (or 16.667ms). What this means is that the frame needs to be rendered well within 16.667ms or the timer will misfire. Flipping buffers when rendering an OpenGL frame can block, depending on the hardware refresh sync, making the likelihood of an overrun (and subsequent misfire) even higher.

What typically happens is the timer fires every 16.667 ms or so (depending on what else the run loop is up to), but for frames whose drawing code has not completed by the next time the timer is meant to fire, the subsequent frame is effectively skipped.


A misfire results in the time between two ticks suddenly being twice the expected period (or possibly a higher multiple of the period if the overrun in the rendering is even higher). Depending on the way in which the animation is implemented in the application, this will usually cause a visible blip or stutter. Regular misfires would make the animation appear jittery and unpleasant.

As most developers simply add the timer to the main runloop, it means that the events need to fire in between whatever other code the main runloop is executing (in particular, user events). This can add inconsistency to the timer period.

Things that can be done to improve this situation (many of which can be done together) are:

  1. Optimise the drawing code so that it comfortably completes within the timer period (16.667ms for 60fps). If it's far under this threshold, then the other things happening in the runloop shouldn't regularly push it over the threshold.
  2. Change the animation code so that it does not expect a regular period and animates the scene based on how much time has passed since the last animation. This is not always feasible - see this time-based animation tutorial.
  3. Set the timer on a seperate thread (not the main thread).
  4. Use a thread with its own custom loop rather than a timer. This in itself is not a solution if the rendering regularly exceeds the desired frame rate period, however can improve the smoothness of the animation when combined with some of the other things in this list; it also gives you greater control over when to draw the next frame when the previous frame has overrun, instead of being forced into multiples of the timer.
  5. Increase the timer period and only render the scene when an appropriate amount of time has passed (oversampling).
  6. Decrease the frame rate; however it can only be decreased so far before it starts to look bad.
  7. Decouple the drawing from code that is not directly related to rendering (such as physics simulation or animation logic) - see this blog on fixing the animation timestep for a good overview of this approach.
  8. Synch to the hardware refresh. This is typically what console games do and would be the best approach in many situations. Unfortunately this not currently possible on the iPhone as no hook or callback is provided by the underlying APIs.

My preferred approach is a combination of 1, 2 and 4. If option 8 was available I would go for a combination of 1, 2 and 8.

Tuesday, 12 May 2009

Rise of the crapplication

There has been chatter of late in the iPhone developer forums that I frequent regarding the prolifation of crap applications (crapplications, or simply crapps) in the App Store and that the App Store model encourages this. Could this really be true?

Like many others, I have a full-time job and just develop iPhone applications in my spare time. But that does not mean it costs nothing to develop my applications. On the contrary - my spare time is very valuable to me - but how do I quantify it? If you assume that I did some other work, say contract work, over that time then the opportunity cost of this lost income can be determined.

With this in mind, I decided to examine one of my applications, Magnetic Block Puzzle to see what the cost of developing it was and what sort of sales I would need to achieve to break even in a reasonable period of time.

Magnetic Block Puzzle deconstructed

I estimate that it took around 200 - 300 hours to develop, from start to release-ready code. In order to calculate an opportunity cost for this time, I need to determine an hourly rate. Conservatively I am using a rate of £30 per hour. That equates to an opportunity cost of £6,000 to £9,000. For the rest of this exercise, I will use the average of £7,500 (about $11,500). Expenses incurred in developing the application have been ignored.

So, how many sales are required to break even?

TierPrice ($)Price (£)Pre-tax profit (£)Req sales
Tier 10.990.590.3620,833
Tier 21.991.190.7210,417
Tier 32.991.791.096,881
Tier 43.992.391.455,172
Tier 54.992.991.824,121
Tier 65.993.492.123,538
Tier 76.993.992.433,086
Tier 87.994.993.042,467
Tier 98.995.493.342,246
Tier 109.995.993.652,055

I need to sell 10,417 copies at its current price of £1.19 ($1.99) just to break even! How many sales are required then, per day to break even in six months?

TierPrice ($)Price (£)Pre-tax profit (£)Req sales per day
Tier 10.990.590.36114
Tier 21.991.190.7257
Tier 32.991.791.0938
Tier 43.992.391.4528
Tier 54.992.991.8223
Tier 65.993.492.1219
Tier 76.993.992.4317
Tier 87.994.993.0413
Tier 98.995.493.3412
Tier 109.995.993.6511

57 copies a day at the current price doesn't sound too bad until you consider that it needs to maintain this level for six months and that on its best sales day it hasn't come close to this amount. It's looking unlikely that I will break even on this any time soon, if ever.

What are the options then? Raising the price requires fewer sales to break even, but raising the price will result in a decrease in sales too, so this is unlikely to help.

Perhaps lowering the price to 59p ($0.99) will help boost sales? It probably will, but at that price the required number of sales to break even shoots up to 20,833 or 114 a day for six months.

The only other option is to lower the development cost. In other words, spend less time developing it in the first place. Too late for this application, but valuable information to take to the next one. Knocking off 10% or 20% is not going to change the situation much. The decrease needs to be significant (say, an order of magnitude). Putting 20 - 30 hours of effort into building an application means an opportunity cost of around £750, which can more realistically be recouped through App Store sales in an acceptable period of time. But what can be built in 20 - 30 hours? Ah, a crapplication.

Pricing

The above logic of course assumes that a crapplication will sell as well as something that took ten times longer to develop. Unfortunately, the history of the App Store leads me to believe that you are no more certain to sell something good than you are to sell something crap. If it appeals to the masses, it will probably sell, irrespective of how bad or how good it might be (this is the best example of the former).

A popular story that is quoted is the developer that decided to see what could be built in an hour; came up with Sound Grenade in 20 minutes and landed up cracking the App Store top 10 with it.

The blessed / dreaded charts

To break even many sales are required at a low price, or fewer sales at a higher price. In pre-App Store days people would happily pay £5 to £10 ($7 to $15), or even more for a mobile application. Ringtones and images were confined to the price brackets below this. The App Store has changed everything. Customers now expect to be able to buy just about anything for 59p ($0.99). It wasn't always like this - I remember the first few apps on the App Store being more costly. Didn't I purchase Super Monkey Ball and Enigmo for £5.99 ($9.99) each? Yes, I did. What happened?

This slide can arguably be attributed to the App Store charts. The charts are just based on downloads, irrespective of cost. So, a £5.99 ($10.00) application would need 10 times the turnover in order to compete with a 59p ($0.99) application in the charts. Of course, this is a losing battle. Surely charts should take the price into consideration? As it stands, it has clearly become a volume game.

Getting a spot in the App Store charts is essential for every developer. The charts tend to be self-perpetuating. Once an application is in there, it is noticed by more people and therefore downloaded more, boosting its position in the charts, leading to even more people noticing it and so on.

It seems then that developers have little choice but to charge 59p ($0.99) or £1.19 ($1.99), or at a push £1.79 ($2.99) and hope they crack the charts. If they don't, the application is quickly confined to the abyss of unnoticed applications (AUA), picking up the odd few sales here and there, but ultimately not very many.

Summary

It would seem that the best return on investment is to spend as little time as possible building an app, try to give it mass appeal and price it at tier 1 (59p or $0.99). Perhaps then building iPhone software with the aim of making money is viable.

If like me you have spent a significant amount of time building applications, for very little reward, console yourself with the fact that many of us are in the same boat. Let the enjoyment of building the application be your reward and the sales (if there are any) be a nice bonus.