Skip to content

Commit

Permalink
JMH list equals benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
pditommaso committed Feb 14, 2018
1 parent 011b98e commit d37d1ae
Show file tree
Hide file tree
Showing 10 changed files with 1,310 additions and 1 deletion.
1,027 changes: 1,027 additions & 0 deletions all.txt

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ org.gradle.caching=true

# enable --parallel
org.gradle.parallel=true

benchInclude=ListBench
16 changes: 16 additions & 0 deletions results.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Benchmark (count) Mode Cnt Score Error Units
ListBench.equalsDefaultGroovy 1 avgt 15 0.003 ± 0.001 ms/op
ListBench.equalsDefaultGroovy 10 avgt 15 0.034 ± 0.001 ms/op
ListBench.equalsDefaultGroovy 100 avgt 15 0.332 ± 0.003 ms/op
ListBench.equalsDefaultGroovy 1000 avgt 15 3.355 ± 0.027 ms/op
ListBench.equalsDefaultGroovy 1000000 avgt 15 3412.212 ± 36.335 ms/op
ListBench.equalsWithAnnotation 1 avgt 15 0.004 ± 0.001 ms/op
ListBench.equalsWithAnnotation 10 avgt 15 0.035 ± 0.001 ms/op
ListBench.equalsWithAnnotation 100 avgt 15 0.336 ± 0.003 ms/op
ListBench.equalsWithAnnotation 1000 avgt 15 3.350 ± 0.029 ms/op
ListBench.equalsWithAnnotation 1000000 avgt 15 3534.392 ± 246.034 ms/op
ListBench.equalsWithInterface 1 avgt 15 0.003 ± 0.001 ms/op
ListBench.equalsWithInterface 10 avgt 15 0.035 ± 0.001 ms/op
ListBench.equalsWithInterface 100 avgt 15 0.341 ± 0.009 ms/op
ListBench.equalsWithInterface 1000 avgt 15 3.359 ± 0.057 ms/op
ListBench.equalsWithInterface 1000000 avgt 15 3510.889 ± 194.890 ms/op
2 changes: 1 addition & 1 deletion subprojects/performance/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ task performanceTests {
}
}

['1.8.9', '2.0.8', '2.1.9', '2.2.2', '2.3.10', '2.3.11', '2.4.7', 'current'].each { version ->
['current'].each { version ->
def t = task "performanceTestGroovy${version.replace('.', '_')}"(type: JavaExec) {
dependsOn compileTestJava
def groovyConf = configurations.detachedConfiguration(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* 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.groovy.bench.list;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;

@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Thread)
public class ListBench {

@Param({"1", "10", "100", "1000", "1000000"})
private int count;

@Benchmark
public void equalsDefaultGroovy() {

List<String> list1 = new ArrayList<>(count);
List<String> list2 = new ArrayList<>(count);

for( int i=0; i<count; i++) {
list1.add(UUID.randomUUID().toString());
list2.add(UUID.randomUUID().toString());
}

ListHelper.equals(list1, list2);
ListHelper.equals(list1, new ArrayList<>(list1));
}

@Benchmark
public void equalsWithAnnotation() {

List<String> list1 = new ListWithAnnotation<>(count);
List<String> list2 = new ArrayList<>(count);

for( int i=0; i<count; i++) {
list1.add(UUID.randomUUID().toString());
list2.add(UUID.randomUUID().toString());
}

ListHelper.equalsWithAnnotation(list1, list2);
ListHelper.equalsWithAnnotation(list1, new ListWithAnnotation<>(list1));
}

@Benchmark
public void equalsWithInterface() {

List<String> list1 = new ListWithInterface<>(count);
List<String> list2 = new ListWithInterface<>(count);

for( int i=0; i<count; i++) {
list1.add(UUID.randomUUID().toString());
list2.add(UUID.randomUUID().toString());
}

ListHelper.equalsWithInterface(list1, list2);
ListHelper.equalsWithInterface(list1, new ListWithInterface<>(list1));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.apache.groovy.bench.list;

import java.util.Iterator;
import java.util.List;

import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;

/**
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
public class ListHelper {

public static boolean equals(List left, List right) {
if (left == null) {
return right == null;
}
if (right == null) {
return false;
}
if (left == right) {
return true;
}
if (left.size() != right.size()) {
return false;
}
final Iterator it1 = left.iterator(), it2 = right.iterator();
while (it1.hasNext()) {
final Object o1 = it1.next();
final Object o2 = it2.next();
if (o1 == null) {
if (o2 != null) return false;
} else if (!coercedEquals(o1, o2)) {
return false;
}
}
return true;
}

public static boolean equalsWithAnnotation(List left, List right) {
if (left == null) {
return right == null;
}
if (right == null) {
return false;
}
if (left == right) {
return true;
}
if( left.getClass().getAnnotation(MarkerAnnotation.class)!=null && right.getClass().getAnnotation(MarkerAnnotation.class)!=null ) {
return left.equals(right);
}
if (left.size() != right.size()) {
return false;
}
final Iterator it1 = left.iterator(), it2 = right.iterator();
while (it1.hasNext()) {
final Object o1 = it1.next();
final Object o2 = it2.next();
if (o1 == null) {
if (o2 != null) return false;
} else if (!coercedEquals(o1, o2)) {
return false;
}
}
return true;
}

public static boolean equalsWithInterface(List left, List right) {
if (left == null) {
return right == null;
}
if (right == null) {
return false;
}
if (left == right) {
return true;
}
if( left instanceof MarkerInterface && right instanceof MarkerInterface) {
return left.equals(right);
}
if (left.size() != right.size()) {
return false;
}
final Iterator it1 = left.iterator(), it2 = right.iterator();
while (it1.hasNext()) {
final Object o1 = it1.next();
final Object o2 = it2.next();
if (o1 == null) {
if (o2 != null) return false;
} else if (!coercedEquals(o1, o2)) {
return false;
}
}
return true;
}

private static boolean coercedEquals(Object o1, Object o2) {
if (o1 instanceof Comparable) {
if (!(o2 instanceof Comparable && DefaultGroovyMethods.numberAwareCompareTo((Comparable) o1, (Comparable) o2) == 0)) {
return false;
}
}
return DefaultTypeTransformation.compareEqual(o1, o2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.apache.groovy.bench.list;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
@MarkerAnnotation
public class ListWithAnnotation<T> extends ArrayList<T> {

ListWithAnnotation(int size) { super(size); }

ListWithAnnotation(Collection<T> c) { super(c); }

public boolean equals(Object obj) {
return ListHelper.equals(this, (List) obj);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.apache.groovy.bench.list;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
public class ListWithInterface<T> extends ArrayList<T> implements MarkerInterface {

ListWithInterface(int size) { super(size); }

ListWithInterface(Collection<T> c) { super(c); }

public boolean equals(Object obj) {
return ListHelper.equals(this, (List) obj);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.apache.groovy.bench.list;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Marker interface to by-pass the default groovy formatting
* and equality rules and allowing a user to provide a custom
* format and equals method
*
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface MarkerAnnotation {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.apache.groovy.bench.list;

/**
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/
interface MarkerInterface {
}

0 comments on commit d37d1ae

Please sign in to comment.