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