I found out that there is real test than the little one I did here. The core of the post is this spreadsheet :
I recently did a basic comparison test between C++ (g++) and C# .Net (mono).
My point is to show that the .Net framework has performances close to the C++ ones. 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 (simplified code, no memory leak, optimal memory consumption)
- 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 nothing catches it
- Mono (and presumably the .Net framework) does some really interesting optimizations:
$ mono --list-opt
Here are some links related to interesting optimizations used by the Mono .Net framework:
Flag | Details |
---|---|
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 |
precomp | Precompile all methods before executing Main |
aot | Usage of Ahead Of Time compiled code |
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++ :
#include <iostream>
using namespace std;
long stupidThing( long nb ) {
long out = 1;
while( nb > )
out *= nb--;
return out;
}
int main() {
long total = ;
for( int i = ; i < 1000000; ++i )
for( long l = ; l < 100; ++l )
total += stupidThing( l );
cout << "Total : " << total << endl;
return ;
}
One in C#:
using System;
namespace test {
class Program {
static long stupidThing( long nb ) {
long ret = 1;
while ( nb > )
ret *= nb--;
return ret;
}
static void Main( string[] args ) {
long total = ;
for ( int i = ; i < 1000000; ++i )
for ( long l = ; 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 processes to mess with my tests :
$ rtprio 99 bash
Then I compile the two programs :
$ gmcs test.cs
$ g++ -O4 test.cpp -o test
And then I launch my test :
On a 64 bits host :
uname -a
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
$ 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 :
$ uname -a
Kernel : 2.6.30-2-686 #1 SMP Fri Dec 4 00:53:20 UTC 2009 i686 GNU/Linux
$ 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).