I've noticed that it's possible to outpace the built-in math functions quite simply. I'm assuming the scripting is slower than the functions in the engine. Which leads me to wonder if some of these could get a little optimization. Ordinarily this sort of thing doesn't matter in comparison to other game mechanics, but since this is almost the basic math - it would be nice if it were super optimized - since in many cases, thousands of math operations per frame are a reality. I guess the Mathf stuff just redirects to the system.math libraries, but still - things like lerp are easily beaten with simple scripting. Code (csharp): public static Vector3 QuickLerp3(Vector3 one, Vector3 two, float t) { t = Mathf.Clamp01(t); //also can rewrite clamp to pass the value type by reference, if you want to squeeze performance out return new Vector3( one.x + (two.x - one.x)*t, one.y + (two.y - one.y)*t, one.z + (two.z - one.z)*t ); } I've also rewritten absolute value, squared, and the clamps, all of which are much faster. I haven't looked at the matrix operations, I'm assuming those have been optimized internally. Furthermore the absolute value function could be optimized to simply remove the sign bit, it would be cool if some of this were done in the engine itself - as it would likely run even faster.
I must admit, I've always wondered if the Mathf routines just call the System routines and cast the parameters and results to float. It's a missed opportunity for optimisation if they do. The transcendental functions need to be calculated to more significant figures for doubles and this means more loop iterations and more CPU time. All this time is wasted if the result is rounded off to be converted to float!
I did the ref function clamp as well - I measured a speed difference of 40% last night over a million iterations or so. The complete code looks like this: Code (csharp): public static void RefClamp01(ref float number){ if (number > 1){ number = 1; } else if(number <0){ number = 0; } } public static Vector3 QuickLerp3(Vector3 one, Vector3 two, float t){ RefClamp01(ref t); return new Vector3( one.x + (two.x - one.x)*t, one.y + (two.y - one.y)*t, one.z + (two.z - one.z)*t ); } Here is a test case - depending on how you stress it you may notice more or less speed difference. My clamp in particular is much faster for values of t > 1 or less than 0 in Lerp. Anyway, I'm wasting a lot of cycles doing other stuff, but I wrote this as a simple test case, and it still is a lot faster. I'm getting 0.369 seconds for A vs 0.305 seconds for B. Try it yourself... Code (csharp): using UnityEngine; using System.Collections; public class Iterator : MonoBehaviour { // Use this for initialization void Start () { Iterate(1000000); } void Iterate(int iter){ float xy = Time.realtimeSinceStartup; for(int i=0; i<iter;i++){ TestA(); } float endA = Time.realtimeSinceStartup-xy; float yz = Time.realtimeSinceStartup; for(int i=0; i<iter;i++){ TestB(); } float endB = Time.realtimeSinceStartup-yz; Debug.Log(endA + " : " + endB); } void TestA(){ Vector3 test1 = new Vector3(Random.value,Random.value,Random.value); Vector3 test2 = new Vector3(Random.value,Random.value,Random.value); float blah = Random.value*2; Vector3 result = Vector3.Lerp(test1, test2, blah); } void TestB(){ Vector3 test1 = new Vector3(Random.value,Random.value,Random.value); Vector3 test2 = new Vector3(Random.value,Random.value,Random.value); float blah = Random.value*2; Vector3 result = MathLib.QuickLerp3(test1, test2, blah); } }
They don't! converting to double and back would indeed be very slow, but it's not what we're doing. Still, interesting observation. Can you give any numbers by how far your custom math is faster then ours? edit: too slow, you just did. Interesting. I will investigate this further..
Thanks for taking a look. I also discussed with a coworker - I can also match the speed of many of the functions - such as Vector3.Dot and Vector3.Cross. My expectation was that since this is relatively simple math I wouldn't be able to beat the engine. Either these aren't being called in C++, Mono is just as fast, or there is so much overhead associated with calling a C++ function the math is insignificant compared to the function call. Like I said before, I realize ordinarily this sort of optimization is trivial, but in the case of these basic math operations - squeezing some extra performance out would help everyone.
As an update, while Unity 2.6 did in fact speed up those Lerp functions a reasonable amount, it turns out it's still faster to write your own functions. So I've added SpeedLerp to the wiki, which has various replacements that range from 1.4X faster to 3.5X faster than using built-in Mathf functions, based on simple benchmarks. (If anyone was wondering how exactly my latest version of Fractscape got 2X faster for texture calculations and 4.5X faster for terrain calculations, that's a pretty big reason why. Among other things.) --Eric
Speaking of faster, I was looking through the disassembled SmoothStep function because it seems that there are a lot of ways to evaluate it. Unity uses Code (csharp): public static float SmoothStep(float from, float to, float t) { t = Clamp01(t); t = (((02f * t) * t) + ((3f *t) *t); return ((to * t) + (from * (1f - t))); } which is only about 80% as fast as: Code (csharp): static float MySmoothstep(float a, float b, float t) { // saturate t to 0..1 range t = Mathf.Clamp01(t); // Evaluate polynomial return a + (t*t*(3-2*t))*(b - a); } But then who uses SmoothStep enough for it to matter? Note: I got Unity's code from the .NET reflector, so who knows what the original code looked like.
Guess you forgot something in the original code, like a *t? otherwise yours would be wrong and the seperation into the 2 terms in the original one wouldn't make any sense And it makes sense that yours is faster, less multiplications to execute (original one is 6 mul, 3 sum while the new one is 4 mul, 2 sum)
Me; it's very useful. Anyway, it's faster to return a if t < 0 or b if t > 1, instead of clamping it and then evaluating the function...seems kinda like a waste of CPU cycles when you already know the result in those cases. Unfortunately your routine doesn't seem to work or else I'd steal it if it would make SmoothStep faster. --Eric
I just found this thread due to the bumping and was curious so I ran UnityEngine.dll through Reflector.NET and contrary to what jonas echterhoff said a ways back a large portion of Mathf is just redirects to System.Math. Here is one example (there are a ton more in there): Code (csharp): public static float Round(float f) { return (float) Math.Round( (double) f); } If this is correct then there could be a pretty big performance gain from a rewrite of the Mathf struct especially on the iPhone.
Jonas may have been referring to the transcendental functions (trig functions, sqrt, etc). There would be a much greater performance hit for these than with things like Round.
Round was just the one I was looking at when I copy/pasted. Almost every function in there is just a cast to double cast back to float.
Is there any downside to using the MathS functions, Eric? Apart from the fact that the performance boost might not be huge? Basically all I do in my Update() calls is Vector3 lerping (with occasional slerping), so it'd be nice to get back even 2 or 3% of that processing time. I guess I'm nostly I'm curious to know why the home-brewed math functions are still faster than the builtins.
...my god. Sweet. Well, performance never hurts, so in it goes... I've been working exclusively with javascript... am I going to shoot myself in the foot using the .cs version of these routines? Should I just make a javascript partner? I know there can be issues using javascript and c# components at the same time but these are static functions so they should be safe, yes?
No, I use Javascript 99% of the time. As the usage docs say: "Put the MathS script in the Scripts folder in Standard Assets; this way it can be called easily from Javascript and Boo." It's actually not about static functions, but rather script compilation order. The main reason it's in C# is that I was playing around with reference variables (which you can use in Javascript but not directly declare in functions) to see if there was any speed benefit...I had an overload where instead of doing "foo = Mathf.Lerp(0, 100, .5)", you'd do "Mathf.Lerp(foo, 0, 100, .5);" It turned out that didn't really help, but since MathS works fine from any language as-is, there's not much point rewriting it. --Eric
Oops- I was doing last-minute editing on my post before I submitted it and neglected to paste something back in. (This is why one should never edit ones posts). It should have said:
It's not special treatment per-se, it's about accounting for compilation order to make sure that the routines are available for your javascript. http://unity3d.com/support/documentation/ScriptReference/index.Script_compilation_28Advanced29.html If you want to use xyz function from Eric's class, it obviously has to be defined before you use it. You can see some examples of javascript->C# interoperability with the perlin noise generator on the resource section of the unity website.
Good to know- thanks! I just made an otherwise unused folder named "Standard Assets" and now the myriad compilation errors are gone.
Well, it's kind of special treatment...if you just make a folder called "Blah", that won't work. --Eric
Hmm.. I noticed that using the System.Math functions instead of the Mathf functions is already a whole lot faster (including the casting from / to double, or using double right away). This seems to be especially the case for things like sin() or sqrt() and such. It would be nice if Unity could, for one, implement the math functions properly for floats (what else would be the point of having Mathf in the first place?), and then provide a built in library for functions that have to run lightning fast but don't nescessarily have to be exact. E.g. Sin() could be implemented with a lookup table that is precised to 1/10th of a degree (I did that for my own code and the performance gain is immense, while the precision loss is not noticable in most cases). I was quite surprised when I figured out that my code was just slow because I used rudimentary functions of Unity, like Sin() or Distance() etc. For a game engine that's a no-no :roll:
I found this thread quite interesting as I'm a sucker for optimization. Is there any news from Unity developers on this issue? It seems to me extremely wrong that custom made math functions should be faster than the internal Mathf functions.
Just came across this thread after profiling some code and noticing that Mathf.Abs() simply calls Math.Abs() in Unity 3.4. Quite a revelation as in my case I was using it to try and test for denormal numbers within a heavy loop doing image processing, resulting in over 600k calls per frame. The double call nature really hammered performance. Granted that was a specialized case, but still its something i'll keep in mind in the future. No point calling a Mathf function if all it does is call the corresponding Math function.
Where we have two issues: 1) Hail the thread necros , for no real reason... 2) Profiling ^^. How did you profile? With Unity profiler? In either case, what shall "really hammered performance" mean? The processor simply doesn't care about double calls as long as they are unconditionally and have no profiling code in between , which they probably had in your case. Additionally you were probably using the debug version, which doesn't inline double calls...
Other than it being of vital importance to those who are unaware of the situation and have heavy usage of Unity Mathf functions, you mean? Along with the post above mine asking if there were any plans to address the situation, which is much better here than starting a duplicate new topic. Granted doing a deep profile in Unity didn't help its cause, but measuring the results (timing directly around the function) without the profiler revealed a similar situation; No ABS in function = 80 fps System Math.Abs = 64 fps Unity Mathf.Abs = 54 fps So whilst adding a call to Abs is costly regardless (to be expected), the drop of 10 fps is considerable considering you'd expect it to be the same performance as calling system Math. Obviously this is still a somewhat special case, Abs is being called hundreds of thousands times a frame, but then its precisely these situations where it would be vital to know that calling Unity Mathf is going to slow down.
I know necroing, but this might be interesting: Unitys Min and Max function use >= respectively <= which is a small performance decrease over > and <. When viewing in a Reflector it looks like this: Code (csharp): public static float Min(float a, float b) { return ((a >= b) ? b : a); } But the following which works the same is obviously slightly faster: Code (csharp): public static float Min(float a, float b) { return (a < b) ? a : b; } Also as Noisecrime mentioned Mathf has some functions which are a kinda pointless wrapper around some .net Math functions. Like: Code (csharp): public static int FloorToInt(float f) { return (int) Math.Floor((double) f); }