I ran a simple benchmark that passes structs as an argument: one uses StructLayout.Sequential and another StructLayout.Auto.
I intentionally ordered fields in a way that makes them have padding.
And result is (the formatting in mobile clients sucks):
| Method | Mean | Ratio |
|------- |---------:|------:|
| Auto | 298.6 us | 1.00 |
| Seq | 359.0 us | 1.20 |
Obviously copying struct that is bigger due to the padding to pass it as an arg is slower. But this operation is so quick that it might be a problem only on a very hot path.It can be avoided by using 'ref' parameter so no copying occurs. I've also thrown readonly structs to the test.
| Method | Mean | Ratio |
|------------- |---------:|------:|
| Auto | 318.5 us | 1.00 |
| Seq | 398.7 us | 1.25 |
| AutoRef | 254.5 us | 0.80 |
| SeqRef | 299.7 us | 0.94 |
| AutoReadonly | 312.9 us | 0.98 |
| SeqReadonly | 390.5 us | 1.22 |
As you can see passing both structs by ref is definitely faster. But Auto is again faster than Sequential. While readonly structs don't have any performance benefits according to this benchmark. To make sure a defensive copy of a readonly struct is avoided, I've also added 'in' parameter to the arg and now we can see that structs are not copied anymore and performance is on par with the 'ref' parameter| Method | Mean | Ratio |
|--------------- |---------:|------:|
| Auto | 299.9 us | 1.00 |
| Seq | 369.1 us | 1.23 |
| AutoRef | 245.1 us | 0.82 |
| SeqRef | 305.7 us | 1.02 |
| AutoReadonly | 309.1 us | 1.03 |
| SeqReadonly | 369.6 us | 1.23 |
| AutoReadonlyIn | 255.4 us | 0.86 |
| SeqReadonlyIn | 303.4 us | 1.02 |
I performed all these benchmarks in .NET. It would be very interesting to look at it in Unity using IL2CPP, whether it affects performance in C++ or not.https://www.meziantou.net/optimize-struct-performances-using-structlayout.htm
#optimization #struct #layout #ref