From: Jon Harrop on
Lew wrote:
> Jon Harrop wrote:
>> Type erasure forces all values to be cast to Object which forces value
>> types (like double) to be boxed into objects which is an allocation. The
>> JVM boxes all 20,000,000 of the doubles generated by this program whereas
>> the CLR boxes none of them. That is the "orders of magnitude" difference
>> I was referring to.
>
> That's not an issue of type erasure but of Java not supporting
> collections of primitive types. It is the autoboxing of 'double' to
> 'Double' that you discuss here, not the erasure of 'Double' to
> 'Object'.

Type erasure means that Java's generics cannot be used to improve the
performance of my benchmark.

> Type erasure has nothing to do with value types being boxed. The
> erasure from 'Double' to 'Object' has no further effect on
> performance.
>
> Others in this thread have tried to duplicate the degree of slowdown
> you report without being able to. No one else here seems to see a
> 32:1 ratio in performance.

Has anyone else here even benchmarked the F# code? If so, what performance
ratio did they get?

--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
From: Marcin Rzeźnicki on
On 23 Lis, 21:04, Jon Harrop <j...(a)ffconsultancy.com> wrote:
> Marcin Rzeźnicki wrote:
> > On 23 Lis, 17:11, Jon Harrop <j...(a)ffconsultancy.com> wrote:
> >> Lew wrote:
> >> > Jon Harrop wrote:
>
> >> Type erasure forces all values to be cast to Object which forces value
> >> types (like double) to be boxed into objects which is an allocation. The
> >> JVM boxes all 20,000,000 of the doubles generated by this program whereas
> >> the CLR boxes none of them. That is the "orders of magnitude" difference
> >> I was referring to.
>
> > That's not true Jon. Type erasure does not force anything in your
> > example - you even did not use generics at all, so how can it affect
> > anything?
>
> Type erasure prevents generics from helping on the JVM as they do on the
> CLR.
>

In your case I cannot see generics used at all.

> > The problem here is that Java lacks value types which is orthognal to
> > generics implementation
>
> The non-generic F# solution is roughly as slow as the Java. Only the generic
> F# solution is faster.
>

So you are running different program than you showed us. But that's
not the point. The point is that the only thing which may make it run
so fast is the presence of value types. Which still has nothing to do
with type erasure. Type erasure does not forbid compiler from making
this kind of optimization which you've been talking about.

> >> > It simply means that a parametrized type is treated as an 'Object' by
> >> > the JVM.
> >> > It affects the number of casts, which may be affected by the HotSpot
> >> > optimizer.
>
> >> Casting a primitive type to Object incurs an allocation.
>
> > Not necessarily - Java specification permits caching instances of
> > boxed numerics.
>
> Sure. That obviously isn't helping on this benchmark.
>

Yes, unfortunately.

> >> > If you allocate, say, a 'Set<Foo>' then fill it with 1000 'Foo'
> >> > instances, you have 1001 allocations plus however many allocation/copy
> >> > operations are necessary to grow the 'Set' to hold 1000 references (six
> >> > with a typical default initial size, zero if you made it big enough to
> >> > hold 1000).  Type erasure has nothing to do with it - you're still
> >> > creating only 'Foo' objects and enough 'Set' slots to refer to them.
>
> >> You are assuming that Foo is an object which is not true in general and
> >> is not true in this case.
>
> > It is true in general,
>
> In this case, Foo is double which is not an object and Lew's statements do
> not apply.
>

Ok, nevermind. It is not relevant to our discussion I suppose (his
assumption that "Foo is an object" IS true)

> > furthermore it is always true in F# or any  
> > language implemented on top of CLR where there is no notion of
> > "primitive type".
>
> My program is a counter example. In general, the CLR's notion of value types
> are equivalent to the JVM's primitive types.
>

No, it is not. Value types can be heap-allocated while primitives
cannot.

> > The thing we should discuss after filtering half-
> > truths out is whether difference between value types and reference
> > types might cause 32x performance degradation
>
> When using reference types, F# is roughly as slow as Java. The difference
> occurs when a generic data structure is parameterized over a value type.
>

Could you please take a look at my benchmark (it states that slowdown
should be ~30%) and, if you have access to a machine with NetBeans (or
any Java profiler), and perform similar profiling on your own? I am
suspecting there is something more than than meets the eye.



