Home | History | Annotate | Download | only in inject
      1 /**
      2  * Copyright (C) 2006 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.inject;
     18 
     19 import static java.lang.annotation.RetentionPolicy.RUNTIME;
     20 import static junit.framework.Assert.assertEquals;
     21 import static junit.framework.Assert.assertSame;
     22 
     23 import org.springframework.beans.MutablePropertyValues;
     24 import org.springframework.beans.factory.config.ConstructorArgumentValues;
     25 import org.springframework.beans.factory.config.RuntimeBeanReference;
     26 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
     27 import org.springframework.beans.factory.support.RootBeanDefinition;
     28 
     29 import java.lang.annotation.Retention;
     30 import java.text.DecimalFormat;
     31 import java.util.concurrent.Callable;
     32 
     33 /**
     34  * A semi-useless microbenchmark. Spring and Guice constuct the same object
     35  * graph a bunch of times, and we see who can construct the most per second.
     36  * As of this writing Guice is more than 50X faster. Also useful for comparing
     37  * pure Java configuration options.
     38  *
     39  * @author crazybob (at) google.com (Bob Lee)
     40  */
     41 public class PerformanceComparison {
     42 
     43   public static void main(String[] args) throws Exception {
     44     // Once warm up. Takes lazy loading out of the equation and ensures we
     45     // created the graphs properly.
     46     validate(springFactory);
     47     validate(juiceFactory);
     48     validate(byHandFactory);
     49 
     50     for (int i2 = 0; i2 < 10; i2++) {
     51       iterate(springFactory, "Spring:  ");
     52       iterate(juiceFactory,  "Guice:   ");
     53       iterate(byHandFactory, "By Hand: ");
     54 
     55       System.err.println();
     56     }
     57 
     58     System.err.println("Concurrent:");
     59 
     60     for (int i2 = 0; i2 < 10; i2++) {
     61       concurrentlyIterate(springFactory, "Spring:  ");
     62       concurrentlyIterate(juiceFactory,  "Guice:   ");
     63       concurrentlyIterate(byHandFactory, "By Hand: ");
     64 
     65       System.err.println();
     66     }
     67   }
     68 
     69   static final Callable<Foo> springFactory = new Callable<Foo>() {
     70 
     71     final DefaultListableBeanFactory beanFactory;
     72 
     73     {
     74       beanFactory = new DefaultListableBeanFactory();
     75 
     76       RootBeanDefinition tee = new RootBeanDefinition(TeeImpl.class, true);
     77       tee.setLazyInit(true);
     78       ConstructorArgumentValues teeValues = new ConstructorArgumentValues();
     79       teeValues.addGenericArgumentValue("test");
     80       tee.setConstructorArgumentValues(teeValues);
     81 
     82       RootBeanDefinition bar = new RootBeanDefinition(BarImpl.class, false);
     83       ConstructorArgumentValues barValues = new ConstructorArgumentValues();
     84       barValues.addGenericArgumentValue(new RuntimeBeanReference("tee"));
     85       barValues.addGenericArgumentValue(5);
     86       bar.setConstructorArgumentValues(barValues);
     87 
     88       RootBeanDefinition foo = new RootBeanDefinition(Foo.class, false);
     89       MutablePropertyValues fooValues = new MutablePropertyValues();
     90       fooValues.addPropertyValue("i", 5);
     91       fooValues.addPropertyValue("bar", new RuntimeBeanReference("bar"));
     92       fooValues.addPropertyValue("copy", new RuntimeBeanReference("bar"));
     93       fooValues.addPropertyValue("s", "test");
     94       foo.setPropertyValues(fooValues);
     95 
     96       beanFactory.registerBeanDefinition("foo", foo);
     97       beanFactory.registerBeanDefinition("bar", bar);
     98       beanFactory.registerBeanDefinition("tee", tee);
     99     }
    100 
    101     public Foo call() throws Exception {
    102       return (Foo) beanFactory.getBean("foo");
    103     }
    104   };
    105 
    106   static final Callable<Foo> juiceFactory = new Callable<Foo>() {
    107     final Provider<Foo> fooProvider;
    108     {
    109       Injector injector;
    110       try {
    111         injector = Guice.createInjector(new AbstractModule() {
    112           protected void configure() {
    113             bind(Tee.class).to(TeeImpl.class);
    114             bind(Bar.class).to(BarImpl.class);
    115             bind(Foo.class);
    116             bindConstant().annotatedWith(I.class).to(5);
    117             bindConstant().annotatedWith(S.class).to("test");
    118           }
    119         });
    120       } catch (CreationException e) {
    121         throw new RuntimeException(e);
    122       }
    123       fooProvider = injector.getProvider(Foo.class);
    124     }
    125 
    126     public Foo call() throws Exception {
    127       return fooProvider.get();
    128     }
    129   };
    130 
    131   static final Callable<Foo> byHandFactory = new Callable<Foo>() {
    132     final Tee tee = new TeeImpl("test");
    133     public Foo call() throws Exception {
    134       Foo foo = new Foo();
    135       foo.setI(5);
    136       foo.setS("test");
    137       Bar bar = new BarImpl(tee, 5);
    138       Bar copy = new BarImpl(tee, 5);
    139       foo.setBar(bar);
    140       foo.setCopy(copy);
    141       return foo;
    142     }
    143   };
    144 
    145   static void validate(Callable<Foo> t) throws Exception {
    146     Foo foo = t.call();
    147     assertEquals(5, foo.i);
    148     assertEquals("test", foo.s);
    149     assertSame(foo.bar.getTee(), foo.copy.getTee());
    150     assertEquals(5, foo.bar.getI());
    151     assertEquals("test", foo.bar.getTee().getS());
    152   }
    153 
    154   static final DecimalFormat format = new DecimalFormat();
    155 
    156   static void iterate(Callable<Foo> callable, String label) {
    157     int count = 100000;
    158 
    159     long time = System.currentTimeMillis();
    160 
    161     for (int i = 0; i < count; i++) {
    162       try {
    163         callable.call();
    164       }
    165       catch (Exception e) {
    166         throw new RuntimeException(e);
    167       }
    168     }
    169 
    170     time = System.currentTimeMillis() - time;
    171 
    172     System.err.println(label
    173         + format.format(count * 1000 / time) + " creations/s");
    174   }
    175 
    176   static void concurrentlyIterate(final Callable<Foo> callable, String label) {
    177     int threadCount = 10;
    178     final int count = 10000;
    179 
    180     Thread[] threads = new Thread[threadCount];
    181 
    182     for (int i = 0; i < threadCount; i++) {
    183       threads[i] = new Thread() {
    184         public void run() {
    185           for (int i = 0; i < count; i++) {
    186             try {
    187               validate(callable);
    188             }
    189             catch (Exception e) {
    190               throw new RuntimeException(e);
    191             }
    192           }
    193         }
    194       };
    195     }
    196 
    197 
    198     long time = System.currentTimeMillis();
    199 
    200     for (int i = 0; i < threadCount; i++) {
    201       threads[i].start();
    202     }
    203 
    204     for (int i = 0; i < threadCount; i++) {
    205       try {
    206         threads[i].join();
    207       }
    208       catch (InterruptedException e) {
    209         throw new RuntimeException(e);
    210       }
    211     }
    212 
    213     time = System.currentTimeMillis() - time;
    214 
    215     System.err.println(label
    216         + format.format(count * 1000 / time) + " creations/s");
    217   }
    218 
    219   public static class Foo {
    220 
    221     Bar bar;
    222     Bar copy;
    223     String s;
    224     int i;
    225 
    226     @Inject
    227     public void setI(@I int i) {
    228       this.i = i;
    229     }
    230 
    231     @Inject
    232     public void setBar(Bar bar) {
    233       this.bar = bar;
    234     }
    235 
    236     @Inject
    237     public void setCopy(Bar copy) {
    238       this.copy = copy;
    239     }
    240 
    241     @Inject
    242     public void setS(@S String s) {
    243       this.s = s;
    244     }
    245   }
    246 
    247   interface Bar {
    248 
    249     Tee getTee();
    250     int getI();
    251   }
    252 
    253   public static class BarImpl implements Bar {
    254 
    255     final int i;
    256     final Tee tee;
    257 
    258     @Inject
    259     public BarImpl(Tee tee, @I int i) {
    260       this.tee = tee;
    261       this.i = i;
    262     }
    263 
    264     public Tee getTee() {
    265       return tee;
    266     }
    267 
    268     public int getI() {
    269       return i;
    270     }
    271   }
    272 
    273   interface Tee {
    274 
    275     String getS();
    276   }
    277 
    278   @Singleton
    279   public static class TeeImpl implements Tee {
    280 
    281     final String s;
    282 
    283     @Inject
    284     public TeeImpl(@S String s) {
    285       this.s = s;
    286     }
    287 
    288     public String getS() {
    289       return s;
    290     }
    291   }
    292 
    293   @Retention(RUNTIME)
    294   @BindingAnnotation @interface I {}
    295 
    296   @Retention(RUNTIME)
    297   @BindingAnnotation @interface S {}
    298 }
    299