# Contents tagged with optimization

I do not want to learn "yet another programming language", especially a low-level one like Microsoft's Intermediate Language (IL). And yet, sometimes it's useful to look under the hood and see what in tarnation is going on. And that means knowing something about IL.

I was answering a question on optimization (the root cause of a lot of unmaintainable code) and found it useful to generate the IL to show which of two algorithms was quicker. With modern operating systems having dozens of background threads running, simple timing can lead to misleading results. Is the algorithm slow, or was System Restore creating a restore point when we measured?

In order to examine code in IL, it's helpful to delimit sections. But we can't use comments, they are stripped out. So, here is a cheesy way to delimit sections of code. Note the variables assigned to MyInt:

`namespace ConsoleApplication1`
`{`
`    class Program`
`    {`
`        static void Main(string[] args)`
`        {                      `
`            string MyString = string.Empty;`
`            int MyInt;`
` `
`            MyInt = 0xAAAAAAA; // ---- Marker: algorithm A`
` `
`            if (MyString == String.Empty)`
`                MyInt = 1;`
`            else`
`                MyInt = 2;`
` `
`            MyInt = 0xBBBBBBB;  // ---- Marker: algorithm B`
` `
`            MyInt = MyString == String.Empty ? 1 : 2;`
` `
`            MyInt = 0xCCCCCCC;  // ---- Marker: end test.`
`        }`
`    }`

When you create the IL with ILDasm, you can easily see where the markers are. In this case I bolded and underlined them:

.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// Code size       68 (0x44)
.maxstack  2
.locals init ([0] string MyString,
[1] int32 MyInt,
[2] bool CS\$4\$0000)
IL_0000:  nop
IL_0001:  ldsfld     string [mscorlib]System.String::Empty
IL_0006:  stloc.0
IL_0007:  ldc.i4     0xaaaaaaa
IL_000c:  stloc.1
IL_000d:  ldloc.0
IL_000e:  ldsfld     string [mscorlib]System.String::Empty
IL_0013:  call       bool [mscorlib]System.String::op_Equality(string,string)
IL_0018:  ldc.i4.0
IL_0019:  ceq
IL_001b:  stloc.2
IL_001c:  ldloc.2
IL_001d:  brtrue.s   IL_0023
IL_001f:  ldc.i4.1
IL_0020:  stloc.1
IL_0021:  br.s       IL_0025
IL_0023:  ldc.i4.2
IL_0024:  stloc.1
IL_0025:  ldc.i4     0xbbbbbbb
IL_002a:  stloc.1
IL_002b:  ldloc.0
IL_002c:  ldsfld     string [mscorlib]System.String::Empty
IL_0031:  call       bool [mscorlib]System.String::op_Equality(string, string)
IL_0036:  brtrue.s   IL_003b
IL_0038:  ldc.i4.2
IL_0039:  br.s       IL_003c
IL_003b:  ldc.i4.1
IL_003c:  stloc.1
IL_003d:  ldc.i4     0xccccccc
IL_0042:  stloc.1
IL_0043:  ret
} // end of method Program::Main

A quick look at the IL code should tell you which algorithm is fastest…and you don't even have to be a rocket surgeon.

But, of course, as any seasoned developer will tell you: "It's the maintenance stupid!"

I hope you find this helpful.

Steve Wellens

[Update]

My friend Svante pointed out to me that it is the JIT that does the final optimization and you can’t really go by IL to determine which algorithms are quicker.  He is correct.

To look at the JIT output…

Go to Tools->Options->Debugging->General and unclick "Suppress JIT optimization on module load."  You want the optimization.
Add a breakpoint to the code. Run the program, when the breakpoint hits, right-click the source code and select "Go to Disassembly."   I removed the "markers" because they are no longer needed.

JIT Output (edited):

if (MyString == String.Empty)
00000050  mov         edx,dword ptr ds:[02CC102Ch]
00000056  mov         ecx,dword ptr [ebp-40h]
00000059  call        6A625FB8
0000005e  mov         dword ptr [ebp-4Ch],eax
00000061  cmp         dword ptr [ebp-4Ch],0
00000065  sete        al
00000068  movzx       eax,al
0000006b  mov         dword ptr [ebp-48h],eax
0000006e  cmp         dword ptr [ebp-48h],0
00000072  jne         0000007E
MyInt = 1;
00000074  mov         dword ptr [ebp-44h],1
0000007b  nop
0000007c  jmp         00000085
else
MyInt = 2;
0000007e  mov         dword ptr [ebp-44h],2

MyInt = MyString == String.Empty ? 1 : 2;
0000008c  mov         edx,dword ptr ds:[02CC102Ch]
00000092  mov         ecx,dword ptr [ebp-40h]
00000095  call        6A625FB8
0000009a  mov         dword ptr [ebp-50h],eax
0000009d  cmp         dword ptr [ebp-50h],0