views:

101

answers:

5

Say I have a struct:

struct MyStruct
{
    public int X
    public int Y
}

And a method in some class that is iterated over many times elsewhere:

public bool MyMethod( MyStruct myStruct )
{
    return ...
}

Is changing the MyMethod signature to the following an acceptable optimization?

public bool MyMethod( ref MyStruct myStruct )

If so, how much of an advantage would it really be? If not, about how many fields would a struct need for a big enough advantage using ref this way?

+7  A: 

You'd be making a change to push 8 bytes of data instead of 4, on a 32-bit system. No change in amount of data pushed on a 64-bit system. You are also adding a requirement to the compiler/JITter that the struct must exist in memory since you are going to be taking the address of it, which may negate other optimizations.

I doubt this will show any performance increase in your program. Profile first and see if MyMethod is even a bottleneck in your program.

Then, presuming there are no other optimization opportunities in MyMethod, make the change to pass by ref, and profile again to see if there is any improvement.

Michael
Why does everyone always say "profile first" or "premature optimization is the root of all evil" if someone asks a theoretical question about performance?
Rauhotz
@Rauhotz: Because "theoretical" and "performance" in the same sentence is really a non-sequitur
BlueRaja - Danny Pflughoeft
@Rauhotz: Because many of these things depend on the situation: How many times is something being called, what's operating system, what's the environment. The garbage collector behaves differently in different situations. Sometimes taking more memory is not problem at all, sometimes it's bad, depending on where the program is running and what else is running. And effort for improvement is always balanced against *the time you have*.
Patrick Karcher
@Rauhotz: Theoretically either could be faster...
sixlettervariables
A: 

With two int fields, the advantage will be extremely small, very unlikely to make a difference. It might not make any difference at all.

Once you start adding more than two Int fields, that advantage starts to go up. Still, not enough to matter unless you're calling that method a lot.

Patrick Karcher
+3  A: 

Since you explicitly asked whether it was “acceptable” …

I’d answer no. By passing the argument by ref, you’re lying to the compiler and programmer; ref in .NET (exclusively) means that you intend to modify the argument inside the method.

Of course, you could provide an additional comment explaining the “lie” to the programmer (but not to the compiler … ). But why abuse the semantics in the first place?

If you really need such extreme micro-optimizations (and see the other answers – any performance advantage is questionable for any number of reasons!) .NET may just be the wrong environment. Implement the relevant part in C++.

Konrad Rudolph
+2  A: 

Not likely, given your example. On a 64-bit processor, the structure will fit comfortably in registers, it won't be passed through the stack. Albeit not on a 32-bit processor and an instance method. When you pass by reference, you're paying for accessing the structure members, an extra pointer dereference is required. This can get to be more expensive then avoiding the copy, ymmv.

The payoff typically starts when the structure is more than 16 bytes. One reason for the common guidance to switch to a class when the structure gets larger than that. Given that this completely depends on usage, you'll either have to analyze your code and read the assembly (release build of course) or use a profiler. The profiler isn't that likely to show a difference. It is usually pretty hard to measure a nanosecond unless you artificially do it a billion times.

Hans Passant
A: 

In general I would say no: stick with a class with properties. However, there are circumstances that might call for something like this - in particular on compact-framework (think: XNA) or micro-framework. In both cases the GC is very different, and object allocations (and non-deterministic collection) may have a significant impact on the application.

In such cases it is not unheard of to see more structs come into play, and the ref avoids the common "lost update" problems (in most .NET, structs should be immutable; again, XNA does have some scenarios that make it tempting to break this rule). Another approach of course is to accept and return the data - then the type can be immutable.

If you mean the performance of passing the object; then you have to profile on the exact setup you intend using. x86 vs x64 is the obvious difference, but there are more. For example, using ref demands that a value is in either a field or a local variable - but many of the JIT performance tweaks on structs work on the head of the stack - meaning you might have a lot more "ldloc" / "stloc" than you strictly need. You also introduce an extra dereference.

Marc Gravell