From: Lew on
Jon Harrop wrote:
> Copying a few bytes of data is a *lot* faster than allocating a few bytes of
> data.
>

According to sun.com and Brian Goetz's articles on DeveloperWorks,
object allocation in Java (discounting GC) is an O(1) operation
involving 10-12 machine instructions.
<http://www.ibm.com/developerworks/java/library/j-jtp09275.html>
"The answer may surprise you -- allocation in modern JVMs is far
faster than the best performing malloc implementations. The common
code path for new Object() in HotSpot 1.4.2 and later is approximately
10 machine instructions (data provided by Sun; see Resources),"

--
Lew
From: Marcin Rzeźnicki on
On 23 Lis, 21:31, Jon Harrop <j...(a)ffconsultancy.com> wrote:
> Patricia Shanahan wrote:
> > Marcin Rzeźnicki wrote:
> >> Now, the interesting part is
> >> 30.3% of time spent in java.lang.Double.valueOf(double) <--- that's
> >> boxing
> >> Furthermore, there were 2m + 1 calls to new Double meaning that no
> >> caching occurred.
>
> > Interesting results. That is about what I would expect. If we were
> > trying to explain a 30% performance difference I would seriously
> > consider autoboxing as cause. If creating an Entry takes about as much
> > time as creating a Double, object creation could account for up to 45%
> > of the Java time.
>
> > The problem is explaining a 32x performance difference. The cause or
> > causes have to account for over 96% of the Java time.
>
> I think the bottleneck must be the GC by a long long way. Look at this:
>
> $ time java Hashtbl -Xmx800m
> hashtable(100.0) = 0.01
>
> real    0m34.676s
> user    1m55.723s
> sys     0m3.332s
>
> The CPU time taken is actually ~100x worse than for F#. Given that this is a
> serial benchmark, that parallelism could only have come from the GC.
>

When I was running mine I observed that only ~6% of time was marked as
spent in GC and even that only if I allocated too little space for the
heap (then, right before OutOfMemory it started to reclaim space
wildly but, of course, failed). When I set heap to -Xms512m -Xmx512m
GC time was negligibly small. I wonder what would happened if you
repeated your tests with -Xms800m -Xmx800m.

From: Jon Harrop on
Marcin Rzeźnicki wrote:
> In your case I cannot see generics used at all.

In the F#?

>> The non-generic F# solution is roughly as slow as the Java. Only the
>> generic F# solution is faster.
>
> So you are running different program than you showed us.

I showed you the generic F# program that is 32x faster than the Java
program.

> But that's
> not the point. The point is that the only thing which may make it run
> so fast is the presence of value types.

Perhaps you mean that without generics but with value types you could obtain
the same performance by writing a type specialized DoubleDoubleHashMap? I'd
agree with that. My point was that using a non-generic Hashtable in F#
destroys its performance.

> Which still has nothing to do
> with type erasure. Type erasure does not forbid compiler from making
> this kind of optimization which you've been talking about.

The VM cannot type specialize data structures if the type information has
been erased.

>> > furthermore it is always true in F# or any
>> > language implemented on top of CLR where there is no notion of
>> > "primitive type".
>>
>> My program is a counter example. In general, the CLR's notion of value
>> types are equivalent to the JVM's primitive types.
>
> No, it is not. Value types can be heap-allocated while primitives
> cannot.

Local value/primitive types are stack allocated. Heap allocated reference
types may contain value/primitive types.

>> > The thing we should discuss after filtering half-
>> > truths out is whether difference between value types and reference
>> > types might cause 32x performance degradation
>>
>> When using reference types, F# is roughly as slow as Java. The difference
>> occurs when a generic data structure is parameterized over a value type.
>
> Could you please take a look at my benchmark (it states that slowdown
> should be ~30%)

No, it shows that ~30% of the time is spent allocating in the mutator. It
says nothing about how much time is spent collecting in the GC. Given that
this benchmark spends half of its time burning all eight of my cores, I
think collection must be the bottleneck.

--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
First  |  Prev  |  Next  |  Last
Pages: 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Prev: The future of Java
Next: weird issue with new lines