Mono C# struct performance

Hi,

I have a question that I’m hoping there are any Mono C# guru might be able answer :slight_smile: I have implemented a double precision version of Vector3 and made some troubling discoveries with regards to its performance compared to its 32-bit float version. To illustrate I have created an example. This is the struct:

public struct DVec3
{
	public double x;
	public double y;
	public double z;
}

This is my test code:

		Stopwatch timer = new Stopwatch ();

		Vector3 v1 = new Vector3 ();
		Vector3 v2 = new Vector3 ();

		DVec3 dv1 = new DVec3 ();
		DVec3 dv2 = new DVec3 ();

		timer.Reset();
		timer.Start ();

		for(int i = 0; i < 100000000; ++i)
		{
			v1 = v2;
		}

		timer.Stop();

		UnityEngine.Debug.Log (timer.ElapsedTicks / TimeSpan.TicksPerMillisecond);

		timer.Reset();
		timer.Start ();
		
		for(int i = 0; i < 100000000; ++i)
		{
			v1.x = v2.x;
			v1.y = v2.y;
			v1.z = v2.z;
		}
		
		timer.Stop();

		UnityEngine.Debug.Log (timer.ElapsedTicks / TimeSpan.TicksPerMillisecond);

		timer.Reset();
		timer.Start ();
		
		for(int i = 0; i < 100000000; ++i)
		{
			dv1 = dv2;
		}
		
		timer.Stop();
		
		UnityEngine.Debug.Log (timer.ElapsedTicks / TimeSpan.TicksPerMillisecond);

		timer.Reset();
		timer.Start ();
		
		for(int i = 0; i < 100000000; ++i)
		{
			dv1.x = dv2.x;
			dv1.y = dv2.y;
			dv1.z = dv2.z;
		}
		
		timer.Stop();
		
		UnityEngine.Debug.Log (timer.ElapsedTicks / TimeSpan.TicksPerMillisecond);

The results with Unity 4.3 (running in editor) in Windows XP 32-bit:
Test 1: 783
Test 2: 831
Test 3: 12063
Test 4: 875

The performance difference between assignment of the Vector3 and the DVec3 is enormous. I have run this same test on a VS .net 4.0 debug build and got a completely different result - test 3 is faster than test 4. Currently the only decent workaround I can find is to avoid using the struct operators and just work with the values directly…

So my questions are; whats causing this and what can I do to fix it? Is it something to do with the size of the struct?

Thanks,
RV

I think this is likely to be some kind of dumb codegen bug in the Mono 2.x that ships with Unity. It would be interesting to see how the test performs if you change the double to a float in your structure. If that makes a big difference, than it indicates that maybe there is an issue specific to doubles in the Mono 2.x runtime.

Thanks for your reply. I did a bit more testing and discovered that it doesn’t appear to be an issue with doubles but rather if a struct is over 16 bytes in size (in this case 24 bytes) it will incur some horrific performance penalties. I’m still unable to find any information on why this is, but perhaps Mono is treating structs differently when they are above 16 bytes - perhaps something to do with how they are allocated or the way operations are inlined. I also need to test this in a release build to see if the results are any different.

It seems to be a common issue with structs, whenever you have struct being greater than 16bytes it becomes way more expensive regarding performance.
I’ve just read some posts in other forums about it and people always mentioned that you should rather use reference types when you need more than 16byte plus need to pass/copy stuff around alot.
I didn’t find an exact answer for the actual technical reason, only that it is probably some kind of more complex computing whenever it’s > 16bytes.

MSDN recommends making structs 16 bytes or fewer, so I doubt it’s an issue with Mono.

–Eric

Yes, I have seen 16 bytes mentioned in other places as well and I have discovered the performance differs greatly if the struct is 16 bytes or less. However, I was not seeing similar issues with a .NET 4.0 debug build when running the exact same test so I do think its something specific to the version of Mono that Unity uses. If it were twice as slow, I wouldn’t have brought this to the forums but a difference of 24 byte struct operations being 14-20x slower than a 12 byte struct strikes me as quite odd :frowning:

My numbers are 198, 98, 1325, 196 (Mac Pro), so “only” about 7X slower here, but yeah that seems excessive. Copying the x/y/z values individually doesn’t have the problem, so it seems something weird is going on with the assignment operator, which unfortunately can’t be overloaded. (Interesting that your computer doesn’t have any speed increase when copying the x/y/z values individually for a Vector3, whereas mine gets twice the speed when doing that.)

–Eric

Thanks for sharing that Eric, its very useful to see results on a different platform and it seems to some extent the performance issue I’m experiencing isn’t unique to my pc. Like you I’m puzzled because I was expecting test 2 to be faster than test 1 which would make more sense since you are doing the operation directly. I hope someone more clued into the inner workings of Mono 2.x compiler can chime in but until then I will just have to cross my fingers for Unity upgrading its C# compiler some day :slight_smile:

In the meantime, I have been applying some of the knowledge of my discoveries to various areas of my code and have shaved milliseconds off execution time. Although this sort of thing might seem overkill to some people, if you have critical run-time code which does large amount of vector operations (for example dynamic procedural meshes) then you can make quite substantial savings if you understand what operations are expensive.