Created
March 8, 2013 17:50
-
-
Save esmasui/5118364 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.uphyca.daggerperformance; | |
| import java.lang.annotation.Retention; | |
| import java.lang.annotation.RetentionPolicy; | |
| import java.text.DecimalFormat; | |
| import java.util.concurrent.Callable; | |
| import javax.inject.Inject; | |
| import javax.inject.Qualifier; | |
| import javax.inject.Singleton; | |
| import junit.framework.TestCase; | |
| import com.google.inject.AbstractModule; | |
| import com.google.inject.BindingAnnotation; | |
| import com.google.inject.CreationException; | |
| import com.google.inject.Guice; | |
| import com.google.inject.Injector; | |
| import com.google.inject.Provider; | |
| import com.google.inject.Scopes; | |
| import dagger.Module; | |
| import dagger.ObjectGraph; | |
| import dagger.Provides; | |
| /** | |
| * Based on | |
| * http://www.jroller.com/Solomon/entry/spring_2_5_perfomance_improvements | |
| */ | |
| public class DaggerPerformanceTest extends TestCase { | |
| public void testGuice() throws Exception { | |
| // Once warm up. Takes lazy loading out of the equation and ensures we | |
| // created the graphs properly. | |
| validate(daggerFactory, false); | |
| validate(juiceFactory, false); | |
| validate(byHandFactory, false); | |
| System.err.println("==================================="); | |
| System.err.println("Prototypes :"); | |
| System.err.println("==================================="); | |
| System.err.println("======"); | |
| System.err.println("Concurrent:"); | |
| System.err.println("======"); | |
| for (int i2 = 0; i2 < 5; i2++) { | |
| concurrentlyIterate(daggerFactory, "Dagger: ", false); | |
| concurrentlyIterate(juiceFactory, "Guice: ", false); | |
| concurrentlyIterate(byHandFactory, "By Hand: ", false); | |
| System.err.println(); | |
| } | |
| System.err.println("======"); | |
| System.err.println("Single Threaded:"); | |
| System.err.println("======"); | |
| for (int i2 = 0; i2 < 5; i2++) { | |
| iterate(daggerFactory, "Dagger: ", false); | |
| iterate(juiceFactory, "Guice: ", false); | |
| iterate(byHandFactory, "By Hand: ", false); | |
| System.err.println(); | |
| } | |
| System.err.println("==================================="); | |
| System.err.println("SingleTons :"); | |
| System.err.println("==================================="); | |
| System.err.println("======"); | |
| System.err.println("Concurrent:"); | |
| System.err.println("======"); | |
| for (int i2 = 0; i2 < 5; i2++) { | |
| concurrentlyIterate(daggerSingletonFactory, "Dagger: ", true); | |
| concurrentlyIterate(juiceSingletonFactory, "Guice: ", true); | |
| concurrentlyIterate(byHandSingletonFactory, "By Hand: ", true); | |
| System.err.println(); | |
| } | |
| System.err.println("Single:"); | |
| for (int i2 = 0; i2 < 5; i2++) { | |
| iterate(daggerSingletonFactory, "Dagger: ", true); | |
| iterate(juiceSingletonFactory, "Guice: ", true); | |
| iterate(byHandSingletonFactory, "By Hand: ", true); | |
| System.err.println(); | |
| } | |
| } | |
| public static class ProviderHolder { | |
| @Inject | |
| javax.inject.Provider<Foo> provider; | |
| } | |
| @Module(entryPoints = { Foo.class, ProviderHolder.class }) | |
| public static class DaggerFactoryModule { | |
| @Provides | |
| Tee provideTee(TeeImpl tee) { | |
| return tee; | |
| } | |
| @Provides | |
| Bar provideTee(BarImpl bar) { | |
| return bar; | |
| } | |
| @Provides | |
| Foo provideFoo(FooImpl foo) { | |
| return foo; | |
| } | |
| @Provides | |
| @I | |
| int provideInt() { | |
| return 5; | |
| } | |
| @Provides | |
| @S | |
| String provideString() { | |
| return "test"; | |
| } | |
| } | |
| static final Callable<Foo> daggerFactory = new Callable<Foo>() { | |
| final javax.inject.Provider<Foo> fooProvider; | |
| { | |
| ObjectGraph injector = ObjectGraph | |
| .create(new DaggerFactoryModule()); | |
| ProviderHolder holder = new ProviderHolder(); | |
| injector.inject(holder); | |
| fooProvider = holder.provider; | |
| } | |
| public Foo call() throws Exception { | |
| return fooProvider.get(); | |
| } | |
| }; | |
| @Module(entryPoints = { Foo.class, ProviderHolder.class }) | |
| public static class DaggerSingletonFactoryModule { | |
| @Provides | |
| Tee provideTee(TeeImpl tee) { | |
| return tee; | |
| } | |
| @Provides | |
| @Singleton | |
| Bar provideTee(BarImpl bar) { | |
| return bar; | |
| } | |
| @Provides | |
| @Singleton | |
| Foo provideFoo(FooSingletonImpl foo) { | |
| return foo; | |
| } | |
| @Provides | |
| @I | |
| int provideInt() { | |
| return 5; | |
| } | |
| @Provides | |
| @S | |
| String provideString() { | |
| return "test"; | |
| } | |
| } | |
| static final Callable<Foo> daggerSingletonFactory = new Callable<Foo>() { | |
| final javax.inject.Provider<Foo> fooProvider; | |
| { | |
| ObjectGraph injector = ObjectGraph | |
| .create(new DaggerSingletonFactoryModule()); | |
| ProviderHolder holder = new ProviderHolder(); | |
| injector.inject(holder); | |
| fooProvider = holder.provider; | |
| } | |
| public Foo call() throws Exception { | |
| return fooProvider.get(); | |
| } | |
| }; | |
| static final Callable<Foo> juiceFactory = new Callable<Foo>() { | |
| final Provider<Foo> fooProvider; | |
| { | |
| Injector injector; | |
| try { | |
| injector = Guice.createInjector(new AbstractModule() { | |
| protected void configure() { | |
| bind(Tee.class).to(TeeImpl.class); | |
| bind(Bar.class).to(BarImpl.class); | |
| bind(Foo.class).to(FooImpl.class); | |
| bindConstant().annotatedWith(I.class).to(5); | |
| bindConstant().annotatedWith(S.class).to("test"); | |
| } | |
| }); | |
| } catch (CreationException e) { | |
| throw new RuntimeException(e); | |
| } | |
| fooProvider = injector.getProvider(Foo.class); | |
| } | |
| public Foo call() throws Exception { | |
| return fooProvider.get(); | |
| } | |
| }; | |
| static final Callable<Foo> juiceSingletonFactory = new Callable<Foo>() { | |
| final Provider<Foo> fooProvider; | |
| { | |
| Injector injector; | |
| try { | |
| injector = Guice.createInjector(new AbstractModule() { | |
| protected void configure() { | |
| bind(Tee.class).to(TeeImpl.class); | |
| bind(Bar.class).to(BarImpl.class).in(Scopes.SINGLETON); | |
| bind(Foo.class).to(FooSingletonImpl.class); | |
| bindConstant().annotatedWith(I.class).to(5); | |
| bindConstant().annotatedWith(S.class).to("test"); | |
| } | |
| }); | |
| } catch (CreationException e) { | |
| throw new RuntimeException(e); | |
| } | |
| fooProvider = injector.getProvider(Foo.class); | |
| } | |
| public Foo call() throws Exception { | |
| return fooProvider.get(); | |
| } | |
| }; | |
| private static class ByHandFactory implements Callable<Foo> { | |
| private boolean isSingleton; | |
| final Tee tee = new TeeImpl("test"); | |
| final Foo foo; | |
| public ByHandFactory(boolean isSingleton) { | |
| this.isSingleton = isSingleton; | |
| foo = isSingleton ? createFoo() : null; | |
| } | |
| public Foo call() throws Exception { | |
| if (isSingleton) | |
| return foo; | |
| else | |
| return createFoo(); | |
| } | |
| private Foo createFoo() { | |
| FooImpl foo = new FooImpl(); | |
| foo.i = 5; | |
| foo.s = "test"; | |
| Bar bar = new BarImpl(tee, 5); | |
| Bar copy = isSingleton ? bar : new BarImpl(tee, 5); | |
| foo.bar = bar; | |
| foo.copy = copy; | |
| return foo; | |
| } | |
| }; | |
| static final Callable<Foo> byHandFactory = new ByHandFactory(false); | |
| static final Callable<Foo> byHandSingletonFactory = new ByHandFactory(true); | |
| static void validate(Callable<Foo> t, boolean isSingleton) throws Exception { | |
| Foo foo = t.call(); | |
| assertEquals(5, foo.getI()); | |
| assertEquals("test", foo.getS()); | |
| Bar bar = foo.getBar(); | |
| Bar copy = foo.getCopy(); | |
| assertSame(bar.getTee(), copy.getTee()); | |
| if (isSingleton) { | |
| assertSame(bar, copy); | |
| } else { | |
| assertNotSame(bar, copy); | |
| } | |
| assertEquals(5, bar.getI()); | |
| assertEquals("test", bar.getTee().getS()); | |
| } | |
| static final DecimalFormat format = new DecimalFormat(); | |
| static void iterate(Callable<Foo> callable, String label, | |
| boolean isSingleton) { | |
| iterate(callable, label, 1, isSingleton); | |
| } | |
| private static long concurrentTime = 0; | |
| static void concurrentlyIterate(final Callable<Foo> callable, String label, | |
| boolean isSingleton) { | |
| iterate(callable, label, 5, isSingleton); | |
| } | |
| private static void iterate(final Callable<Foo> callable, String label, | |
| int threadCount, final boolean isSingleton) { | |
| final long count = isSingleton ? 100000 : 10000; | |
| concurrentTime = 0; | |
| Thread[] threads = new Thread[threadCount]; | |
| for (int i = 0; i < threadCount; i++) { | |
| threads[i] = new Thread() { | |
| public void run() { | |
| long testStart = System.currentTimeMillis(); | |
| for (int i = 0; i < count; i++) { | |
| try { | |
| validate(callable, isSingleton); | |
| } catch (Exception e) { | |
| throw new RuntimeException(e); | |
| } | |
| } | |
| synchronized (DaggerPerformanceTest.class) { | |
| concurrentTime += (System.currentTimeMillis() - testStart); | |
| } | |
| } | |
| }; | |
| } | |
| for (int i = 0; i < threadCount; i++) { | |
| threads[i].start(); | |
| } | |
| for (int i = 0; i < threadCount; i++) { | |
| try { | |
| threads[i].join(); | |
| } catch (InterruptedException e) { | |
| throw new RuntimeException(e); | |
| } | |
| } | |
| if (concurrentTime == 0) { | |
| System.err.println(label + " is too freaking fast"); | |
| } else { | |
| long total = count * threadCount * threadCount * 1000 | |
| / concurrentTime; | |
| System.err.println(label + format.format(total) + " creations/s"); | |
| } | |
| } | |
| public static interface Foo { | |
| Bar getBar(); | |
| Bar getCopy(); | |
| String getS(); | |
| int getI(); | |
| } | |
| public static class FooImpl implements Foo { | |
| @Inject | |
| Bar bar; | |
| @Inject | |
| Bar copy; | |
| @Inject | |
| @S | |
| String s; | |
| @Inject | |
| @I | |
| int i; | |
| @Override | |
| public Bar getBar() { | |
| return bar; | |
| } | |
| @Override | |
| public Bar getCopy() { | |
| return copy; | |
| } | |
| @Override | |
| public String getS() { | |
| return s; | |
| } | |
| @Override | |
| public int getI() { | |
| return i; | |
| } | |
| } | |
| @Singleton | |
| public static class FooSingletonImpl implements Foo { | |
| @Inject | |
| Bar bar; | |
| @Inject | |
| Bar copy; | |
| @Inject | |
| @S | |
| String s; | |
| @Inject | |
| @I | |
| int i; | |
| @Override | |
| public Bar getBar() { | |
| return bar; | |
| } | |
| @Override | |
| public Bar getCopy() { | |
| return copy; | |
| } | |
| @Override | |
| public String getS() { | |
| return s; | |
| } | |
| @Override | |
| public int getI() { | |
| return i; | |
| } | |
| } | |
| interface Bar { | |
| Tee getTee(); | |
| int getI(); | |
| } | |
| public static class BarImpl implements Bar { | |
| final int i; | |
| final Tee tee; | |
| @Inject | |
| public BarImpl(Tee tee, @I int i) { | |
| this.tee = tee; | |
| this.i = i; | |
| } | |
| public Tee getTee() { | |
| return tee; | |
| } | |
| public int getI() { | |
| return i; | |
| } | |
| } | |
| interface Tee { | |
| String getS(); | |
| } | |
| @Singleton | |
| public static class TeeImpl implements Tee { | |
| final String s; | |
| @Inject | |
| public TeeImpl(@S String s) { | |
| this.s = s; | |
| } | |
| public String getS() { | |
| return s; | |
| } | |
| } | |
| @Retention(RetentionPolicy.RUNTIME) | |
| @Qualifier | |
| @BindingAnnotation | |
| @interface I { | |
| } | |
| @Retention(RetentionPolicy.RUNTIME) | |
| @Qualifier | |
| @BindingAnnotation | |
| @interface S { | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment