You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by st...@apache.org on 2015/12/11 16:29:08 UTC

svn commit: r1719457 - in /openwebbeans/trunk/webbeans-impl/src: main/java/org/apache/webbeans/container/ test/java/org/apache/webbeans/test/annotation/binding/ test/java/org/apache/webbeans/test/performance/

Author: struberg
Date: Fri Dec 11 15:29:08 2015
New Revision: 1719457

URL: http://svn.apache.org/viewvc?rev=1719457&view=rev
Log:
OWB-1034 improve BeanCacheKey performance

we actually don't need such a good qualifier hash as all gets compared
later anyways. So we now only look at the annotationTypes hash
and be good. 
I also enabled a special handling for qualifiers which are known 
to have no parameters.

Added:
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/performance/BeanResolvingPerformanceTest.java   (with props)
Modified:
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/annotation/binding/BeanCacheKeyUnitTest.java

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java?rev=1719457&r1=1719456&r2=1719457&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java Fri Dec 11 15:29:08 2015
@@ -18,6 +18,7 @@
  */
 package org.apache.webbeans.container;
 
+import org.apache.webbeans.annotation.EmptyAnnotationLiteral;
 import org.apache.webbeans.util.AnnotationUtil;
 
 import javax.enterprise.util.Nonbinding;
