crushing java

  • Thread starter Thread starter Lloyd Dupont
  • Start date Start date
L

Lloyd Dupont

here a little test program.
it's so simple taht it should deliver simmilar result.
it's also so simple that people that might says it's unfair to the looser
(why Java people are always arguing like that ?)...

anyway see for yourself the test command lines:
javac SimplePerf.java && java SimplePerf 10000000
csc /nologo SimplePerf.cs && SimplePerf 10000000
 
Lloyd Dupont said:
here a little test program.
it's so simple taht it should deliver simmilar result.
it's also so simple that people that might says it's unfair to the looser
(why Java people are always arguing like that ?)...

Congratulations - you've shown that the JIT compiler for Java doesn't
spot that the call to Math.cos can be removed.

Now, how applicable do you believe that is? Are your programs full of
calls to trig methods which aren't actually relevant?


In fact, if you fix the program so it *does* use the value, .NET still
wins easily - but the fact that you thought this was even slightly
useful in its current form is somewhat interesting.

(I was running with JDK1.4.2; it would be interesting to try the IBM
JDK as that's traditionally been better for floating point stuff.)
 
As John said, there are a number of things that might explain this. And C# and Java is sufficiently different that comparing the two is difficult and in many cases pointless (Apples and Oranges).

Strange thing though, when trying to force Math.Cos do work in C# I added a double[10000000] array and stored each value in there. This increased the execution time for C# from 0-16 ms on my system to about 1.4 seconds. However, java was incapable of creating a double array of that size. ??? OutOfMemoryError

It would be interesting to see if someone on non Windows systems could run the code (or anyone using Windows).

My modified code is

C#

public static void Main(string[] args)
{
int N = int.Parse("10000000");
double[] d = new double[N];
long t0 = Environment.TickCount;
for(int i=0 ; i< N; i++)
{
d = Math.Cos(i);
}
Console.WriteLine(Environment.TickCount-t0);
}

Java

public static void main(String[] args)
{
int N = Integer.parseInt("10000000");
double[] d = new double[N];
long t0 = System.currentTimeMillis();
for(int i=0; i< N; i++)
{
d = Math.cos(i);
}
System.out.println(System.currentTimeMillis()-t0);
}
 
Morten Wennevik said:
As John said, there are a number of things that might explain this.
And C# and Java is sufficiently different that comparing the two is
difficult and in many cases pointless (Apples and Oranges).

Strange thing though, when trying to force Math.Cos do work in C# I
added a double[10000000] array and stored each value in there. This
increased the execution time for C# from 0-16 ms on my system to
about 1.4 seconds. However, java was incapable of creating a double
array of that size. ??? OutOfMemoryError

It's not an inability of Java to create the array - it's that the
maximum heap size is set to 64Mb by default. Run it with -Xmx128M to
give it 128MB instead.

However, rather than storing all the doubles, another way is to keep a
single double variable and add the result of Math.Cos to that on each
iteration. It's then testing floating point addition as well, of
course.
 
Yeah,
I initially stored a single double value, but was unsure if the compiler was smart enough to discover it only needed to do Math.Cos(9999999) and drop the rest (sometimes compilers can surprise :P). If only I had also thought of doing the addition.
 
Just curious: How does the JIT compiler know that Math.Cos *can* be removed,
i.e. that it has no side-effects, like changing a global variable, writing
to a file, or shutting down my computer? Is there some kind of attribute
that says "this function may be removed if it's return value is not used"?
Some programming languages have expressions for that, but I didn't know
there was a way for that in .NET IL.

Niki
 
Niki Estner said:
Just curious: How does the JIT compiler know that Math.Cos *can* be removed,
i.e. that it has no side-effects, like changing a global variable, writing
to a file, or shutting down my computer? Is there some kind of attribute
that says "this function may be removed if it's return value is not used"?
Some programming languages have expressions for that, but I didn't know
there was a way for that in .NET IL.

My *guess* is that this knowledge is built into the CLR, but that's
only a guess.
 
Jon Skeet said:
My *guess* is that this knowledge is built into the CLR, but that's
only a guess.

You mean that somewhere in the JIT code there's a line like "if
(function=="Math.Cos" && ! returnValue.used) continue;"? Would that kind of
optimization have any other use than faking benchmarks? I mean: what
'normal' program would call Math.Cos without using it's return value?
Wouldn't it make more sense e.g. to state a warning in that case, instead of
just removing the code?

Niki
 
Niki Estner said:
You mean that somewhere in the JIT code there's a line like "if
(function=="Math.Cos" && ! returnValue.used) continue;"?

Sort of, yes.
Would that kind of optimization have any other use than faking benchmarks?
I mean: what'normal' program would call Math.Cos without using it's return value?
Wouldn't it make more sense e.g. to state a warning in that case, instead of
just removing the code?

In this case, yes. I suspect there are situations where dead code is
present where it's not actually so obvious.

I could be entirely wrong, of course, and the JIT compiler could be
working it out by inlining it and then removing dead code as it
normally does. That would be a more flexible system, of course.
 
of course the compiler don't just remove a call.
it's incorrect to remove a function call !
at most does it inline it.
your reaction just proved you to be sentimental and self blinded

anyway, this proof can be canceled by another similar test:
using System;

public class ExceptPerf
{
public static void Main(string[] args)
{
int N = int.Parse(args[0]);
long t0 = Environment.TickCount;
for(int i=0; i< N; i++)
try{
throw new Exception();
}catch( Exception e )
{
;
}
Console.WriteLine((Environment.TickCount-t0));
}
}



public class ExceptPerf
{
public static void main(String[] args)
{
int N = Integer.parseInt(args[0]);
long t0 = System.currentTimeMillis();
for(int i=0; i< N; i++)
try{
throw new Exception();
}catch( Exception e )
{
;
}
System.out.println((System.currentTimeMillis()-t0));
}
}
 
Lloyd Dupont said:
of course the compiler don't just remove a call.
it's incorrect to remove a function call !

Not if the JIT compiler absolutely knows that it can have no effect on
anything other than performance.
at most does it inline it.

Really? I looked at the JITted code with cordbg. Did you?
I tried running your code without the call to Math.Cos, and got the
same results. Did you? Are you saying that Math.Cos calls are
absolutely free?
your reaction just proved you to be sentimental and self blinded

Whatever you say...
anyway, this proof can be canceled by another similar test:

On my box, that shows .NET throwing exceptions to be significantly
slower than Java. Of course, any system which is throwing hundreds of
thousands of exceptions ought to look at its design very carefully
anyway.

There are areas where .NET is faster than Java.
There are areas where Java is faster than .NET.
I really don't see why that's so hard to accept...
 
BTW, if needed, I didn't intended to be rude, I just believed you wrong.

additional comment below.

Jon Skeet said:
Not if the JIT compiler absolutely knows that it can have no effect on
anything other than performance.


Really? I looked at the JITted code with cordbg. Did you? No

I tried running your code without the call to Math.Cos, and got the
same results. Did you?
mmhh....
I just increased N and see it was slower.
now that it remove the Math.Cos call but let an empty loop, now that's
something puzzling !
Are you saying that Math.Cos calls are
absolutely free?
did I ?
Whatever you say...
it looked so at least ...
On my box, that shows .NET throwing exceptions to be significantly
slower than Java. Of course, any system which is throwing hundreds of
thousands of exceptions ought to look at its design very carefully
anyway.

There are areas where .NET is faster than Java.
There are areas where Java is faster than .NET.
I really don't see why that's so hard to accept...
I accept, I accept, didn't I ?
 
Lloyd Dupont said:
BTW, if needed, I didn't intended to be rude, I just believed you wrong.

I think whenever you say that someone's reaction proves them to be
"sentimental and self blinded" you're likely to be rude, to be honest.
mmhh....
I just increased N and see it was slower.
now that it remove the Math.Cos call but let an empty loop, now that's
something puzzling !

Not really - it's just as I said: the JIT is removing calls which it
knows are pointless. It does the same in other situations. For
instance, I believe if you do:

int[] x = new int[100];

for (int i=0; i < x.Length; i++)
{
DoSomethingWith(x);
}

it won't need to do both the Length check in the "for" condition *and*
the implicit bounds check on x, because it knows that if
0 < i < x.Length, x should be fine.

If you had done the tests without Math.Cos and still claimed the JIT
wasn't removing them, you'd have been implying that.
I accept, I accept, didn't I ?

I wasn't at all sure what your second test was meant to be showing as
you didn't say what results you got - but given the subject line of
"crushing Java" (and the denegration of Java developers in your first
post) you seemed to be under the impression that .NET was faster for
everything.
 
Back
Top