.NET Code Optimization
For code efficiency, C++ has the best optimizer of any .NET language
One of the questions I often get asked is "Why use managed C++?" I usually give the C++ interop story as my answer, and this satisfies many questioners. However, some people reply that they do not need any interop, so then I go onto the next answer—optimization. The C# compiler does have a code optimizer, but there are no options about how it works, so you can either run the compiler with the optimizer or without it. The C# compiler is also new technology, so you can imagine that the technology hasn’t matured to the point that all optimization techniques have been exploited. On the other hand, the C++ compiler is a mature product and the C++ team has had the opportunity over many years (this year is the 10th anniversary of the Microsoft C++ compiler) to try different optimization techniques. Furthermore, the compiler gives you the option to optimize for speed or size.
Now let’s throw in another optimizer. The .NET JIT compiler includes an optimizer that will be applied to all IL except assemblies built for debugging. Compilers will add the assembly level [Debuggable] attribute to debugging code, and this has a property called IsJITOptimizerDisabled, which will be set to True so that the debugger can relate the IL to the source code easier. If this field is set to False, or the attribute is missing, then the optimizer will be run by the JIT compiler as it compiles the IL. This assumes that the assembly is built specifically for debugging, but in the rare case that you want to debug a release build assembly (assuming you have symbols), you can turn off the optimizer using an ini file. This file takes the same name as the process (so app.exe has an ini file called app.ini) and it is located in the same folder as the process. This ini file has a similar structure to other Windows ini files, the optimizer is controlled through a section called [.NET Framework Debugging Control], and a value called AllowOptimize can be set to a value of 0 to disable the optimizer.
Clearly the JIT optimizer is important, but code compiler optimizers also play a part because they provide the IL used by the JIT optimizer and they have more information about what the code should do. Comparing the actions of compiler optimizers is difficult; however, I will give a few general observations. The first point I should make is that the C++ compiler does extensive checks on the code to determine which code will actually be called. If you create a library assembly (DLL), the compiler will only include private classes if the C++ class is actually used directly, or indirectly, by code that is part of a public class. On the other hand, the C# compiler will add all classes to the resultant library, which will clearly make the library larger than it should be. However, it is interesting to note that both the C++ compiler and the C# compiler will include private methods, even if those methods are not called by public or protected methods.
The C++ compiler inspects the code that you have provided. If it determines that code will not be called or that it does not do anything useful, the optimizer will remove that code. For example:
int j = 0;
for (int i = 0; i < 100; i++)
The C++ compiler will compile the function but the optimizer will remove all code because clearly, the value of j is never used. While doing tests on the optimizers I found this action very irritating because the optimizer removed most of the code I was trying to test! The C# compiler, on the other hand, will include code that clearly does nothing useful (like the code above). Of course, the function NothingUseful() has a bad side effect: When code runs this method, extra CPU cycles will be wasted.
The lesson to be learned is that now that managed C++ can create verifiable assemblies, there are no reasons not to use it for much of your code. Since C++ has a far more efficient optimizer than any of the other .NET languages, it makes sense that C++ should always be your first choice in any situation where efficiency is important.