The code I run is attached in the mail copy it to your env and run it
and flip the testLambda from true to false.

I might have been something dumb wrong but this is what I came up with.

Tom

On 24.03.14 23:31, Kevin Rushforth wrote:
> Those results are surprising. Is this an apples-to-apples comparison
> with the only difference being a Lambda versus an equivalent anonymous
> inner class?
> 
> -- Kevin
> 
> 
> Tom Schindl wrote:
>> Hi,
>>
>> I've written a small sample to see what it gets me to check:
>> * creation overhead
>> * memory overhead
>> * call overhead
>>
>> I'm not very good at this kind of thing so someone who knows to write
>> benchmarks might know a lot better - need to check out JMH most likely.
>>
>> Anyways here are the numbers:
>>
>> Topic                Lambda                  Subclass
>> --------------------------------------------------------------
>> Create10M    372ms (0.00003723)      220ms (0.00002205)
>> Mem          108byte / instance      84byte / instance
>> Call-1M*10   42ms (0.0000042)        35ms (0.0000035)
>> Call-1*1M    11ms (0.0000011)        10ms (0.0000010)
>>
>> So Lamda is considerable slower 40% and takes 20% more space, call
>> behavior is fairly the same. I'll try to learn about JMH.
>>
>> Tom
>>
>>
>>   
>>> package hello;
>>>
>>> import java.util.ArrayList;
>>> import java.util.List;
>>> import java.util.concurrent.atomic.AtomicInteger;
>>> import java.util.function.Consumer;
>>>
>>> import javafx.beans.property.ObjectProperty;
>>> import javafx.beans.property.ObjectPropertyBase;
>>> import javafx.beans.property.SimpleObjectProperty;
>>>
>>> public class TestMemory {
>>>     private static int oneIteration = 1_000_000;
>>>     private static int iterationCount = 10;
>>>     private static int invokationOverheadCallCount = 1_000_000; 
>>>     
>>>     private static boolean testLambda = false;
>>>     
>>>     private static void testLambda(int iterations, List<TestObject> 
>>> storage) {
>>>             for( int i = 0; i < iterations; i++ ) {
>>>                     storage.add(new SimpleLambdaBean());
>>>             }
>>>     }
>>>     
>>>     private static void testSubclass(int iterations, List<TestObject> 
>>> storage) {
>>>             for( int i = 0; i < iterations; i++ ) {
>>>                     storage.add(new SimpleSubclassBean());
>>>             }
>>>     }
>>>     
>>>     public static void main(String[] args) {
>>>             System.err.println("Test Creation time");
>>>             System.err.println("==================");
>>>             
>>>             {
>>>                     long timeDiffTotal = 0;
>>>                     for( int i = 0; i < iterationCount; i++ ) {
>>>                             System.err.println("    Working for objects: " 
>>> + (i * oneIteration) + " - " + ((i+1) * oneIteration) );
>>>                             System.err.println("    
>>> ---------------------------------");
>>>                             long s = System.currentTimeMillis();
>>>                             if( testLambda ) {
>>>                                     testLambda(oneIteration, new 
>>> ArrayList<>());
>>>                             } else {
>>>                                     testSubclass(oneIteration, new 
>>> ArrayList<>());
>>>                             }
>>>                             long e = System.currentTimeMillis();
>>>                             long diff = e - s;
>>>                             
>>>                             timeDiffTotal+=diff;
>>>                             System.err.println("    Creation time: " + diff 
>>> + "("+diff * 1.0 / oneIteration+")");
>>>                             
>>>                             System.err.println("    
>>> ---------------------------------");
>>>                     }
>>>                     
>>>                     System.err.println("    Average time: " + timeDiffTotal 
>>> * 1.0 / (iterationCount * oneIteration));
>>>             }
>>>             
>>>             List<TestObject> target = new 
>>> ArrayList<TestObject>(iterationCount * oneIteration);
>>>             
>>>             {
>>>                     System.err.println("");
>>>                     System.err.println("Test Creation memory");
>>>                     System.err.println("==================");
>>>
>>>                     for( int i = 0; i < iterationCount; i++ ) {
>>>                             System.err.println("    Working for objects: " 
>>> + (i * oneIteration) + " - " + ((i+1) * oneIteration) );
>>>                             System.err.println("    
>>> ---------------------------------");
>>>                             if( testLambda ) {
>>>                                     testLambda(oneIteration, target);
>>>                             } else {
>>>                                     testSubclass(oneIteration, target);
>>>                             }
>>>                             
>>>                             long freeDiff = 
>>> Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
>>>                             System.err.println("    Memory: " + freeDiff + 
>>> "("+freeDiff * 1.0 / target.size()+")");                         
>>>                             System.err.println("    
>>> ---------------------------------");
>>>                     }
>>>                     
>>>                     System.err.println("    Total objects created: " + 
>>> target.size());
>>>             }
>>>             
>>>             {
>>>                     System.err.println("");
>>>                     System.err.println("Test invokation overhead (all then 
>>> times)");
>>>                     
>>> System.err.println("=========================================");
>>>                     
>>>                     long s = System.currentTimeMillis();
>>>                     for( int i = 0; i < oneIteration; i++ ) {
>>>                             target.get(i).invalidate();
>>>                     }
>>>                     long e = System.currentTimeMillis();
>>>                     long diff = e - s;
>>>                     System.err.println("    Total time calls: " + diff);
>>>                     System.err.println("    Time per call: " + diff * 1.0 / 
>>> invokationOverheadCallCount);                   
>>>             }
>>>             
>>>             {
>>>                     System.err.println("");
>>>                     System.err.println("Test invokation multiple times");
>>>                     System.err.println("===============================");
>>>                     long s = System.currentTimeMillis();
>>>                     
>>>                     for( int i = 0; i < invokationOverheadCallCount; i++ ) {
>>>                             
>>>                     }
>>>                     long e = System.currentTimeMillis();
>>>                     long diff = e - s;
>>>                     System.err.println("    Total time calls: " + diff);
>>>                     System.err.println("    Time per call calls: " + diff * 
>>> 1.0 / invokationOverheadCallCount);
>>>             }
>>>             
>>>     }
>>>
>>>     public static class LamdaInvalidationProperty<T> extends 
>>> SimpleObjectProperty<T> {
>>>             private Consumer<LamdaInvalidationProperty<T>> c;
>>>             
>>>             public LamdaInvalidationProperty(Object bean, String name, 
>>> Consumer<LamdaInvalidationProperty<T>> c) {
>>>                     super(bean, name);
>>>                     this.c = c;
>>>             }
>>>             
>>>             @Override
>>>             protected void invalidated() {
>>>                     c.accept(this);
>>>             }
>>>     }
>>>     
>>>     public interface TestObject {
>>>             public void invalidate();
>>>     }
>>>     
>>>     public static class SimpleLambdaBean implements TestObject {
>>>             private AtomicInteger i = new AtomicInteger();
>>>             
>>>             private ObjectProperty<Object> sample = new 
>>> LamdaInvalidationProperty<>(this, "sample", (e) -> {
>>>                     i.incrementAndGet();
>>>             });
>>>             
>>>             public void invalidate() {
>>>                     sample.setValue(new Object());
>>>             }
>>>     }
>>>     
>>>     public static class SimpleSubclassBean implements TestObject {
>>>             private AtomicInteger i = new AtomicInteger();
>>>             
>>>             private ObjectProperty<Object> sample = new 
>>> ObjectPropertyBase<Object>() {
>>>                     @Override
>>>                     public Object getBean() {
>>>                             return SimpleSubclassBean.this;
>>>                     }
>>>                     
>>>                     public String getName() {
>>>                             return "sample";
>>>                     }
>>>                     
>>>                     public Object getValue() {
>>>                             return null;
>>>                     }
>>>                     
>>>                     protected void invalidated() {
>>>                             i.incrementAndGet();
>>>                     }
>>>             };
>>>             
>>>             public void invalidate() {
>>>                     sample.setValue(new Object());
>>>             }
>>>     }
>>>
>>> }
>>>     
>>
>>
>> On 21.03.14 23:26, Kevin Rushforth wrote:
>>   
>>> It does seem promising. We'll also need data to show the trade-offs to
>>> help inform whether it is worth making such a massive change.
>>>
>>> -- Kevin
>>>
>>>
>>> Stephen F Northover wrote:
>>>     
>>>> This looks good.  I wonder if we should make this (massive) change
>>>> before we lambda graphics and controls?  Probably doesn't matter.
>>>> We'll need a JIRA and someone assigned to it in order to track the work.
>>>>
>>>> Steve
>>>>
>>>> On 2014-03-21 12:53 PM, Tom Schindl wrote:
>>>>       
>>>>> Hi Richard,
>>>>>
>>>>> Coming back to this old thread and now that we are using lamdas all over
>>>>> I guess we could take one more look into that.
>>>>>
>>>>> I've prototyped an initial version by introducing a new internal type
>>>>> named InvalidatedSimpleObjectProperty (not the best name ever!) - see
>>>>> code pasted below.
>>>>>
>>>>> And now one can write code like this:
>>>>>
>>>>>         
>>>>>>      public final ObjectProperty<Rectangle2D> viewportProperty() {
>>>>>>          if (viewport == null) {
>>>>>>              viewport = new InvalidatedSimpleObjectProperty<>(this,
>>>>>> "viewport", (o) -> {
>>>>>>                  invalidateWidthHeight();
>>>>>>                  impl_markDirty(DirtyBits.NODE_VIEWPORT);
>>>>>>                  impl_geomChanged();
>>>>>>              } );
>>>>>>          }
>>>>>>          return viewport;
>>>>>>      }
>>>>>>           
>>>>> instead of
>>>>>
>>>>>         
>>>>>>      public final ObjectProperty<Rectangle2D> viewportProperty() {
>>>>>>          if (viewport == null) {
>>>>>>              viewport = new ObjectPropertyBase<Rectangle2D>() {
>>>>>>
>>>>>>                  @Override
>>>>>>                  protected void invalidated() {
>>>>>>                      invalidateWidthHeight();
>>>>>>                      impl_markDirty(DirtyBits.NODE_VIEWPORT);
>>>>>>                      impl_geomChanged();
>>>>>>                  }
>>>>>>
>>>>>>                  @Override
>>>>>>                  public Object getBean() {
>>>>>>                      return ImageView.this;
>>>>>>                  }
>>>>>>
>>>>>>                  @Override
>>>>>>                  public String getName() {
>>>>>>                      return "viewport";
>>>>>>                  }
>>>>>>              };
>>>>>>          }
>>>>>>          return viewport;
>>>>>>      }
>>>>>>           
>>>>> Which allows us to get rid of most of the ObjectPropertyBase sublcasses.
>>>>>
>>>>> Tom
>>>>>
>>>>>
>>>>>         
>>>>>> package com.sun.javafx.property;
>>>>>>
>>>>>> import java.util.function.Consumer;
>>>>>>
>>>>>> import javafx.beans.property.SimpleObjectProperty;
>>>>>>
>>>>>> public final class InvalidatedSimpleObjectProperty<T> extends
>>>>>> SimpleObjectProperty<T> {
>>>>>>     private final Consumer<InvalidatedSimpleObjectProperty<T>>
>>>>>> invalidationConsumer;
>>>>>>          /**
>>>>>>       * The constructor of {@code ObjectProperty}
>>>>>>       *
>>>>>>       * @param initialValue
>>>>>>       *            the initial value of the wrapped value
>>>>>>       * @param invalidationConsumer
>>>>>>       *               the consumer to be called when the bean is
>>>>>> invalidated
>>>>>>       */
>>>>>>      public InvalidatedSimpleObjectProperty(T initialValue, final
>>>>>> Consumer<InvalidatedSimpleObjectProperty<T>> invalidationConsumer) {
>>>>>>          super(initialValue);
>>>>>>          if( invalidationConsumer == null ) {
>>>>>>              throw new IllegalArgumentException("Consumer can not be
>>>>>> null");
>>>>>>          }
>>>>>>          this.invalidationConsumer = invalidationConsumer;
>>>>>>      }
>>>>>>
>>>>>>      /**
>>>>>>       * The constructor of {@code ObjectProperty}
>>>>>>       *
>>>>>>       * @param bean
>>>>>>       *            the bean of this {@code ObjectProperty}
>>>>>>       * @param name
>>>>>>       *            the name of this {@code ObjectProperty}
>>>>>>       * @param invalidationConsumer
>>>>>>       *               the consumer to be called when the bean is
>>>>>> invalidated
>>>>>>       */
>>>>>>      public InvalidatedSimpleObjectProperty(Object bean, String
>>>>>> name, final Consumer<InvalidatedSimpleObjectProperty<T>>
>>>>>> invalidationConsumer) {
>>>>>>         super(bean, name);
>>>>>>         if( invalidationConsumer == null ) {
>>>>>>             throw new IllegalArgumentException("Consumer can not be
>>>>>> null");
>>>>>>         }
>>>>>>         this.invalidationConsumer = invalidationConsumer;
>>>>>>      }
>>>>>>
>>>>>>      /**
>>>>>>       * The constructor of {@code ObjectProperty}
>>>>>>       *
>>>>>>       * @param bean
>>>>>>       *            the bean of this {@code ObjectProperty}
>>>>>>       * @param name
>>>>>>       *            the name of this {@code ObjectProperty}
>>>>>>       * @param initialValue
>>>>>>       *            the initial value of the wrapped value
>>>>>>       * @param invalidationConsumer
>>>>>>       *               the consumer to be called when the bean is
>>>>>> invalidated
>>>>>>       */
>>>>>>      public InvalidatedSimpleObjectProperty(Object bean, String
>>>>>> name, T initialValue, final
>>>>>> Consumer<InvalidatedSimpleObjectProperty<T>> invalidationConsumer) {
>>>>>>          super(bean,name,initialValue);
>>>>>>          if( invalidationConsumer == null ) {
>>>>>>              throw new IllegalArgumentException("Consumer can not be
>>>>>> null");
>>>>>>          }
>>>>>>          this.invalidationConsumer = invalidationConsumer;
>>>>>>      }
>>>>>>           @Override
>>>>>>      protected void invalidated() {
>>>>>>          invalidationConsumer.accept(this);
>>>>>>      }
>>>>>> }
>>>>>>           
>>>>> On 22.01.13 10:30, Richard Bair wrote:
>>>>>         
>>>>>>> Is the Java8 plan still there if not should the current
>>>>>>> Simple*Property
>>>>>>> subclasses who overload invalidated be changed to PropertyBase?
>>>>>>>             
>>>>>> It is unlikely that we'll be able to do anything major here in Java
>>>>>> 8 just because we don't really have Lambda yet that we can play
>>>>>> with, and changing over every property is a big job. Unless we knew
>>>>>> it would be a major win. I would say, if you encounter a Simple*
>>>>>> property that has been subclassed, then we should fix it up as we go
>>>>>> to be a PropertyBase* guy instead.
>>>>>>
>>>>>>           
>>
>>   

Reply via email to