Last weekend, I enjoyed a (very) heated Java vs C# argument between some of my friends. C++ folks also pitched in for good measure and I had over an hour of good entertainment.
The C++ folks had a very strong argument that the C++ compilers are better than the rest and produce better executable code than any other.
This one thought stuck with me … how smart are the compilers really? While one may consider that C++ may be better for things that require raw computing power like graphics and games, what is the difference for trivial/typical code?
I have VS2008 installed on my laptop so decided to test out how the C++, C# and VB.NET compilers fare for very simple code. The code was trivial as well as written in a way that optimizations should be obvious. The C++, C#, VB.NET projects were
all created with default settings and used to create RELASE versions of the executables. No tweaking of any settings was done so that it is clear how the compilers behave out-of-the-box.
The code used was:
C/C++
#include <stdio.h> #include <windows.h> #include <math.h> void main() { double _root; long _start = GetTickCount(); for (long i=0; i<1000000000; i++) { _root = sqrt((double)i); } long _end = GetTickCount(); long _duration = _end - _start; printf("It took %d milli-seconds to run the loop", _duration); getchar(); }
C#
using System; namespace TestOpt { class Program { static void Main(string[] args) { double _root; DateTime _start = DateTime.Now; for (long i = 0; i < 1000000000; i++) { _root = Math.Sqrt(i); } DateTime _end = DateTime.Now; TimeSpan _duration = _end - _start; Console.WriteLine("It took {0} milli-seconds to run the loop", _duration.TotalMilliseconds); Console.ReadKey(); } } }
VB.NET
Module Module1 Sub Main() Dim _root As Double Dim _start As DateTime = DateTime.Now For i As Long = 0 To 1000000000 _root = Math.Sqrt(i) Next Dim _end As DateTime = DateTime.Now Dim _duration As TimeSpan = _end - _start Console.WriteLine("It took {0} milli-seconds to run the loop", _duration.TotalMilliseconds) Console.ReadKey() End Sub End Module
The FOR loop is used to calculate a Square-root that is never used. So the compiler should ignore the loop and the expected output is that the code runs in ZERO time.
Running the release versions gave the following:
C/C++: It took 0 milli-seconds to run the loop VB.NET: It took 27397.231 milli-seconds to run the loop C#: It took 24472.447 milli-seconds to run the loop
The C/C++ compiler has done the expected and ignored the loop. I was stunned to see that the two .NET compilers did not optimize out the loop even in the RELEASE versions.
Double checking the generated executable code:
C/C++
; 10 :
; 11 : for (long i=0; i<1000000000; i++)
; 12 : {
; 13 : _root = sqrt((double)i);
; 14 : }
; 15 :
; 16 : long _end = GetTickCount();
Sure enough, no code generated for the loop.
C# IL_000d: call float64 [mscorlib]System.Math::Sqrt(float64) VB.NET IL_000d: call float64 [mscorlib]System.Math::Sqrt(float64)
The output for C# and VB.NET both run the loop and have the calls to “Sqrt”.
Why don’t the .NET compilers do what the C/C++ compiler from the same Visual Studio suite can do? Even though VS 2008 is not the latest and greatest, it targets .NET 3.5 and is mature enough to expect basic optimizations.