Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

In something as simple as int sq(int x) { int y = x*x; return y; } versus int sq

ID: 645861 • Letter: I

Question

In something as simple as

int sq(int x) { int y = x*x; return y; }
versus

int sq(int x) { return (x*x); }
the former function requires an extra IL step.

EDIT: IL code from the first example, using the current C# compiler from VS 2013 Update 4 (.NET Framework 4.5.1), code from the optimized release version:

IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: mul
IL_0003: stloc.0   // These two instructions
IL_0004: ldloc.0   // seem to be unneccessary
IL_0005: ret
and from the second example:

IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: mul
IL_0003: ret
Is that IL extra step indicative of data being copied in memory? Is this difference still present when using something seemingly better optimized? (C?)

If yes to first or both: can I use the latter, especially when the returned data takes a lot of space, and presumably a lot of time to be moved in memory? Or should I favor the former, because it is more readable? LINQ makes it easy to have whole functions inside a long return() line, but my example faces the same choice were it C. Speed or readability?

In general, would you put the last bit of maths between the parentheses in the return line?

Explanation / Answer

First of all, micro-optimizations like this rarely make sense. You should focus on readability and worry about these kinds of optimizations only when you've identified the code that you actually need to optimize by profiling.

Now, if you're still interested about performance, looking at IL doesn't make much sense, because it's not IL that's executed.

Instead, what you should do is to measure.

Another option would be do look at the generated machine code (usually x86). But the problem with that is that CPUs are very complicated and it can be very difficult to figure out which version of the code is going to be faster.

Note: looking at the machine code is not as simple as opening the Disassembly window. You need to run in the Release mode, and make sure the CLR actually does optimize the code (either by unchecking "Supress JIT optimization on module load" or by starting without the debugger attached: Ctrl+F5, and attaching it later e.g. using Debugger.Break() and selecting to debug the code).

If you do that, you will most likely notice that both versions of the method are going to be inlined, which makes it hard to see which instructions belong to your method (but both versions generate the same machine code for me).

If you want to compare the two versions of the method in isolation, you can use [MethodImpl(MethodImplOptions.NoInlining)]. With that, the code I'm getting for both versions of the method is the same:

push ebp
mov ebp,esp
mov eax,edx
imul eax,edx
pop ebp
ret

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote