com.google.inject.PerformanceComparison.java Source code

Java tutorial

Introduction

Here is the source code for com.google.inject.PerformanceComparison.java

Source

/**
 * Copyright (C) 2006 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.inject;

import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertSame;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.annotation.Retention;
import java.text.DecimalFormat;
import java.util.concurrent.Callable;

/**
 * A semi-useless microbenchmark. Spring and Guice constuct the same object
 * graph a bunch of times, and we see who can construct the most per second.
 * As of this writing Guice is more than 50X faster. Also useful for comparing 
 * pure Java configuration options.
 *
 * @author crazybob@google.com (Bob Lee)
 */
public class PerformanceComparison {

    public static void main(String[] args) throws Exception {
        // Once warm up. Takes lazy loading out of the equation and ensures we
        // created the graphs properly.
        validate(springFactory);
        validate(juiceFactory);
        validate(byHandFactory);

        for (int i2 = 0; i2 < 10; i2++) {
            iterate(springFactory, "Spring:  ");
            iterate(juiceFactory, "Guice:   ");
            iterate(byHandFactory, "By Hand: ");

            System.err.println();
        }

        System.err.println("Concurrent:");

        for (int i2 = 0; i2 < 10; i2++) {
            concurrentlyIterate(springFactory, "Spring:  ");
            concurrentlyIterate(juiceFactory, "Guice:   ");
            concurrentlyIterate(byHandFactory, "By Hand: ");

            System.err.println();
        }
    }

    static final Callable<Foo> springFactory = new Callable<Foo>() {

        final DefaultListableBeanFactory beanFactory;

        {
            beanFactory = new DefaultListableBeanFactory();

            RootBeanDefinition tee = new RootBeanDefinition(TeeImpl.class, true);
            tee.setLazyInit(true);
            ConstructorArgumentValues teeValues = new ConstructorArgumentValues();
            teeValues.addGenericArgumentValue("test");
            tee.setConstructorArgumentValues(teeValues);

            RootBeanDefinition bar = new RootBeanDefinition(BarImpl.class, false);
            ConstructorArgumentValues barValues = new ConstructorArgumentValues();
            barValues.addGenericArgumentValue(new RuntimeBeanReference("tee"));
            barValues.addGenericArgumentValue(5);
            bar.setConstructorArgumentValues(barValues);

            RootBeanDefinition foo = new RootBeanDefinition(Foo.class, false);
            MutablePropertyValues fooValues = new MutablePropertyValues();
            fooValues.addPropertyValue("i", 5);
            fooValues.addPropertyValue("bar", new RuntimeBeanReference("bar"));
            fooValues.addPropertyValue("copy", new RuntimeBeanReference("bar"));
            fooValues.addPropertyValue("s", "test");
            foo.setPropertyValues(fooValues);

            beanFactory.registerBeanDefinition("foo", foo);
            beanFactory.registerBeanDefinition("bar", bar);
            beanFactory.registerBeanDefinition("tee", tee);
        }

        public Foo call() throws Exception {
            return (Foo) beanFactory.getBean("foo");
        }
    };

    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);
                        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> byHandFactory = new Callable<Foo>() {
        final Tee tee = new TeeImpl("test");

        public Foo call() throws Exception {
            Foo foo = new Foo();
            foo.setI(5);
            foo.setS("test");
            Bar bar = new BarImpl(tee, 5);
            Bar copy = new BarImpl(tee, 5);
            foo.setBar(bar);
            foo.setCopy(copy);
            return foo;
        }
    };

    static void validate(Callable<Foo> t) throws Exception {
        Foo foo = t.call();
        assertEquals(5, foo.i);
        assertEquals("test", foo.s);
        assertSame(foo.bar.getTee(), foo.copy.getTee());
        assertEquals(5, foo.bar.getI());
        assertEquals("test", foo.bar.getTee().getS());
    }

    static final DecimalFormat format = new DecimalFormat();

    static void iterate(Callable<Foo> callable, String label) {
        int count = 100000;

        long time = System.currentTimeMillis();

        for (int i = 0; i < count; i++) {
            try {
                callable.call();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        time = System.currentTimeMillis() - time;

        System.err.println(label + format.format(count * 1000 / time) + " creations/s");
    }

    static void concurrentlyIterate(final Callable<Foo> callable, String label) {
        int threadCount = 10;
        final int count = 10000;

        Thread[] threads = new Thread[threadCount];

        for (int i = 0; i < threadCount; i++) {
            threads[i] = new Thread() {
                public void run() {
                    for (int i = 0; i < count; i++) {
                        try {
                            validate(callable);
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            };
        }

        long time = System.currentTimeMillis();

        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);
            }
        }

        time = System.currentTimeMillis() - time;

        System.err.println(label + format.format(count * 1000 / time) + " creations/s");
    }

    public static class Foo {

        Bar bar;
        Bar copy;
        String s;
        int i;

        @Inject
        public void setI(@I int i) {
            this.i = i;
        }

        @Inject
        public void setBar(Bar bar) {
            this.bar = bar;
        }

        @Inject
        public void setCopy(Bar copy) {
            this.copy = copy;
        }

        @Inject
        public void setS(@S String s) {
            this.s = s;
        }
    }

    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(RUNTIME)
    @BindingAnnotation
    @interface I {
    }

    @Retention(RUNTIME)
    @BindingAnnotation
    @interface S {
    }
}