From: <iro...@us...> - 2009-09-07 21:24:18
|
Revision: 150 http://pojomatic.svn.sourceforge.net/pojomatic/?rev=150&view=rev Author: iroberts Date: 2009-09-07 21:24:12 +0000 (Mon, 07 Sep 2009) Log Message: ----------- comparative benchmarks, first take. While a submodule of PojomaticAll, it is not part of that pom's build. Added Paths: ----------- trunk/PojomaticAll/pojomatic-benchmark/ trunk/PojomaticAll/pojomatic-benchmark/pom.xml trunk/PojomaticAll/pojomatic-benchmark/src/ trunk/PojomaticAll/pojomatic-benchmark/src/main/ trunk/PojomaticAll/pojomatic-benchmark/src/main/java/ trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/ trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/pojomatic/ trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/pojomatic/Bean.java trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/pojomatic/BeanSpeedTest.java Property changes on: trunk/PojomaticAll/pojomatic-benchmark ___________________________________________________________________ Added: svn:ignore + pojomatic-benchmark.iml target Added: trunk/PojomaticAll/pojomatic-benchmark/pom.xml =================================================================== --- trunk/PojomaticAll/pojomatic-benchmark/pom.xml (rev 0) +++ trunk/PojomaticAll/pojomatic-benchmark/pom.xml 2009-09-07 21:24:12 UTC (rev 150) @@ -0,0 +1,23 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <artifactId>pojomatic-all</artifactId> + <groupId>org.pojomatic</groupId> + <version>trunk-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <groupId>org.pojomatic</groupId> + <artifactId>pojomatic-benchmark</artifactId> + <packaging>jar</packaging> + <version>trunk-SNAPSHOT</version> + <name>pojomatic-benchmark</name> + <url>http://maven.apache.org</url> + <dependencies> + <dependency> + <groupId>org.pojomatic</groupId> + <artifactId>pojomatic</artifactId> + <version>trunk-SNAPSHOT</version> + </dependency> + </dependencies> +</project> Added: trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/pojomatic/Bean.java =================================================================== --- trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/pojomatic/Bean.java (rev 0) +++ trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/pojomatic/Bean.java 2009-09-07 21:24:12 UTC (rev 150) @@ -0,0 +1,312 @@ +package org.pojomatic; + +import java.util.Arrays; +import java.util.List; + +import org.pojomatic.Pojomatic; +import org.pojomatic.Pojomator; +import org.pojomatic.PropertyElement; +import org.pojomatic.annotations.AutoDetectPolicy; +import org.pojomatic.annotations.AutoProperty; +import org.pojomatic.internal.ClassProperties; + +@AutoProperty(autoDetect=AutoDetectPolicy.METHOD) +public class Bean { + private String string; + private int i; + private Integer integer; + private int[] ints; + private List<String> strings; + + private static PropertyElement getInteger, getString, getI, getInts, getStrings; + + static { + setUpPojomaticHandrolled(); + } + + private static void setUpPojomaticHandrolled() { + ClassProperties classProperties = ClassProperties.createInstance(Bean.class); + for (PropertyElement prop: classProperties.getHashCodeProperties()) { + if ("integer".equals(prop.getName())) { + getInteger = prop; + } + else if ("string".equals(prop.getName())) { + getString = prop; + } + else if ("i".equals(prop.getName())) { + getI = prop; + } + else if ("ints".equals(prop.getName())) { + getInts = prop; + } + else if ("strings".equals(prop.getName())) { + getStrings = prop; + } + else { + throw new RuntimeException("unexpected property: " + prop); + } + } + System.out.println(classProperties.getHashCodeProperties()); + } + + public String getString() { + return string; + } + public void setString(String string) { + this.string = string; + } + public int getI() { + return i; + } + public void setI(int i) { + this.i = i; + } + public Integer getInteger() { + return integer; + } + public void setInteger(Integer integer) { + this.integer = integer; + } + public int[] getInts() { + return ints; + } + public void setInts(int[] ints) { + this.ints = ints; + } + public List<String> getStrings() { + return strings; + } + public void setStrings(List<String> strings) { + this.strings = strings; + } + + public boolean pmequals(Object other) { + return Pojomatic.equals(this, other); + } + + public int pmHashCode() { + return Pojomatic.hashCode(this); + } + + private Pojomator<Bean> POJOMATOR = Pojomatic.pojomator(Bean.class); + + public boolean pmFastequals(Object other) { + return POJOMATOR.doEquals(this, other); + } + + public int pmFastHashCode() { + return POJOMATOR.doHashCode(this); + } + + public int handRolledPmHashCode() { + int hashCode = 1; + hashCode = 31 * hashCode + hashCodeOfValue(getInteger.getValue(this)); + hashCode = 31 * hashCode + hashCodeOfValue(getString.getValue(this)); + hashCode = 31 * hashCode + hashCodeOfValue(getI.getValue(this)); + hashCode = 31 * hashCode + hashCodeOfValue(getInts.getValue(this)); + hashCode = 31 * hashCode + hashCodeOfValue(getStrings.getValue(this)); + return hashCode; + } + + public boolean handRolledPmEquals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof Bean)) { + return false; + } + + return areValuesEqual(getInteger.getValue(this), getInteger.getValue(other)) + && areValuesEqual(getString.getValue(this), getString.getValue(other)) + && areValuesEqual(getI.getValue(this), getI.getValue(other)) + && areValuesEqual(getInts.getValue(this), getInts.getValue(other)) + && areValuesEqual(getStrings.getValue(this), getStrings.getValue(other)); + } + +private static boolean areValuesEqual(Object instanceValue, Object otherValue) { + if (instanceValue == null) { + if (otherValue != null) { + return false; + } + } + else { // instanceValue is not null + if (otherValue == null) { + return false; + } + if (!instanceValue.getClass().isArray()) { + if (!instanceValue.equals(otherValue)) { + return false; + } + } + else { + if (!otherValue.getClass().isArray()) { + return false; + } + Class<?> instanceComponentClass = instanceValue.getClass().getComponentType(); + Class<?> otherComponentClass = otherValue.getClass().getComponentType(); + + if (!instanceComponentClass.isPrimitive()) { + if (otherComponentClass.isPrimitive()) { + return false; + } + if (!Arrays.deepEquals((Object[]) instanceValue, (Object[]) otherValue)) { + return false; + } + } + else { // instanceComponentClass is primative + if (otherComponentClass != instanceComponentClass) { + return false; + } + + if (Boolean.TYPE == instanceComponentClass) { + if(!Arrays.equals((boolean[]) instanceValue, (boolean[]) otherValue)) { + return false; + } + } + else if (Byte.TYPE == instanceComponentClass) { + if (! Arrays.equals((byte[]) instanceValue, (byte[]) otherValue)) { + return false; + } + } + else if (Character.TYPE == instanceComponentClass) { + if(!Arrays.equals((char[]) instanceValue, (char[]) otherValue)) { + return false; + } + } + else if (Short.TYPE == instanceComponentClass) { + if(!Arrays.equals((short[]) instanceValue, (short[]) otherValue)) { + return false; + } + } + else if (Integer.TYPE == instanceComponentClass) { + if(!Arrays.equals((int[]) instanceValue, (int[]) otherValue)) { + return false; + } + } + else if (Long.TYPE == instanceComponentClass) { + if(!Arrays.equals((long[]) instanceValue, (long[]) otherValue)) { + return false; + } + } + else if (Float.TYPE == instanceComponentClass) { + if(!Arrays.equals((float[]) instanceValue, (float[]) otherValue)) { + return false; + } + } + else if (Double.TYPE == instanceComponentClass) { + if(!Arrays.equals((double[]) instanceValue, (double[]) otherValue)) { + return false; + } + } + else { + // should NEVER happen + throw new IllegalStateException( + "unknown primative type " + instanceComponentClass.getName()); + } + } + } + } + return true; +} + + private static int hashCodeOfValue(Object value) { + if (value == null) { + return 0; + } + else { + if (value.getClass().isArray()) { + Class<?> instanceComponentClass = value.getClass().getComponentType(); + if (! instanceComponentClass.isPrimitive()) { + return Arrays.hashCode((Object[]) value); + } + else { + if (Boolean.TYPE == instanceComponentClass) { + return Arrays.hashCode((boolean[]) value); + } + else if (Byte.TYPE == instanceComponentClass) { + return Arrays.hashCode((byte[]) value); + } + else if (Character.TYPE == instanceComponentClass) { + return Arrays.hashCode((char[]) value); + } + else if (Short.TYPE == instanceComponentClass) { + return Arrays.hashCode((short[]) value); + } + else if (Integer.TYPE == instanceComponentClass) { + return Arrays.hashCode((int[]) value); + } + else if (Long.TYPE == instanceComponentClass) { + return Arrays.hashCode((long[]) value); + } + else if (Float.TYPE == instanceComponentClass) { + return Arrays.hashCode((float[]) value); + } + else if (Double.TYPE == instanceComponentClass) { + return Arrays.hashCode((double[]) value); + } + else { + // should NEVER happen + throw new IllegalStateException( + "unknown primative type " + instanceComponentClass.getName()); + } + } + } + else { + return value.hashCode(); + } + } + } + + + @Override public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + i; + result = prime * result + ((integer == null) + ? 0 + : integer.hashCode()); + result = prime * result + Arrays.hashCode(ints); + result = prime * result + ((string == null) + ? 0 + : string.hashCode()); + result = prime * result + ((strings == null) + ? 0 + : strings.hashCode()); + return result; + } + + @Override public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final Bean other = (Bean) obj; + if (i != other.i) + return false; + if (integer == null) { + if (other.integer != null) + return false; + } + else if (!integer.equals(other.integer)) + return false; + if (!Arrays.equals(ints, other.ints)) + return false; + if (string == null) { + if (other.string != null) + return false; + } + else if (!string.equals(other.string)) + return false; + if (strings == null) { + if (other.strings != null) + return false; + } + else if (!strings.equals(other.strings)) + return false; + return true; + } + + +} Added: trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/pojomatic/BeanSpeedTest.java =================================================================== --- trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/pojomatic/BeanSpeedTest.java (rev 0) +++ trunk/PojomaticAll/pojomatic-benchmark/src/main/java/org/pojomatic/BeanSpeedTest.java 2009-09-07 21:24:12 UTC (rev 150) @@ -0,0 +1,125 @@ +package org.pojomatic; + +import java.util.Random; + +public class BeanSpeedTest { + private final static Random rand = new Random(); + + public static void main(String[] args) { + Bean[] beans = makeBeans(800); + BaseChecker[] checkers = new BaseChecker[] { + new StandardChecker(), + new PmChecker(), + new PmFastChecker(), + new PmHandRolledChecker(), + }; + + while(true) { + for (BaseChecker checker: checkers) { + long equalsStart = System.nanoTime(); + checker.checkEquals(beans); + long equalsElapsed = System.nanoTime() - equalsStart; + + long hashStart = System.nanoTime(); + checker.checkHashCode(beans); + long hashElapsed = System.nanoTime() - hashStart; + + long size = beans.length * beans.length; + System.out.println(equalsElapsed / size + + " - " + hashElapsed / size + + " - " + checker.getClass().getSimpleName()); + } + System.out.println(); + } + } + + private static Bean[] makeBeans(int beanCount) { + Bean[] beans = new Bean[beanCount]; + for (int i = 0; i < beanCount; i++) { + beans[i] = randomBean(); + } + return beans; + } + + private static Bean randomBean() { + Bean bean = new Bean(); + bean.setI(rand.nextInt()); + bean.setInteger(rand.nextInt()); + int[] ints = new int[0/*rand.nextInt(10)*/]; + for (int i = 0; i < ints.length; i++) { + ints[i] = rand.nextInt(); + } + bean.setInts(null); //ints); + bean.setString(String.valueOf(rand.nextDouble())); + String[] strings = new String[0]; //rand.nextInt(5)]; + for (int i = 0; i < strings.length; i++) { + strings[i] = String.valueOf(rand.nextInt()); + } + bean.setStrings(null); //Arrays.asList(strings)); + return bean; + } + + public static abstract class BaseChecker { + public void checkEquals(Bean[] beans) { + for (int i = 0; i < beans.length; i++) { + for (int j = 0; j < beans.length; j++) { + if (equals(beans[i], beans[j]) != (i == j)) { + System.out.println("error at " + i + ", " + j); + } + } + } + } + + public void checkHashCode(Bean[] beans) { + for (int i = 0; i < beans.length; i++) { + for (int j = 0; j < beans.length; j++) { + if ((hashCode(beans[i]) == hashCode(beans[j])) != (i == j)) { + System.out.println("error at " + i + ", " + j); + } + } + } + } + + protected abstract long hashCode(Bean bean); + + protected abstract boolean equals(Bean bean1, Bean bean2); + } + + public static class StandardChecker extends BaseChecker { + @Override protected boolean equals(Bean bean1, Bean bean2) { + return bean1.equals(bean2); + } + + @Override protected long hashCode(Bean bean) { + return bean.hashCode(); + } + } + + public static class PmChecker extends BaseChecker { + @Override protected boolean equals(Bean bean1, Bean bean2) { + return bean1.pmequals(bean2); + } + @Override protected long hashCode(Bean bean) { + return bean.pmHashCode(); + } + } + + public static class PmFastChecker extends BaseChecker { + @Override protected boolean equals(Bean bean1, Bean bean2) { + return bean1.pmFastequals(bean2); + } + @Override protected long hashCode(Bean bean) { + return bean.pmFastHashCode(); + } + } + + public static class PmHandRolledChecker extends BaseChecker { + @Override protected boolean equals(Bean bean1, Bean bean2) { + return bean1.handRolledPmEquals(bean2); + } + @Override protected long hashCode(Bean bean) { + return bean.handRolledPmHashCode(); + } + } + +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |