Question about struct boxing. (performance related!)

I defined a int vector like this:

public struct MyIntVector2
{
  public int x;
  
  public int y;
  public static int Dot(ref MyIntVector2 a, ref MyIntVector2 b)
  {
  return (a.x * b.x) + (a.y * b.y);
  }
  //..
  //Some other methods
}
public class MyIntVector2Test : MonoBehaviour {
   void Start () {
  
     var a = new MyIntVector2(1,1);
     var b = new MyIntVector2(2,2);
     var c = MyIntVector2.Dot(ref a, ref b);
   }
}

My question is about MyIntVector2.Dot()'s performance:

When I call MyIntVector2.Dot, the struct a and b will be boxing by C# runtime?

I read ref keyword - C# reference | Microsoft Learn

It said: There is no boxing of a value type when it is passed by reference.

I think

“public static int Dot(ref MyIntVector2 a, ref MyIntVector2 b)” 's performance is better than

“public static int Dot(MyIntVector2 a, MyIntVector2 b)”

Is right?

But I also looked UnityEngine.Vector2.Dot:

static float Dot(Vector2 lhs, Vector2 rhs)

Why unity don’t use ref keyword? like:

static float Dot(ref Vector2 lhs, ref Vector2 rhs)

This means struct will be boxing when it passed by “ref” in unity c#?

Hard question, I’m not sure anyone here give you right answer)
I think, it could be usefull to compile test and see IL code :wink:

Also, I think, CLR could spent some extra resources for passing value type as reference, and copying of value could be more effective.

http://stackoverflow.com/questions/8203247/is-a-struct-boxed-when-passed-to-a-method-using-the-ref-keyword

Contrary to what most people suggest, passing valuetypes by ref does not carry anything near a performance benefit.
It might make sense that passing a reference consisting of 4-8 bytes (depending on OS) is faster than copying a bytechunk, means a struct.
However, practically this theory proves to be falls. Feel free to aswell benchmark it.

But why is that so? Well, the CLR first has to build/fetch the memory pointer which is slower than just passing a struct by value.

Though, under some conditions by ref might be fast, namely huge structs with about 100 bytes of data. Give or take.

Under normal cirumstances you dont have to worry about this kind of stuff. The performance benefits/increases/decreases are absolutly not noticeable and will just reflect in a few milliseconds on 1kk calls.

But it may be important for me, since in my algorithm there are a lot of geometry struct which like: vertex, rectangle, edge, edgeAA, etc.

These geometries will be calculated as some method params and these geometries ’ calculation may be in for loop.

This means these structs will be copied a lot of times:(

Like I’ve explained above, it doesnt make any difference. Even in loops the above explanation matches, byval and therefore copying the struct is faster than passing byref. Stack is fast, dont forget that! Only for huge structs it’ll make a small difference. Tho if you hit such big structs, you might consider turning them into a class since that might be a more accurate represenation of that certain object.

Furthermore, what will give you way more performance benefits is inlining. Especially small methods which are used in loops have a higher priority to get inlined. However, methods with ref/out keywords wont be inlined. Keep that in mind.

Tho I dont quiet remember if thats correct, but methods taking valuetypes as parameters wont get inlined aswell.

//E: It doesnt matter if its important to you or not, it’ll change nothing of the fact of passing by ref being slower. :wink:

Thanks,

But could you tell my why passing by ref will be slower?

boxing?

Value types are not boxed when passed to a ref parameter. And the pointer that is created actually lives on the stack, so the heap does not even come into play. You should bench mark it to find out which is faster or slower in your case but either way you will be operating on the stack. Now, as Sharp Development has said, getting the pointer to pass may be slower than copying the struct. This is going to depend on the struct itself. Yours are very small (8 bytes) so really you’re only saving 4-bytes per method call in memory and copying those structs is hardly any different than declaring 2 ints which you would do without thinking about it, so I think it’s over optimization to pass by ref.

1 Like

Exactly this.

Just to add a little point. Due to pointers needing to be created/fetched when passing by reference, you lose performance, means itll be slower! Especially for small structs.

//E: vb.net - Which is faster? ByVal or ByRef? - Stack Overflow

1 Like

Why would you want to pass by ref? it’s a struct like Vector3. Just pass it by value. I dont see the the point.

Since the two words “by reference” in this context suggest some kind of performance benefit when passing value types. Tho, thats not the case.

What if you don’t declare your method static ? You’d be passing only one argument.

c = a.dot(b);

I haven’t benchmarked it but you should if you think the byval argument copying will plunder your performances.

Thanks.

I think fetch point by reference should be a fast operation. (Only get struct pointer on stack and push it to next function stack)

My struct will be 16bytes or 32bytes. (copying of value maybe faster in 64bit fast-copy, 64bit maybe copy 8bytes in one Instruction, but in 32bit platform? slower?)

I will implelemt my algorithm by “copying of value” first…

But it seems need further study. (eg: check IL code and do some benchmark)

very thanks.

You let me believe "Value types are not boxed when passed to a ref parameter. " in unity.:slight_smile:

I didn’t just let you believe it, it’s true.

“There is no boxing of a value type when it is passed by reference.”
– http://msdn.microsoft.com/en-us/library/14akc2c7.aspx

Now, if your parameter type was “object” instead of your struct type, then it would be boxed and unboxed (when you returned and casted), but you’re passing a struct by ref so it only creates a pointer on the stack.

Even if your struct was huge - which a struct should not be - passing them by ref is a very bad habit you’re carrying from C++ pointers, which you should get rid of as soon as you can.

http://stackoverflow.com/questions/635915/when-to-use-ref-and-when-it-is-not-necessary-in-c-sharp

Useful answer: you almost never need to use ref/out.
Just don’t do it. When you will actually NEED to do it, you will know about it because there will be no other way around a specific issue.

1 Like

Infact, instance methods are aswell static methods. They are just hiding the “this” parameter on which they operate on the target instance of a class.
In other words, it doesnt matter, you will always have two parameters passed.

@chansey97 , I think you’re coming to C# with a lot of C+±isms that aren’t particularly useful or even applicable in .NET land. I’m willing to bet that all these micro-optimizations that you’re preoccupied with won’t even register in the profiler.

I’m not sure what would be the best way to get out of that mindset. I still find myself writing ++i in for loops because that’s The Proper C++ Way™.

You’re in Rome now. Get used to what those non-typedefing, un-std-pair-ing, pointer-ignorant Romans do :slight_smile:

1 Like