Preamble for planet.freedesktop.org
Sorry about the poor formatting on
planet.freedesktop.org; it seems it and BlogSpot don't quite get along, therefor you won't see any color hilights. It looks much better (and easier to read) on my actual blog page, honest!
Updated version includes float-to-int optimization and comments; sorry if this bumps this rather long post to the top again; this is not my intention. planet.freedesktop.org admins: is there some way to disable bumping when a post is updated? (Perhaps selectively, in case the bump is important. e.g. updated dates for an event.)
This analysis was performed using a modified version of
Chris Lomont's inverse square-root testing code. The
accompanying publication is worth reading before looking at any of this data.
I've started looking into whether there would be any performance difference in a few optimized math functions should
-fstrict-aliasing be enabled. I did not believe strict-aliasing would have much of an effect on these optimized functions (and it turns out I was correct) but the benefit is seen when compiling other code which includes these inline functions.
Without strict-aliasing compatibility, including the header file containing the incompatible functions/macros taints the entire file, meaning you cannot use
-fstrict-aliasing where it may be helpful for your general code.
Here are the results for the standard
1.0 / sqrt(x) frequently used in graphics engines. Even though today's renderers typically use carefully crafted SIMD functions for the critical path, this is still useful for quickly normalizing vectors in game code, etc.
The Lomont version of the function is a tiny bit faster and a tiny bit more accurate, but nothing to write home about.
Clearly it can be seen that this micro-optimization is an excellent for x86 and x86_64. Don't try it on ARM; it's
far slower than just taking the hit on
1.0 / sqrt(x)
I don't know whether this optimization could be modified for ARM; any assembly experts out there?
Timing Exact function
1752 ms used for 100000000 passes, avg 1.752e-05 ms
Timing Carmack function
463 ms used for 100000000 passes, avg 4.63e-06 ms
Timing Carmack function (strict-aliasing)
455 ms used for 100000000 passes, avg 4.55e-06 ms
Timing Lomont function
453 ms used for 100000000 passes, avg 4.53e-06 ms
Timing Lomont function (strict-aliasing)
455 ms used for 100000000 passes, avg 4.55e-06 ms
The absolute value function is mostly used for comparisons (e.g.
fabs(y - x) > epsilon and some other specialized functions: finding on which side of a plane an AABB resides, it's distance from said plane, AABB radius, etc. Therefor it's useful to optimize this function where possible...
Timing Exact fabsf function
268 ms used for 100000000 passes, avg 2.68e-06 ms
Timing Bit-Masking fabsf function
304 ms used for 100000000 passes, avg 3.04e-06 ms
Timing Bit-Masking fabsf function (strict-aliasing)
305 ms used for 100000000 passes, avg 3.05e-06 ms
However, apparently it's quite a bit faster to just call libc's
fabsf function! I saw this originally in the Quake 3 Arena source code, so maybe things were different with the compilers and hardware of the time.
These macros/functions are used when you want to know the sign of a float (i.e. is the value positive or negative) without performing any comparison (for performance reasons.) It seems that the strict-aliasing versions perform about identical to the macros.
Timing Exact float sign bit not set function
327 ms used for 100000000 passes, avg 3.27e-06 ms
Timing FLOATSIGNBITNOTSET macro
313 ms used for 100000000 passes, avg 3.13e-06 ms
Timing Bit-Masking float sign bit not set function (strict-aliasing)
312 ms used for 100000000 passes, avg 3.12e-06 ms
Timing Exact float sign bit set function
342 ms used for 100000000 passes, avg 3.42e-06 ms
Timing FLOATSIGNBITSET macro
305 ms used for 100000000 passes, avg 3.05e-06 ms
Timing Bit-Masking float sign bit set function (strict-aliasing)
305 ms used for 100000000 passes, avg 3.05e-06 ms
Don't use "
d = (int) f" if you want fast code.
fld and
fistp work nicely on x86 and x86_64.
Timing Exact float-to-int function
1252 ms used for 100000000 passes, avg 1.252e-05 ms
Timing Fast float-to-int function
336 ms used for 100000000 passes, avg 3.36e-06 ms
Done. By Chris Lomont 2003. Modified by Oliver McFadden 2011
These measurements were taken on my laptop with an
Intel(R) Core(TM)2 Duo CPU P9500 @ 2.53GHz processor and the test program compiled with
gcc version 4.4.5 (Debian 4.4.5-6)
Whether this makes any huge difference in frames-per-second is debatable, really I had a bit of time and was bored. :-) Anyway, I wouldn't say anything until testing under real-world conditions.
It does look like the bit-masking
fabs can be thrown away, though, and the fast float-to-int is a major win (although beware of possible rounding differences.)