Answered by:
Optimizing temporary/intermediate variables.

Question
-
In our C++ code base, our coding rules require that we separate and identify otherwise arbitrary values with temporaries: please note, this sample code is wholly artificial, entirely pointless/meaningless and was created solely for the purpose of generating some IL code a little further down.
Our C++ code policy encourages breaking down of complex calculations into named intermediate variables.
I realize that - in the following examples, there's no reason not to make MeaningOfLife a private/internal member variable; however our C++ code policy discourages this for single-use values because they can easily become separated from the code to which they are relevant.
Also, I realize that, were it a member, we could similarly initialize "lifeRoot" as a static member or something, given that the source value is static.
However: The code is a reduction/simplification of the recurring concept of intermediate steps of calculation where, for code legibility, you want to temporarily assign a calculated value a name in source only as with the "lifeRoot"
// C++ code float SumRoots(int n1, int n2) { // Local intermediates: that is, the value won't // change for the lifetime of any given call of this // function, so the compiler can effectively optimize // them out. // NOTE: This is different than C#s definition of 'const'. const float root1 = sqrt(n1) ; const float root2 = sqrt(n2) ; // Our one and only references to root1 and root2. const float rootSum = root1 + root2 ; return rootSum ; }
Converting this vaguely to C#:
public float SumRoots(int n1, int n2) { double root1 = Math.Sqrt(n1) ; double root2 = Math.Sqrt(n2) ; double rootSum = root1 + root2 ; return rootSum ; }
What surprised me here was the resulting IL code produced with optimization enabled [and I mean, Build -> Optimize code checked, not just assuming it's optimizing in Release mode :)]
// Code size 22 (0x16) .maxstack 2 .locals init ([0] float64 root1, [1] float64 root2, [2] float64 rootSum) IL_0000: ldarg.0 IL_0001: conv.r8 IL_0002: call float64 [mscorlib]System.Math::Sqrt(float64) IL_0007: stloc.0 IL_0008: ldarg.1 IL_0009: conv.r8 IL_000a: call float64 [mscorlib]System.Math::Sqrt(float64) IL_000f: stloc.1 IL_0010: ldloc.0 IL_0011: ldloc.1 IL_0012: add IL_0013: stloc.2 IL_0014: ldloc.2 IL_0015: ret
I'd expected (having been spoiled by C++ optimizers etc) something more akin to:
// Code size 16 (0x10) .maxstack 8 IL_0000: ldarg.0 IL_0001: conv.r8 IL_0002: call float64 [mscorlib]System.Math::Sqrt(float64) IL_0007: ldarg.1 IL_0008: conv.r8 IL_0009: call float64 [mscorlib]System.Math::Sqrt(float64) IL_000e: add IL_000f: ret
But the C# compiler's optimizer doesn't seem to perform the same kind of local elimination that the C/C++/CLI-C++ compilers do. While I appreciate it might be done by the JIT instead, this seems to unduly bloat the size of the resulting assemblies.
I'm wondering:
a. Is there a way to provide this kind of hint to the C# compiler?
b. Is the C#-generated variant better for parallelization?
Answers
-
I'm wondering:
a. Is there a way to provide this kind of hint to the C# compiler?
b. Is the C#-generated variant better for parallelization?
a. No
b. No
This type of optimization is left up to the JIT in C#. In this case, this is one place where the C# compilers are just behind the C++ compilers. That being said, these optimizations are rarely done at the compiler level in .NET, and instead pushed to the JIT level.
However, I wouldn't worry about it in general - forget the micro-optimizations, and focus on the large scale algorithmic optimizations you can achieve (which are much more effective, and often much easier to create in C#/.NET due to the framework), until you find a "real" (ie: measured) performance problem. Then you can go eliminate the bottlenecks...
Reed Copsey, Jr. - http://reedcopsey.com
If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".- Proposed as answer by James Michael Hare Monday, February 7, 2011 10:27 PM
- Marked as answer by Paul Zhou Friday, February 18, 2011 5:35 AM