@@ -177,96 +178,16 @@ public final class BeanCacheKey
     }
 
     /**
-     * Calculate the hashCode() of a qualifier, which ignores {@link Nonbinding} members.
+     * Calculate the hashCode() of a qualifier.
+     * We do not do any in-depth hashCode down to member hashes
+     * but only use the hashcode of the AnnotationType itself.
+     * This is WAY faster and spreads well enough in practice.
+     * We can do this as we do not need to return a perfectly unique
+     * result anyway.
      */
     private int getQualifierHashCode(Annotation a)
     {
-        Class annotationClass = getAnnotationClass(a.getClass());
-
-        if (annotationClass == null)
-        {
-            return getTypeHashCode(a.getClass());
-        }
-
-        // the hashCode of an Annotation is calculated solely via the hashCodes
-        // of it's members. If there are no members, it is 0.
-        // thus we first need to get the annotation-class hashCode
-        int hashCode = getTypeHashCode(annotationClass);
-
-        // and now add the hashCode of all it's Nonbinding members
-        // the following algorithm is defined by the Annotation class definition
-        // see the JavaDoc for Annotation!
-        // we only change it so far that we skip evaluating @Nonbinding members
-        final Method[] members = annotationClass.getDeclaredMethods();
-
-        for (Method member : members)
-        {
-            if (member.isAnnotationPresent(Nonbinding.class))
-            {
-                // ignore the non binding
-                continue;
-            }
-
-            // Member value
-            final Object object = callMethod(a, member);
-            final int value;
-            if(object.getClass().isArray())
-            {
-                Class<?> type = object.getClass().getComponentType();
-                if(type.isPrimitive())
-                {
-                    if(Long.TYPE == type)
-                    {
-                        value = Arrays.hashCode((long[]) object);
-                    }
-                    else if(Integer.TYPE == type)
-                    {
-                        value = Arrays.hashCode((int[])object);
-                    }
-                    else if(Short.TYPE == type)
-                    {
-                        value = Arrays.hashCode((short[])object);
-                    }
-                    else if(Double.TYPE == type)
-                    {
-                        value = Arrays.hashCode((double[])object);
-                    }
-                    else if(Float.TYPE == type)
-                    {
-                        value = Arrays.hashCode((float[])object);
-                    }
-                    else if(Boolean.TYPE == type)
-                    {
-                        value = Arrays.hashCode((boolean[])object);
-                    }
-                    else if(Byte.TYPE == type)
-                    {
-                        value = Arrays.hashCode((byte[])object);
-                    }
-                    else if(Character.TYPE == type)
-                    {
-                        value = Arrays.hashCode((char[])object);
-                    }
-                    else
-                    {
-                        value = 0;
-                    }
-                }
-                else
-                {
-                    value = Arrays.hashCode((Object[])object);
-                }
-            }
-            else
-            {
-                value = object.hashCode();
-            }
-
-            hashCode = 29 * hashCode + value;
-            hashCode = 29 * hashCode + member.getName().hashCode();
-        }
-
-        return hashCode;
+        return a.annotationType().hashCode();
     }
 
     /**
@@ -277,17 +198,6 @@ public final class BeanCacheKey
         return ANNOTATION_COMPARATOR.compare(qualifier1, qualifier2) == 0;
     }
 
-    private static Class getAnnotationClass(Class a)
-    {
-        for (Class i : a.getInterfaces())
-        {
-            if (i.isAnnotation())
-            {
-                return i;
-            }
-        }
-        return null;
-    }
 
     /**
      * Helper method for calculating the hashCode of an annotation.
@@ -338,6 +248,13 @@ public final class BeanCacheKey
             {
                 return temp;
             }
+            if (annotation1 instanceof EmptyAnnotationLiteral || annotation2 instanceof EmptyAnnotationLiteral)
+            {
+                // if any of those 2 annotations are known to have no members
+                // then we can immediately return as we know the 2 annotations mean the same
+                return 0;
+            }
+
             final Method[] member1 = type1.getDeclaredMethods();
             final Method[] member2 = type2.getDeclaredMethods();
 

Modified: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/annotation/binding/BeanCacheKeyUnitTest.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/annotation/binding/BeanCacheKeyUnitTest.java?rev=1719457&r1=1719456&r2=1719457&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/annotation/binding/BeanCacheKeyUnitTest.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/annotation/binding/BeanCacheKeyUnitTest.java Fri Dec 11 15:29:08 2015
@@ -175,7 +175,6 @@ public class BeanCacheKeyUnitTest
         BeanCacheKey a = new BeanCacheKey(true, String.class, null, a1);
         BeanCacheKey b = new BeanCacheKey(true, String.class, null, a2);
         Assert.assertFalse(a.equals(b));
-        Assert.assertFalse(a.hashCode() == b.hashCode());
     }
 
     @Test
@@ -230,7 +229,6 @@ public class BeanCacheKeyUnitTest
         BeanCacheKey a = new BeanCacheKey(true, String.class, null, a4);
         BeanCacheKey b = new BeanCacheKey(true, String.class, null, a5);
         Assert.assertFalse(a.equals(b));
-        Assert.assertFalse(a.hashCode() == b.hashCode());
     }
 
     @Test
@@ -257,7 +255,6 @@ public class BeanCacheKeyUnitTest
         BeanCacheKey a = new BeanCacheKey(true, String.class, null, a7);
         BeanCacheKey b = new BeanCacheKey(true, String.class, null, a8);
         Assert.assertFalse(a.equals(b));
-        Assert.assertFalse(a.hashCode() == b.hashCode());
     }
 
     @Test
@@ -266,7 +263,6 @@ public class BeanCacheKeyUnitTest
         BeanCacheKey a = new BeanCacheKey(true, String.class, null, a9);
         BeanCacheKey b = new BeanCacheKey(true, String.class, null, aa);
         Assert.assertFalse(a.equals(b));
-        Assert.assertFalse(a.hashCode() == b.hashCode());
     }
 
     @Test
@@ -275,7 +271,6 @@ public class BeanCacheKeyUnitTest
         BeanCacheKey a = new BeanCacheKey(true, String.class, null, ab);
         BeanCacheKey b = new BeanCacheKey(true, String.class, null, ac);
         Assert.assertFalse(a.equals(b));
-        Assert.assertFalse(a.hashCode() == b.hashCode());
     }
 
     @Test

Added: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/performance/BeanResolvingPerformanceTest.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/performance/BeanResolvingPerformanceTest.java?rev=1719457&view=auto
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/performance/BeanResolvingPerformanceTest.java (added)
+++ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/performance/BeanResolvingPerformanceTest.java Fri Dec 11 15:29:08 2015
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.webbeans.test.performance;
+
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.spi.BeanManager;
+
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
+
+import org.apache.webbeans.test.AbstractUnitTest;
+import org.junit.Test;
+
+/**
+ * Test to benchmark the performance of bean resolving
+ */
+public class BeanResolvingPerformanceTest extends AbstractUnitTest
+{
+    private static final Logger logger = Logger.getLogger(BeanResolvingPerformanceTest.class.getName());
+
+    private static final int WARMUP_ITERATIONS = 10000;
+
+    // tune up to larger values to
+    private static final int BENCHMARK_ITERATIONS = 1000000;
+
+    /**
+     * original times with 10000000 iterations on my MBP
+     * started with 9885,9776,9868
+     * after qualifier hashCode tuning: 6177,6144,6075
+     * after qualifier-Comparator tuning: 1573,1453,1471
+     */
+    @Test
+    public void testBeanResolverPerformance()
+    {
+        startContainer(BeanWithDefaultQualifier.class);
+        BeanManager bm = getBeanManager();
+
+        for (int i= 0; i < WARMUP_ITERATIONS; i++)
+        {
+            getBeans(bm);
+        }
+
+        long start = System.nanoTime();
+        for (int i= 0; i < BENCHMARK_ITERATIONS; i++)
+        {
+            getBeans(bm);
+        }
+        long end = System.nanoTime();
+        logger.info("Resolving a bean " + BENCHMARK_ITERATIONS + " times took ms: " + TimeUnit.NANOSECONDS.toMillis(end - start));
+    }
+
+    private void getBeans(BeanManager bm)
+    {
+        bm.getBeans(BeanWithDefaultQualifier.class);
+    }
+
+
+    @RequestScoped
+    public static class BeanWithDefaultQualifier
+    {
+        // no content needed
+    }
+}

Propchange: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/performance/BeanResolvingPerformanceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native