Android FloatMath revisited

Today i implemented a class called FastMath which offers the same static methods as the Android FloatMath class. Behind the scenes there’s a singleton instance which can be user defined that actually implements the math functions such as cosine, sine or sqrt. All the math code in libgdx now uses that static class to delegate those calculations to platform dependent optimal versions, like FloatMath on Android.

I have two implementations for the FastMath class, a standard implementatin using the Math class from the standard library as well as an Android specific implementation that uses the FloatMath class internally. When calling a method of the FastMath class it gets delegated to the singleton instance which means we have one additional call to a static method, another call to the singleton method, e.g. AndroidFastMath.cos(), and finally the call to the actual implementation, e.g. Math.cos() or FloatMath.cos(). That’s a total of 3 calls to get the cosine of an angle or a square root.

A request for enhancement over on the issue tracker requested this so we get maximum performance on all platforms. I had the suspicion that this wouldn’t work out from the beginning due to the function call overhead. The design is as slick as possible so i believe that the three method calls are the minimum.

Now here’s some hard data. I tested the methods Math.cos, Math.sqrt, FloatMath.cos, FloatMath.sqrt and FastMath.cos/FastMath.sqrt (which internally use FloatMath) on my HTC Hero (no FPU, Android 1.5) and my Nexus One (FPU, Android 2.2). Each function was executed a million times with a variable argument. Here’s the results for the Hero:


FloatMath.cos(): 10.42688 secs
FloatMath.sqrt(): 2.8764648 secs
Math.cos():9.445556641 secs
Math.sqrt(): 3.755310058 secs
FastMath.cos(): 13.469482422 secs
FastMath.sqrt(): 5.175018311 secs

Wow, now that is silly. Granted this is only a single run and FloatMath.cos() might still outperform Math.cos() when averaged over multiple runs. However, the big loser is my FastMath class which uses FloatMath internally. The function call overhead is immense so nothing is gained here really. How’s the situation on the Nexus One?


FloatMath.cos(): 0.70428467 secs
FloatMath.sqrt(): 0.23391724 secs
Math.cos(): 0.45666504 secs
Math.sqrt(): 0.133239742 secs
FastMath.cos(): 0.910583498 secs
FastMath.sqrt(): 0.48376465 secs

First we see the FPU and the JIT doing there magic. I don’t think that the JIT actually plays a big role here, it’s probably mainly the FPU which is speeding up things significantly compared to the Hero. Math beats the crap out of FloatMath here. This is similar to the old x86/87 Wisdom that using doubles actually increases performance as most FPU registers are > 32bits anyways. You can therefor eliminate a costly conversion to and from float. On the Hero that effect is non-existant as it has no FPU and everything is done in software, so double is slower than floats. FastMath still stinks. The relative timings to FloatMath are nearly the same as on the Hero which suggests that the function call overhead is still there. The JIT in Dalvik does no inlining yet so you still have to pay the price for excessive function calls.

So what does this mean? FloatMath works a tiny bit better on older devices with no FPU as expected. On never devices with FPU it’s actually slower it seems due to load conversions to and from the FPU registers for 32-bit floats. Function calls are still evil and nasty even with the JIT. Finally, i’ll revert the changes to libgdx and use the standard library Math function instead. The performance impact on old devices is neglectable.

Note: Yes, those are only micro benchmarks and there’s a lot that’s ignored. However, for my purposes they are more than precise enough.

WTF: Google you scare me. 20 minutes after i posted this i get the following. I never felt so relevant…

  • Share/Bookmark
 

3 Responses to “Android FloatMath revisited”

  1. [...] This post was mentioned on Twitter by Planet Android, Daniel. Daniel said: Android FloatMath revisited: Today i implemented a class called FastMath which offers the same sta… http://bit.ly/cFnVL8 #xoopia #android [...]

  2. Mike Leahy says:

    Interesting data regardless of micro test.. Silly me insofar that I never saw the FloatMath class, but no worries since the standard Math class is outperforming. I also have a separate Math2 class with “optimized” methods for atan, sqrt, and other calculations, but you always have to check out how they run on a given platform. The sqrt stuff often doesn’t have any performance gain. Depending on the application LUTs are the tried and true approach.

    I too recognized the method calling overhead on Android when I tested replacements for EventListenerList (J2SE) and keeping with the array backed one and a new linked list implementation I made. I made a factory implementation to switch between both and took note of the extra method calling overhead.

  3. [...] in Android’s FloatMath class? Well here’s FastMath, which is FloatMath, [...]

Leave a Reply