Arghhh time for bed:

Number is 179 vs 150 but I only ran it once so the numbers might be
completely bogus!

Tom

On 24.03.14 23:40, Tom Schindl wrote:
> Ups there was an error in my test for the last Call line so the numbers
> there are:
> 
> 38 (lambda) vs 32 (subclass)
> 
>> 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();
>>                      TestObject o = target.get(0);
>>                      for( int i = 0; i < invokationOverheadCallCount; i++ ) {
>>                              o.invalidate();
>>                      }
>>                      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 24.03.14 23:36, Tom Schindl wrote:
>> 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