WHy is C# so much slower than c++???

J

jimocz

Did I do something wrong? I cross posted this on the dotnet
development group -- sorry if it is a double posting but we are
seriously considering going to c# and this could be a show stopper.

I ran the following C# program and it ran in 9 seconds (give or take 1
sec)

using System;
using System.Collections.Generic;
using System.Text;

namespace DotProduct1Million
{
class Program
{
static void Main(string[] args)
{

double d1 = 0.727272;
double d2 = 0.26252;
double d3 = 343432.232;
Console.WriteLine(" {0}", System.DateTime.Now);
for (long i = 0; i < 2000000000; i++)
{
d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
}
Console.WriteLine(" {0}", System.DateTime.Now);
}
}

}

I ran the following C++ program -- it ran in under 1 second. Is C#
really that much slower than C++????
What is the problem here?

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main(int argc,char *argv[])
{
double d1 = 0.727272;
double d2 = 0.26252;
double d3 = 343432.232;

cout << time(NULL) << endl;

for (long i = 0; i < 2000000000; i++)
{

d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
}
cout << time(NULL) << endl;
 
J

jimocz

okay -- chnaged some code a bit:
double d1 = 0.92;
double d2 = 1.34;
double d3 = 1.0;
Console.WriteLine(" {0}", System.DateTime.Now);
for (long i = 0; i < 2000000000; i++)
{
d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
if (d1 > 1.0e10) d1 = 9.0;
if (d2 > 9e10) d2 = 1.6;


This makes the times 12.6 secs for C++ and 15-16 seconds for C#.
Much more reasonable.
I suspect there was an underflow/overflow situation and the C++ code
stopped executing.

Still C# is still ~ 20% slower than C++. Managed C++ too!
 
B

Bruno van Dooren [MVP VC++]

This makes the times 12.6 secs for C++ and 15-16 seconds for C#.
Much more reasonable.
I suspect there was an underflow/overflow situation and the C++ code
stopped executing.

Still C# is still ~ 20% slower than C++. Managed C++ too!

Hi,
enable the optimizer in your C# project settings. It is disabled by default.
Then the C++.NET and C# results should be nearly identical.
Native C++ will probably a bit faster dues to lower memory overhead.

For more accurate timing you should use the StopWatch class, and not include
the Console.WriteLine statements in your time measurements. That will give
you ms accuracy or better.

As far as switching to C# goes: from personal experience I can say that
application development times and debugging times are much shorted in C#
than in native C++ or even C++.NET.
YMMV.

--

Kind regards,
Bruno van Dooren
(e-mail address removed)
Remove only "_nos_pam"
 
W

Willy Denoyette [MVP]

for(long i = 0...
in C#
and
for(long i = 0...
in C++ are not the same loops. A long in C# is 64 bit while in C++ it's a
32bit value.
Make i an int and you'll see that both will run at the same speed.


Willy.

| okay -- chnaged some code a bit:
| double d1 = 0.92;
| double d2 = 1.34;
| double d3 = 1.0;
| Console.WriteLine(" {0}", System.DateTime.Now);
| for (long i = 0; i < 2000000000; i++)
| {
| d3 = d1 * d2;
| d1 = d3 * d2;
| d2 = d2 * d2;
| d3 = d1 * d2;
| d3 = d3 * d2;
| if (d1 > 1.0e10) d1 = 9.0;
| if (d2 > 9e10) d2 = 1.6;
|
|
| This makes the times 12.6 secs for C++ and 15-16 seconds for C#.
| Much more reasonable.
| I suspect there was an underflow/overflow situation and the C++ code
| stopped executing.
|
| Still C# is still ~ 20% slower than C++. Managed C++ too!
|
|
|
| jimocz wrote:
| > Did I do something wrong? I cross posted this on the dotnet
| > development group -- sorry if it is a double posting but we are
| > seriously considering going to c# and this could be a show stopper.
| >
| > I ran the following C# program and it ran in 9 seconds (give or take 1
| > sec)
| >
| > using System;
| > using System.Collections.Generic;
| > using System.Text;
| >
| > namespace DotProduct1Million
| > {
| > class Program
| > {
| > static void Main(string[] args)
| > {
| >
| > double d1 = 0.727272;
| > double d2 = 0.26252;
| > double d3 = 343432.232;
| > Console.WriteLine(" {0}", System.DateTime.Now);
| > for (long i = 0; i < 2000000000; i++)
| > {
| > d3 = d1 * d2;
| > d1 = d3 * d2;
| > d2 = d2 * d2;
| > d3 = d1 * d2;
| > d3 = d3 * d2;
| > }
| > Console.WriteLine(" {0}", System.DateTime.Now);
| > }
| > }
| >
| > }
| >
| > I ran the following C++ program -- it ran in under 1 second. Is C#
| > really that much slower than C++????
| > What is the problem here?
| >
| > #include <iostream>
| > #include <cstdlib>
| > #include <ctime>
| >
| > using namespace std;
| >
| > int main(int argc,char *argv[])
| > {
| > double d1 = 0.727272;
| > double d2 = 0.26252;
| > double d3 = 343432.232;
| >
| > cout << time(NULL) << endl;
| >
| > for (long i = 0; i < 2000000000; i++)
| > {
| >
| > d3 = d1 * d2;
| > d1 = d3 * d2;
| > d2 = d2 * d2;
| > d3 = d1 * d2;
| > d3 = d3 * d2;
| > }
| > cout << time(NULL) << endl;
|
 
S

Shawn B.

Hi,
enable the optimizer in your C# project settings. It is disabled by
default.
Then the C++.NET and C# results should be nearly identical.
Native C++ will probably a bit faster dues to lower memory overhead.

For more accurate timing you should use the StopWatch class, and not
include the Console.WriteLine statements in your time measurements. That
will give you ms accuracy or better.

In addition, you might try running the loop once to warm up and JIT the
code, and then do your test once it has been fully JITd, since you're probly
seeing a certain amount of "warm-up" time while the IL code gets compiled
and it makes things looks slower (for such a small program its probly not
noticeable but still)... as well, run it RELEASE mode and not DEBUG mode...

You might also want to try changing the code to:

static void Main(string[] args)
{
double d1 = 0.727272;
double d2 = 0.26252;
double d3 = 343432.232;
Console.WriteLine(" {0}", System.DateTime.Now);

unchecked
{
for (long i = 0; i < 2000000000; i++)
{
d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
}
}
Console.WriteLine(" {0}", System.DateTime.Now);
}

By default the numerical operations are _checked_ which means the the
runtime will check for overflows. Changing it to unchecked in C# eliminates
that extra check and puts it on par with what the C++ code is actually
doing. You can change it in the project also (globally) but the code above
is just fine. I prefer to unchecked {...} my code where needed for the sake
of clarity when reading the code later.


Thanks,
Shawn
 
S

Shawn B.

Actually, executing the code in checked {...} vs. unchecked {...} really
doesn't make a whole lot of difference. However, running it in DEBUG (with
or without debugging) vs. RELEASE makes a huge difference.

For example, running in DEBUG with debugging takes 380 seconds, DEBUG
without debugging takes 56 seconds, and RELEASE without debugging takes 14
seconds.

The first iteration includes the JIT time and the second iterations is
already JIT'd.


Thanks,
Shawn




using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
private static void Main(string[] args)
{

for (int i = 0; i < 2 ; i++)
{
Console.WriteLine("Iteration {0} of 2", (i + 1));

Test1();
Test2();
}


Console.ReadLine();
}

private static void Test1()
{
double d1 = 0.727272;
double d2 = 0.26252;
double d3 = 343432.232;

System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();

checked
{
for (long i = 0; i < 2000000000; i++)
{
d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
}
}

watch.Stop();

Console.WriteLine("Test1: " + watch.Elapsed.TotalSeconds.ToString());
}

private static void Test2()
{
double d1 = 0.727272;
double d2 = 0.26252;
double d3 = 343432.232;

System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();

unchecked
{
for (long i = 0; i < 2000000000; i++)
{
d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
}
}

watch.Stop();

Console.WriteLine("Test2: " + watch.Elapsed.TotalSeconds.ToString());
}

}
}
 
W

Willy Denoyette [MVP]

As I said in another reply, you should make the loop counter an int instead
of a long (2000000000 fits in an int), incrementing a long (64 bit value in
C#) is more expensive than incrementing an int on a 32 bit CPU.
Also, when comparing C# performance against C++, you should keep in mind
that a long in C++ != long in C#.

Willy.

| Actually, executing the code in checked {...} vs. unchecked {...} really
| doesn't make a whole lot of difference. However, running it in DEBUG
(with
| or without debugging) vs. RELEASE makes a huge difference.
|
| For example, running in DEBUG with debugging takes 380 seconds, DEBUG
| without debugging takes 56 seconds, and RELEASE without debugging takes 14
| seconds.
|
| The first iteration includes the JIT time and the second iterations is
| already JIT'd.
|
|
| Thanks,
| Shawn
|
|
|
|
| using System;
| using System.Collections.Generic;
| using System.Text;
|
| namespace ConsoleApplication1
| {
| class Program
| {
| private static void Main(string[] args)
| {
|
| for (int i = 0; i < 2 ; i++)
| {
| Console.WriteLine("Iteration {0} of 2", (i + 1));
|
| Test1();
| Test2();
| }
|
|
| Console.ReadLine();
| }
|
| private static void Test1()
| {
| double d1 = 0.727272;
| double d2 = 0.26252;
| double d3 = 343432.232;
|
| System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
| watch.Start();
|
| checked
| {
| for (long i = 0; i < 2000000000; i++)
| {
| d3 = d1 * d2;
| d1 = d3 * d2;
| d2 = d2 * d2;
| d3 = d1 * d2;
| d3 = d3 * d2;
| }
| }
|
| watch.Stop();
|
| Console.WriteLine("Test1: " + watch.Elapsed.TotalSeconds.ToString());
| }
|
| private static void Test2()
| {
| double d1 = 0.727272;
| double d2 = 0.26252;
| double d3 = 343432.232;
|
| System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
| watch.Start();
|
| unchecked
| {
| for (long i = 0; i < 2000000000; i++)
| {
| d3 = d1 * d2;
| d1 = d3 * d2;
| d2 = d2 * d2;
| d3 = d1 * d2;
| d3 = d3 * d2;
| }
| }
|
| watch.Stop();
|
| Console.WriteLine("Test2: " + watch.Elapsed.TotalSeconds.ToString());
| }
|
| }
| }
|
|
 
J

jimocz

Okay,
I am running in release mode and I have changed the longs to doubles as
seen here:
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main(int argc,char *argv[])
{
double d1 = 0.92;
double d2 = 1.34;
double d3 = 1.0;
double i;

float now = clock()/(float)CLOCKS_PER_SEC;


for (i = 0; i < 6000000000.0; i+= 1.0)
{

d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
if (d1 > 1.0e10) d1 = 9.0;
if (d2 > 9e10) d2 = 1.6;

}
cout << "i = " << i << " Time to run CPP ==> " <<
(clock()/(float)CLOCKS_PER_SEC - now) << endl;

}


AND the C# code ::


using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace DotProduct1Million
{
class Program
{

static void Main(string[] args)
{
Stopwatch sw;
double d1 = 0.92;
double d2 = 1.34;
double d3 = 1.0;

sw = new Stopwatch();
sw.Start();

for (double i = 0; i < 6000000000.0; i+= 1.0)
{
d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
if (d1 > 1.0e10) d1 = 9.0;
if (d2 > 9e10) d2 = 1.6;

}
sw.Stop();
TimeSpan ts = sw.Elapsed;


string s = String.Format("{0:00}:{1:00}.{2:000}",
ts.Minutes, ts.Seconds,
ts.Milliseconds );

Console.WriteLine("Time with C# = {0}", s);
}
}
}

I have included the if statements to avoid any underflow/overflow
stuff.

The interesting thing is if I turn off optimization the C# code runs
faster. (81 secs to 121 secs)
However, if I turn on optimization the C++ code runs in 45 secs and C#
drops to 61 secs. I guess the C++ compiler is smarter than the C#
compiler!?

Thanks to all for the suggestions and help.

Jim
 
B

Bruno van Dooren [MVP VC++]

The interesting thing is if I turn off optimization the C# code runs
faster. (81 secs to 121 secs)
However, if I turn on optimization the C++ code runs in 45 secs and C#
drops to 61 secs. I guess the C++ compiler is smarter than the C#
compiler!?

Be aware that you are comparing apples and oranges.
IF you would compare C# with a C++/CLI application, they would be nearly
identical.
Number crunching is almost always going to be faster in a native
application.

--

Kind regards,
Bruno van Dooren
(e-mail address removed)
Remove only "_nos_pam"
 
J

jimocz

You are right on -- I compiled the C++ as managed code (I assume that
is CLI) and it was around 62 seconds.

This begs the question why is managed code so much slower than native?
I know you JIT compile it (that shouldn't affect the times since the
compile time is not included in the time) but is running in the virtual
machine following JIT 30% slower?

I suppose this is a major reason to maintain native C++ code --
computations.
 
W

Willy Denoyette [MVP]

jimocz said:
Okay,
I am running in release mode and I have changed the longs to doubles as
seen here:
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main(int argc,char *argv[])
{
double d1 = 0.92;
double d2 = 1.34;
double d3 = 1.0;
double i;

float now = clock()/(float)CLOCKS_PER_SEC;


for (i = 0; i < 6000000000.0; i+= 1.0)
{

d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
if (d1 > 1.0e10) d1 = 9.0;
if (d2 > 9e10) d2 = 1.6;

}
cout << "i = " << i << " Time to run CPP ==> " <<
(clock()/(float)CLOCKS_PER_SEC - now) << endl;

}


AND the C# code ::


using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace DotProduct1Million
{
class Program
{

static void Main(string[] args)
{
Stopwatch sw;
double d1 = 0.92;
double d2 = 1.34;
double d3 = 1.0;

sw = new Stopwatch();
sw.Start();

for (double i = 0; i < 6000000000.0; i+= 1.0)
{
d3 = d1 * d2;
d1 = d3 * d2;
d2 = d2 * d2;
d3 = d1 * d2;
d3 = d3 * d2;
if (d1 > 1.0e10) d1 = 9.0;
if (d2 > 9e10) d2 = 1.6;

}
sw.Stop();
TimeSpan ts = sw.Elapsed;


string s = String.Format("{0:00}:{1:00}.{2:000}",
ts.Minutes, ts.Seconds,
ts.Milliseconds );

Console.WriteLine("Time with C# = {0}", s);
}
}
}

I have included the if statements to avoid any underflow/overflow
stuff.

The interesting thing is if I turn off optimization the C# code runs
faster. (81 secs to 121 secs)
However, if I turn on optimization the C++ code runs in 45 secs and C#
drops to 61 secs. I guess the C++ compiler is smarter than the C#
compiler!?

Thanks to all for the suggestions and help.

Jim



Compiled both using the following compiler commands:
cl /EHsc /O2 filename.cpp

csc /o filename.cs

C++ code takes 36 sec. while the C# code took 39 sec. on my box. The difference is due to
the C++ back-end optimizer who can spend some more time to optimize the loop, something a
JIT compiler cannot afford. Anyway these kind of benchmarks have little value, really.


Willy.
 
W

Willy Denoyette [MVP]

jimocz said:
You are right on -- I compiled the C++ as managed code (I assume that
is CLI) and it was around 62 seconds.

This begs the question why is managed code so much slower than native?
I know you JIT compile it (that shouldn't affect the times since the
compile time is not included in the time) but is running in the virtual
machine following JIT 30% slower?

I suppose this is a major reason to maintain native C++ code --
computations.


Please, add the compiler the framework and OS versions used when comparing managed code
with unmanaged. Also specify your command-line arguments used, they can make the difference.
Also note that both C++ and C# (and all other managed code languages) use the same
underlying math library (CRT) to do floating point calculations (like mult, sqrt etc), the
CLR initializes the floating point unit in "precise" mode (same as cl option fp:precise -
assuming this is run as a 32 bit app.).
If you consider this, you'll understand that the performance figures should not differ that
much, and, as I showed you using an int as loop counter in your sample, there isn't any
difference at all.

Willy.
 
S

Shawn B.

I don't know whether you're target is 64-bit or 32-bit (or both)... but the
32-bit NGEN and JIT use the exact same algorithms. But for 64-bit CLR, NGEN
was actually created by the VC++ team and uses a much more heavily optimized
code generation since it is being compiled and not JITd but the 64-bit JIT
is maintained by the CLR team and does not as much optimizations.

If numerical crunching is paramount and 64-bit CPU is an option, try it on a
64-bit NGEN machine and see how it turns out vs. 64-bit JIT. My 64-bit CPU
is tied up with a 32-bit OS right now so I can't test.



Thanks,
Shawn
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top