Very strange .NET 2 behaviour (compilation result)
Hello all,
I'm using:
Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.42
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
But have confirmed the problem with the 1.0 framework too.
I've been trying to find out why some doubles operations weren't going so fast and i ended up with the following test case:
using System;
namespace Benchmark_CSharp
{
class BenchmarkCSharp
{
static DateTime startTime;
static DateTime stopTime;
static TimeSpan elapsedTime;
static void Main()
{
long elapsedMilliseconds;
startTime = DateTime.Now;
double doubleResult = 10000000000.0D;
double i = 10000000000.0D;
while (i < 11000000000.0D) {
doubleResult -= i++;
doubleResult += i++;
doubleResult *= i++;
doubleResult /= i++;
}
stopTime = DateTime.Now;
elapsedTime = stopTime.Subtract(startTime);
elapsedMilliseconds = (int)elapsedTime.TotalMilliseconds;
Console.WriteLine("Double time: " + elapsedMilliseconds+" ms");
//Console.WriteLine(" i: " + i); Console.WriteLine(" doubleResult: " + doubleResult);
}
}
}
Try uncommenting the last line.
For me these are the results:
with: Double arithmetic elapsed time: 1937 ms
without: Double arithmetic elapsed time: 7078 ms
For some reason, it seems the compiler does something that really slows down badly everything just because of these WriteLine.
Any ideas as to what to do/how to avoid that/if it's a bug?
Best Regards,
Paul-Kenji Cahier
[1607 byte] By [
pkcahier] at [2007-12-28]
Hi,
I've been able to reproduce this with the exact same code, and I'm absolutely baffled.
I'm running the same compiler, same framework, and a P4 2.4 HT.
Calling this at the end of the method in place of the WriteLines causes the same effect:
double j = doubleResult;
j++;
However, this doesn't:
double j = doubleResult;
j = 0;
Weird!
"Now the subsequent question that comes to mind is... why are doubles in c# so slow?
I compared to a c++ version of the same program, and it is roughly 2-3 times faster..."
That's because the .NET code generator (JIT) is not as good as a C/C++ compiler code generator at optimizing things. It has to trade optimizations over code generation speed.
The main difference for floating point ops is that the C/C++ compiler generates code that makes use of the floating point registers in the FPU inside the loop while the .NET code generator spills everything to memory. If you are using VC++ 2005 to compile the C++ code there is a compiler option (/fp:strict) that makes the compiler generate similar code.
?
style="PADDING-RIGHT: 0px; PADDING-LEFT: 5px; MARGIN-LEFT: 5px; BORDER-LEFT: #000000 2px solid; MARGIN-RIGHT: 0px">
This post has been edited either by the author or a moderator in the Microsoft
Forums: http://forums.microsoft.com
id=_ctl0_MainContent_PostFlatView>After checking it appears it's optimizations that cause the problem.
The fact is that apparently when
it doesnt need the value after, it simply ignores it, making the calculations
much faster.
Adding a write of it of course forces it to do the
calculations.
But saying j=0 will of course not need to have the
value of it before whereas +1 does.
Hence what happened.
Now the
subsequent question that comes to mind is... why are doubles in c# so
slow?
I compared to a c++ version of the same program, and it is roughly
2-3 times faster...
Here is the code for it:
#include
<time.h>
#include <stdio.h>
void main()
{
double elapsedTime;
clock_t stopTime; clock_t startTime = clock();
double doubleResult = 10000000000.0;
double i =
10000000000.0;
while (i < 11000000000.0)
{
doubleResult -=
i++;
doubleResult +=
i++;
doubleResult *=
i++;
doubleResult /=
i++;
}
stopTime = clock();
elapsedTime = (stopTime - startTime) / (CLOCKS_PER_SEC / (double)
1000.0);
printf("CPP Double arithmetic elapsed
time: %1.0f ms\n", elapsedTime);
printf(" i: %f\n",
i);
printf(" doubleResult: %.15f\n",
doubleResult);
}
Following C# optimized build (/o+) runs exactly as fast as the "C" version compiled with /O2.
Result: 10011632717,4955, Elapsed time: 00:00:03.5780563
CPP Double arithmetic elapsed time: 3578 ms
i: 11000000000.000000
doubleResult:
10011632717.495501000000000
// The code: compile with csc /o
class Program
{
static void Main()
{
DateTime start =
DateTime.Now;
double doubleResult =
10000000000.0;
double i =
10000000000.0;
while (i < 11000000000.0)
{
doubleResult -= i++;
doubleResult += i++;
doubleResult *=
i++;
doubleResult /= i++;
}
TimeSpan elapsed = DateTime.Now -
start;
Console.WriteLine("Result: {0}, Elapsed time: {1}",
doubleResult, elapsed);
}
}
Guess is that you are comparing release builds with debug builds.
Willy.