I found out that there is real test than the little one i did here. In fact the main interest of the post is this spreadsheet :
I recently did a simple and stupid comparison test between C++ (g++) and C# .Net (mono).
My point here is that C# can actually be considered as a very fast language. It allows automatic hardware-specific optimization. The only real drawback you have in the .Net framework is the garbage collector. It prevents the C# .Net it from being a realtime language/framework. But does it really matter for you ?
The purpose of the following test is to show that C++ isn’t faster than C# “as is”. I KNOW C# can not be faster than C++ because C# can do few hardware specific optimizations when you can do all of them in C++, because all the systems calls have to be done in C/C++ and because there’s no such thing like Template and forced inlining in C#.
But if you’re searching for arguments to choose C# .Net over native C++, you should also consider these :
- C# is much more simple. No headers, the languages specifications are simple and clear
- You don’t have to manage the memory in .Net (no memory leak, optimal memory consumption, etc.)
- C# code is as portable as java, it doesn’t need to be manually ported to a new architecture like C++
- .Net don’t just crash, they always throw an exception and they only crash if nobody catches it
- Mono (and presumely the .Net framework) does some really interesting optimizations :
1
# mono --list-opt
I put some link so that you can learn about these really interesting optimization. This is like design patterns, you should really know these things.
peephole Peephole postpass branch Branch optimizations inline Inline method calls cfold Constant folding consprop Constant propagation copyprop Copy propagation deadce Dead code elimination linears Linear scan global reg allocation cmov Conditional moves shared Emit per-domain code sched Instruction scheduling intrins Intrinsic method implementations tailc Tail recursion and tail calls loop Loop related optimizations fcmov Fast x86 FP compares leaf Leaf procedures optimizations aot Usage of Ahead Of Time compiled code precomp Precompile all methods before executing Main abcrem Array bound checks removal ssapre SSA based Partial Redundancy Elimination exception Optimize exception catch blocks ssa Use plain SSA form sse2 SSE2 instructions on x86 gshared Share generics simd Simd intrinsics - Multithreading in .net is much easier than any other language. You even have the parrallel loop operations, like Parallel.For.
SO ! Here is the test…
I wrote these two sample programs :
One in C++ :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <iostream> using namespace std; long stupidThing( long nb ) { long out = 1; while( nb > 0 ) out *= nb--; return out; } int main() { long total = 0; for( int i = 0; i < 1000000; ++i ) for( long l = 0; l < 100; ++l ) total += stupidThing( l ); cout << "Total : " << total << endl; return 0; } |
One in C# :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | using System; namespace test { class Program { static long stupidThing( long nb ) { long ret = 1; while ( nb > 0 ) ret *= nb--; return ret; } static void Main( string[] args ) { long total = 0; for ( int i = 0; i < 1000000; ++i ) for ( long l = 0; l < 100; ++l ) total += stupidThing( l ); Console.WriteLine( "Total : {0}", total ); } } } |
First of all, I open a shell in real-time priority, because I don’t want my other processses to mess with my tests :
1 | # rtprio 99 bash |
Then I compile the two programs :
1 2 | # gmcs test.cs # g++ -O4 test.cpp -o test |
And then I launch my test :
On a 64 bits host :
1 | Kernel : 2.6.9-023stab051.3-smp #1 SMP Wed Nov 4 18:36:34 MSK 2009 x86_64 x86_64 x86_64 GNU/Linux |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # time ./test ; time ./test ; time ./test ; time mono test.exe ; time mono test.exe ; time mono test.exe Total : -6192109806162068864 real 0m12.433s user 0m12.394s sys 0m0.049s Total : -6192109806162068864 real 0m12.415s user 0m12.411s sys 0m0.014s Total : -6192109806162068864 real 0m12.430s user 0m12.411s sys 0m0.026s Total : -6192109806162068864 real 0m10.311s user 0m10.287s sys 0m0.029s Total : -6192109806162068864 real 0m10.254s user 0m10.247s sys 0m0.011s Total : -6192109806162068864 real 0m10.250s user 0m10.255s sys 0m0.012s |
C# clearly beats C++ here. Well
On a 32 bits host :
1 | Kernel : 2.6.30-2-686 #1 SMP Fri Dec 4 00:53:20 UTC 2009 i686 GNU/Linux |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # time ./test ; time ./test ; time ./test ; time mono test.exe ; time mono test.exe ; time mono test.exe Total : 100461056 real 1m10.927s user 1m7.376s sys 0m0.056s Total : 100461056 real 1m12.590s user 1m8.976s sys 0m0.020s Total : 100461056 real 1m13.279s user 1m9.532s sys 0m0.056s Total : -6192109806162068864 real 2m22.492s user 2m15.260s sys 0m0.136s Total : -6192109806162068864 real 2m23.002s user 2m15.760s sys 0m0.104s Total : -6192109806162068864 real 2m25.102s user 2m17.709s sys 0m0.144s |
C++ beats C# here, but in 32 bits C++ use other types whereas C# use the same. In C# long is always 64 bits, in C++ it can be 64 bits or 32 bits (depending on the current architecture).