blob: fc1338aeebf23ed5787862d3f0fa7d136bc69869 [file] [log] [blame]
/**
* Copyright (c) 2013 Eclipse contributors and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*/
package org.eclipse.emf.test.core;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.impl.ENamedElementImpl;
import org.eclipse.emf.ecore.impl.EPackageImpl;
import org.eclipse.emf.ecore.util.EObjectContainmentEList;
import org.eclipse.emf.test.core.common.util.URITest;
/**
* A harness for micro benchmarking.
* Run this harness with the <code>-XX:+PrintCompilation</code> and <code>-verbose:gc</code>
* to ensure that you're collecting measurements after JITing as completed and that no garbage collection overhead is affecting the result.
*/
public class BenchmarkHarness
{
/**
* Formatting for nano seconds with three decimals of precision.
*/
protected static final NumberFormat NANO_SECOND_FORMAT = new DecimalFormat("#,##0.000");
/**
* Formatting for percentages with two decimals of precision.
*/
protected static final NumberFormat PERCENT_FORMAT = new DecimalFormat("###0.00");
/**
* The number of milliseconds in a second.
*/
protected static final long MILLI_SECONDS_PER_SECOND = 1000L;
/**
* The number of microseconds in a second.
*/
protected static final long MICRO_SECONDS_PER_SECOND = MILLI_SECONDS_PER_SECOND * 1000L;
/**
* The number of nanoseconds in a second.
*/
protected static final long NANO_SECONDS_PER_SECOND = MICRO_SECONDS_PER_SECOND * 1000L;
/**
* The number of picoseconds in a second.
*/
protected static final long PICO_SECONDS_PER_SECOND = NANO_SECONDS_PER_SECOND * 1000L;
/**
* An abstract base class for micro benchmark performance analysis.
*/
public static abstract class Benchmark
{
/**
* The number of units of work done by {@link #run()}.
*/
public int count;
/**
* The number of times the {@link #run()} must be invoked to perform at least 1 second total execution.
* This is updated by calibrate {@link BenchmarkHarness#calibrate(Benchmark)}.
*/
public int repeat = 1;
/**
* Creates an instance that will do the indicated number of units of work in {@link #run()}
* @param count
*/
public Benchmark(int count)
{
this.count = count;
}
/**
* Specialize this method to do {@link #count} units of work.
* I.e., write a loop like this
* <pre>
* int total = 0;
* for (int i = 0, count = this.count; i < count; ++i)
* {
* total += i;
* }
* return total;
* </pre>
* Be sure that some result from doing the unit of work, i.e., the body of the loop, affects the result.
* I.e., here we use the loop variable to compute a sum that we return.
*/
public abstract int run();
/**
* Returns a string representation of the code for the unit of work.
*/
public abstract String getLogic();
/**
* Cleans up the benchmark between measured runs.
* It's an opportunity to discard information accumulated during the measured executions of {@link #run()}.
*/
public void reset()
{
// Do nothing.
}
}
/**
* The accumulated result of the at the end of the call to {@link #measure(Benchmark)}.
*/
protected int accumulatedResult;
/**
* The number of seconds each benchmark should run.
*/
protected int interval;
/**
* Creates an instance.
* @see #run(int, Benchmark...)
*/
public BenchmarkHarness()
{
this(1);
}
/**
* Creates an instance.
* @see #run(int, Benchmark...)
*/
public BenchmarkHarness(int interval)
{
this.interval = interval;
}
/**
* Returns the average of the benchmark's measurements,
* optionally printing its statistics,
* i.e., the minimum, average, maximum, coefficient of variation, and the 95% confidence range.
*/
protected long summarize(boolean dump, Benchmark benchmark, long[] measurements)
{
int measurementCount = measurements.length;
// Computes the average.
//
long total = 0;
for (int i = 0; i < measurementCount; ++i)
{
long measurement = measurements[i];
total += measurement;
}
long average = total / measurementCount;
// If we're not printing statistics, we can just return now.
//
if (!dump)
{
return average;
}
// Sort the measurements.
//
Arrays.sort(measurements);
// Compute the bounds of the 90% confidence interval.
// I.e., the range within which 90% of the measurements lie.
//
int ci = measurementCount / 20;
long confidenceRangeLower = measurements[ci];
long confidenceRangeUpper = measurements[measurementCount - ci];
// Compute the standard deviation.
//
long sum = 0;
for (int i = 0; i < measurementCount; ++i)
{
long measurement = measurements[i];
long deviation = measurement - average;
sum += deviation * deviation;
}
sum /= (measurementCount - 1);
long standardDeviation = (long)Math.sqrt(sum);
// Dump the statistics.
//
System.err.println(benchmark.getLogic());
System.err.print(" ");
System.err.print(NANO_SECOND_FORMAT.format(measurements[0] / 1000.0));
System.err.print(" < ");
System.err.print(NANO_SECOND_FORMAT.format(average / 1000.0));
System.err.print(" < ");
System.err.print(NANO_SECOND_FORMAT.format(measurements[measurementCount - 1] / 1000.0));
System.err.print(" CV%: ");
System.err.print(PERCENT_FORMAT.format(standardDeviation * 100.0 / average));
System.err.print(" CR 90%: ");
System.err.print(NANO_SECOND_FORMAT.format(confidenceRangeLower / 1000.0));
System.err.print(" <- ");
System.err.print(NANO_SECOND_FORMAT.format(confidenceRangeUpper / 1000.0));
System.err.println();
System.err.flush();
return average;
}
/**
* Measure the time it takes to execute the benchmark, and increases the {@link Benchmark#repeat} to ensure that it runs for close to a full second.
* Returns a result derived from the benchmark execution to ensure that the JIT doesn't consider the benchmark execution dead code; it's a meaningless value.
*/
public int calibrate(Benchmark benchmark)
{
int total = 0;
benchmark.repeat *= 20;
for (;;)
{
benchmark.reset();
// Determine the elapsed interval for the benchmark.
//
long start = System.nanoTime();
for (int j = 0; j < benchmark.repeat; ++j)
{
total += benchmark.run();
}
long end = System.nanoTime();
long elapsedTime = end - start;
// Determine how many times the benchmark needs to be run in order to take close to a interval number of full seconds.
//
double fraction= (double)interval * benchmark.repeat * NANO_SECONDS_PER_SECOND / elapsedTime;
// Because we call this method recursively, check that the new count is at least 10% bigger than the repetitions we're already using...
//
if (fraction > 1.1 * benchmark.repeat)
{
// Calibrate again with the new repeat count to ensure that this does achieve a result close to one second.
//
benchmark.repeat = (int)fraction + 1;
}
else
{
break;
}
}
benchmark.reset();
// Return a meaningless result.
//
return total;
}
/**
* Measure the time it takes to execute the running, returning the average per unit time in picoseconds.
*/
public long measure(Benchmark benchmark)
{
// Execute the benchmark repeatedly and determine the elapsed nanosecond time interval for the benchmark.
// A meaningless result is accumulated to ensure that the JIT doesn't consider the execution to be dead code.
//
int repeat = benchmark.repeat;
int total = 0;
long start = System.nanoTime();
for (int j = 0; j < repeat; ++j)
{
total += benchmark.run();
}
long end = System.nanoTime();
long elapsedTime = end - start;
// Validate the benchmark has run long enough (at least 5 seconds) to make the inaccuracy in System.nanoTime() insignificant relative to the interval being measured.
//
if (elapsedTime < interval * NANO_SECONDS_PER_SECOND / 2)
{
double fraction = (double)interval * NANO_SECONDS_PER_SECOND / elapsedTime;
throw new RuntimeException("Measurement interval for the benchmark is less than " + interval / 2.0 + " seconds so the benchmark's repeat should have been increased by " + PERCENT_FORMAT.format(fraction) + "%");
}
// Accumulate the result into a globally visible value, again to ensure the JIT doesn't decide to stop running the benchmarks.
//
accumulatedResult += total;
benchmark.reset();
// Covert the time to pico seconds and divide by the benchmark's count and repeat to derive per-unit time.
//
return 1000L * elapsedTime / benchmark.count / repeat;
}
/**
* Executes the benchmark for the specified number of repetitions and dumps the measurement statistics.
*/
public void run(int repetitions, Benchmark benchmark)
{
System.out.flush();
System.err.println("Measuring");
System.err.println(benchmark.getLogic());
// Each run is already an average of many benchmark runs.
//
long[] averages = new long[repetitions];
for (int i = 0; i < repetitions; ++i)
{
averages[i] = measure(benchmark);
System.err.print(NANO_SECOND_FORMAT.format(averages[i] / 1000.0));
System.err.print(" ");
}
// Dump statistics about the averages of the averages.
//
System.err.println();
summarize(true, benchmark, averages);
}
/**
* Measure the performance of the given benchmarks,
* dumping their statistics
*/
public void run(int count, Benchmark... benchmarks)
{
// Calibrate the benchmarks and accumulate meaningless result to circumvent aggressive JIT optimization of dead code.
//
for (int i = 0; i < benchmarks.length; ++i)
{
accumulatedResult += calibrate(benchmarks[i]);
}
// Repeatedly measure the benchmarks and accumulate meaningless result to circumvent aggressive JIT optimization of dead code.
//
for (int i = 0; i < 10; ++i)
{
for (int j = 0; j < benchmarks.length; ++j)
{
run(count, benchmarks[j]);
}
}
// Print the final meaningless result.
//
System.out.println("Accumulated result: " + accumulatedResult);
}
public static class CountedLoop extends Benchmark
{
public CountedLoop()
{
super(1000000);
}
@Override
public int run()
{
int total = 0;
for (int i = 0; i < count; ++i)
{
total += i;
}
return total;
}
@Override
public String getLogic()
{
return "total += i;";
}
}
public static class CountedLoopWithLocalCounter extends Benchmark
{
public CountedLoopWithLocalCounter()
{
super(1000000);
}
@Override
public int run()
{
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i;
}
return total;
}
@Override
public String getLogic()
{
return "total += i; // With local count";
}
}
public static class CountedLoopWithAdd extends Benchmark
{
public CountedLoopWithAdd()
{
super(1000000);
}
@Override
public int run()
{
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + i;
}
return total;
}
@Override
public String getLogic()
{
return "total += i + i;";
}
}
public static class ArrayReadAtIndex extends Benchmark
{
protected int[] array;
protected Random random = new Random(0);
public ArrayReadAtIndex()
{
super(1000000);
array = new int[count];
for (int i = 0, count = this.count; i < count; ++i)
{
array[i] = random.nextInt();
}
}
@Override
public int run()
{
int[] array = this.array;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += array[i];
}
return total;
}
@Override
public String getLogic()
{
return "total += array[i];";
}
}
public static class ArrayReadAtIndexAndAddIndex extends Benchmark
{
protected int summary;
protected int[] array;
protected Random random = new Random(0);
public ArrayReadAtIndexAndAddIndex()
{
super(1000000);
array = new int[count];
for (int i = 0, count = this.count; i < count; ++i)
{
array[i] = random.nextInt();
}
}
@Override
public int run()
{
int[] array = this.array;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + array[i];
}
return total;
}
@Override
public String getLogic()
{
return "total += i + array[i];";
}
}
public static class ArrayReadAtIndexAndAddIndexWithArrayLengthGuard extends Benchmark
{
protected int summary;
protected int[] array;
protected Random random = new Random(0);
public ArrayReadAtIndexAndAddIndexWithArrayLengthGuard()
{
super(1000000);
array = new int[count];
for (int i = 0, count = this.count; i < count; ++i)
{
array[i] = random.nextInt();
}
}
@Override
public int run()
{
int[] array = this.array;
int total = 0;
for (int i = 0; i < array.length; ++i)
{
total += i + array[i];
}
return total;
}
@Override
public String getLogic()
{
return "total += i + array[i]; // With array length guard";
}
}
public static class ArrayReadAtIndexAddTwice extends Benchmark
{
protected int[] array;
protected Random random = new Random(0);
public ArrayReadAtIndexAddTwice()
{
super(1000000);
array = new int[count];
for (int i = 0; i < count; ++i)
{
array[i] = random.nextInt();
}
}
@Override
public int run()
{
int[] array = this.array;
int total = 0;
for (int i = 0; i < count; ++i)
{
total += i;
total += array[i];
}
return total;
}
@Override
public String getLogic()
{
return "total += i;\ntotal += array[i];";
}
}
public static class ArrayUpdateIndex extends Benchmark
{
protected int[] array;
protected Random random = new Random(0);
public ArrayUpdateIndex()
{
super(1000000);
array = new int[count];
for (int i = 0; i < count; ++i)
{
array[i] = random.nextInt();
}
}
@Override
public int run()
{
int[] array = this.array;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
array[i] = total += i + array[i];
}
return total;
}
@Override
public String getLogic()
{
return "array[i] = total += array[i];";
}
}
public static class StringArrayHashCode extends Benchmark
{
protected String[] array;
protected Random random = new Random(0);
public StringArrayHashCode()
{
super(1000000);
array = new String[count];
for (int i = 0, count = this.count; i < count; ++i)
{
array[i] = new String(String.valueOf(random.nextInt()));
}
}
@Override
public int run()
{
String[] array = this.array;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + array[i].hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + array[i].hashCode();";
}
}
public static class ObjectArrayHashCode extends Benchmark
{
protected Object[] array;
public ObjectArrayHashCode()
{
super(1000000);
array = new Object[count];
for (int i = 0, count = this.count; i < count; ++i)
{
array[i] = new Object();
}
}
@Override
public int run()
{
Object[] array = this.array;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + array[i].hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + array[i].hashCode();";
}
}
public static class StringArrayListHashCode extends Benchmark
{
protected ArrayList<String> list;
protected Random random = new Random(0);
public StringArrayListHashCode()
{
super(1000000);
list = new ArrayList<String>(count);
for (int i = 0; i < count; ++i)
{
list.add(new String(String.valueOf(random.nextInt())));
}
}
@Override
public int run()
{
ArrayList<String> list = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + list.get(i).hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + list.get(i).hashCode();";
}
}
public static class StringArrayListHashCodeWithSizeCall extends Benchmark
{
protected ArrayList<String> list;
protected Random random = new Random(0);
public StringArrayListHashCodeWithSizeCall()
{
super(1000000);
list = new ArrayList<String>(count);
for (int i = 0; i < count; ++i)
{
list.add(new String(String.valueOf(random.nextInt())));
}
}
@Override
public int run()
{
ArrayList<String> list = this.list;
int total = 0;
for (int i = 0; i < list.size(); ++i)
{
total += i + list.get(i).hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + list.get(i).hashCode();";
}
}
public static class StringBasicEListHashCode extends Benchmark
{
protected BasicEList<String> list;
protected Random random = new Random(0);
public StringBasicEListHashCode()
{
super(1000000);
list = new BasicEList<String>(count);
for (int i = 0; i < count; ++i)
{
list.add(new String(String.valueOf(random.nextInt())));
}
}
@Override
public int run()
{
BasicEList<String> eList = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + eList.get(i).hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + eList.get(i).hashCode();";
}
}
public static class StringArrayListHashCodeWithForEachLoop extends Benchmark
{
protected List<String> list;
protected Random random = new Random(0);
public StringArrayListHashCodeWithForEachLoop()
{
super(1000000);
list = new ArrayList<String>(count);
for (int i = 0; i < count; ++i)
{
list.add(new String(String.valueOf(random.nextInt())));
}
}
@Override
public int run()
{
List<String> list = this.list;
int total = 0;
for (String value : list)
{
total += value.hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "for (String value : list) {\n total += value.hashCode();\n}";
}
}
public static class StringBasicEListHashCodeWithForEachLoop extends Benchmark
{
protected List<String> list;
protected Random random = new Random(0);
public StringBasicEListHashCodeWithForEachLoop()
{
super(1000000);
list = new BasicEList<String>(count);
for (int i = 0; i < count; ++i)
{
list.add(new String(String.valueOf(random.nextInt())));
}
}
@Override
public int run()
{
List<String> eList = this.list;
int total = 0;
for (String value : eList)
{
total += value.hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "for (String value : eList) {\n total += value.hashCode();\n}";
}
}
public static class StringArrayCharAt extends Benchmark
{
protected String[] array;
protected Random random = new Random(0);
public StringArrayCharAt()
{
super(1000000);
array = new String[count];
for (int i = 0; i < count; ++i)
{
array[i] = new String(String.valueOf(random.nextInt()));
}
}
@Override
public int run()
{
String[] array = this.array;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + array[i].charAt(0);
}
return total;
}
@Override
public String getLogic()
{
return "total += i + array[i].charAt(0);";
}
}
public static class StringArrayListCharAt extends Benchmark
{
protected ArrayList<String> list;
protected Random random = new Random(0);
public StringArrayListCharAt()
{
super(1000000);
list = new ArrayList<String>(count);
for (int i = 0; i < count; ++i)
{
list.add(new String(String.valueOf(random.nextInt())));
}
}
@Override
public int run()
{
ArrayList<String> list = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + list.get(i).charAt(0);
}
return total;
}
@Override
public String getLogic()
{
return "total += i + list.get(i).charAt(0);";
}
}
public static class ENamedElementArrayGetName extends Benchmark
{
protected ENamedElement[] array;
protected Random random = new Random(0);
public ENamedElementArrayGetName()
{
super(1000000);
array = new ENamedElement[count];
for (int i = 0; i < count; ++i)
{
switch (random.nextInt(10))
{
case 0:
{
array[i] = EcoreFactory.eINSTANCE.createEAttribute();
break;
}
case 1:
{
array[i] = EcoreFactory.eINSTANCE.createEClass();
break;
}
case 2:
{
array[i] = EcoreFactory.eINSTANCE.createEDataType();
break;
}
case 3:
{
array[i] = EcoreFactory.eINSTANCE.createEEnum();
break;
}
case 4:
{
array[i] = EcoreFactory.eINSTANCE.createEEnumLiteral();
break;
}
case 5:
{
array[i] = EcoreFactory.eINSTANCE.createEOperation();
break;
}
case 6:
{
array[i] = EcoreFactory.eINSTANCE.createEPackage();
break;
}
case 7:
{
array[i] = EcoreFactory.eINSTANCE.createEParameter();
break;
}
case 8:
{
array[i] = EcoreFactory.eINSTANCE.createEReference();
break;
}
case 9:
{
array[i] = EcoreFactory.eINSTANCE.createETypeParameter();
break;
}
}
array[i].setName("_" + random.nextInt());
}
}
@Override
public int run()
{
ENamedElement[] array = this.array;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + array[i].getName().hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + array[i].getName().hashCode();";
}
}
public static class ENamedElementArrayListGetName extends Benchmark
{
protected List<ENamedElement> list;
protected Random random = new Random(0);
public ENamedElementArrayListGetName()
{
super(1000000);
list = new ArrayList<ENamedElement>(count);
for (int i = 0; i < count; ++i)
{
switch (random.nextInt(10))
{
case 0:
{
list.add(EcoreFactory.eINSTANCE.createEAttribute());
break;
}
case 1:
{
list.add(EcoreFactory.eINSTANCE.createEClass());
break;
}
case 2:
{
list.add(EcoreFactory.eINSTANCE.createEDataType());
break;
}
case 3:
{
list.add(EcoreFactory.eINSTANCE.createEEnum());
break;
}
case 4:
{
list.add(EcoreFactory.eINSTANCE.createEEnumLiteral());
break;
}
case 5:
{
list.add(EcoreFactory.eINSTANCE.createEOperation());
break;
}
case 6:
{
list.add(EcoreFactory.eINSTANCE.createEPackage());
break;
}
case 7:
{
list.add(EcoreFactory.eINSTANCE.createEParameter());
break;
}
case 8:
{
list.add(EcoreFactory.eINSTANCE.createEReference());
break;
}
case 9:
{
list.add(EcoreFactory.eINSTANCE.createETypeParameter());
break;
}
}
list.get(i).setName("_" + random.nextInt());
}
}
@Override
public int run()
{
List<ENamedElement> list = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + list.get(i).getName().hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + list.get(i).getName().hashCode();";
}
}
public static class EModelElementArrayListGetName extends Benchmark
{
protected List<Object> list;
protected Random random = new Random(0);
public EModelElementArrayListGetName()
{
super(1000000);
list = new ArrayList<Object>(count);
for (int i = 0; i < count; ++i)
{
switch (random.nextInt(10))
{
case 0:
{
list.add(EcoreFactory.eINSTANCE.createEAttribute());
break;
}
case 1:
{
list.add(EcoreFactory.eINSTANCE.createEClass());
break;
}
case 2:
{
list.add(EcoreFactory.eINSTANCE.createEDataType());
break;
}
case 3:
{
list.add(EcoreFactory.eINSTANCE.createEEnum());
break;
}
case 4:
{
list.add(EcoreFactory.eINSTANCE.createEEnumLiteral());
break;
}
case 5:
{
list.add(EcoreFactory.eINSTANCE.createEOperation());
break;
}
case 6:
{
list.add(EcoreFactory.eINSTANCE.createEPackage());
break;
}
case 7:
{
list.add(EcoreFactory.eINSTANCE.createEParameter());
break;
}
case 8:
{
list.add(EcoreFactory.eINSTANCE.createEReference());
break;
}
case 9:
{
list.add(EcoreFactory.eINSTANCE.createETypeParameter());
break;
}
}
((ENamedElement)list.get(i)).setName("_" + random.nextInt());
}
}
@Override
public int run()
{
List<Object> list = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + ((ENamedElement)list.get(i)).getName().hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + ((ENamedElement)list.get(i)).getName().hashCode();";
}
}
public static class ENamedElementArrayListContains extends Benchmark
{
protected List<ENamedElement> list;
protected ENamedElement lastENamedElement;
protected Random random = new Random(0);
public ENamedElementArrayListContains()
{
super(10000);
list = new ArrayList<ENamedElement>(count);
for (int i = 0; i < count; ++i)
{
switch (random.nextInt(10))
{
case 0:
{
list.add(EcoreFactory.eINSTANCE.createEAttribute());
break;
}
case 1:
{
list.add(EcoreFactory.eINSTANCE.createEClass());
break;
}
case 2:
{
list.add(EcoreFactory.eINSTANCE.createEDataType());
break;
}
case 3:
{
list.add(EcoreFactory.eINSTANCE.createEEnum());
break;
}
case 4:
{
list.add(EcoreFactory.eINSTANCE.createEEnumLiteral());
break;
}
case 5:
{
list.add(EcoreFactory.eINSTANCE.createEOperation());
break;
}
case 6:
{
list.add(EcoreFactory.eINSTANCE.createEPackage());
break;
}
case 7:
{
list.add(EcoreFactory.eINSTANCE.createEParameter());
break;
}
case 8:
{
list.add(EcoreFactory.eINSTANCE.createEReference());
break;
}
case 9:
{
list.add(EcoreFactory.eINSTANCE.createETypeParameter());
break;
}
}
(lastENamedElement = list.get(i)).setName("_" + random.nextInt());
}
}
@Override
public int run()
{
List<ENamedElement> list = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (list.contains(lastENamedElement) ? 1 : 0);
}
return total;
}
@Override
public String getLogic()
{
return "total += i + (list.contains(lastENamedElement) ? 1 : 0);";
}
}
public static class ENamedElementFastEListContains extends Benchmark
{
protected BasicEList.FastCompare<ENamedElement> list;
protected ENamedElement lastENamedElement;
protected Random random = new Random(0);
public ENamedElementFastEListContains()
{
super(1000);
list = new BasicEList.FastCompare<ENamedElement>(count);
for (int i = 0; i < count; ++i)
{
switch (random.nextInt(10))
{
case 0:
{
list.add(EcoreFactory.eINSTANCE.createEAttribute());
break;
}
case 1:
{
list.add(EcoreFactory.eINSTANCE.createEClass());
break;
}
case 2:
{
list.add(EcoreFactory.eINSTANCE.createEDataType());
break;
}
case 3:
{
list.add(EcoreFactory.eINSTANCE.createEEnum());
break;
}
case 4:
{
list.add(EcoreFactory.eINSTANCE.createEEnumLiteral());
break;
}
case 5:
{
list.add(EcoreFactory.eINSTANCE.createEOperation());
break;
}
case 6:
{
list.add(EcoreFactory.eINSTANCE.createEPackage());
break;
}
case 7:
{
list.add(EcoreFactory.eINSTANCE.createEParameter());
break;
}
case 8:
{
list.add(EcoreFactory.eINSTANCE.createEReference());
break;
}
case 9:
{
list.add(EcoreFactory.eINSTANCE.createETypeParameter());
break;
}
}
(lastENamedElement = list.get(i)).setName("_" + random.nextInt());
}
}
@Override
public int run()
{
BasicEList.FastCompare<ENamedElement> eList = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (eList.contains(lastENamedElement) ? 1 : 0);
}
return total;
}
@Override
public String getLogic()
{
return "total += i + (eList.contains(lastENamedElement) ? 1 : 0); // Fast compare";
}
}
public static class ENamedElementContainmentEListContains extends Benchmark
{
protected EObjectContainmentEList<ENamedElement> list;
protected ENamedElement lastENamedElement;
protected Random random = new Random(0);
@SuppressWarnings("unchecked")
public ENamedElementContainmentEListContains()
{
super(1000);
list = (EObjectContainmentEList<ENamedElement>)(EList<?>)EcoreFactory.eINSTANCE.createEAnnotation().getContents();
for (int i = 0; i < count; ++i)
{
switch (random.nextInt(10))
{
case 0:
{
list.add(EcoreFactory.eINSTANCE.createEAttribute());
break;
}
case 1:
{
list.add(EcoreFactory.eINSTANCE.createEClass());
break;
}
case 2:
{
list.add(EcoreFactory.eINSTANCE.createEDataType());
break;
}
case 3:
{
list.add(EcoreFactory.eINSTANCE.createEEnum());
break;
}
case 4:
{
list.add(EcoreFactory.eINSTANCE.createEEnumLiteral());
break;
}
case 5:
{
list.add(EcoreFactory.eINSTANCE.createEOperation());
break;
}
case 6:
{
list.add(EcoreFactory.eINSTANCE.createEPackage());
break;
}
case 7:
{
list.add(EcoreFactory.eINSTANCE.createEParameter());
break;
}
case 8:
{
list.add(EcoreFactory.eINSTANCE.createEReference());
break;
}
case 9:
{
list.add(EcoreFactory.eINSTANCE.createETypeParameter());
break;
}
}
(lastENamedElement = list.get(i)).setName("_" + random.nextInt());
}
}
@Override
public int run()
{
EObjectContainmentEList<ENamedElement> eList = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (eList.contains(lastENamedElement) ? 1 : 0);
}
return total;
}
@Override
public String getLogic()
{
return "total += i + (eList.contains(lastENamedElement) ? 1 : 0); // Containment list";
}
}
public static class ENamedElementHashSetContains extends Benchmark
{
protected HashSet<ENamedElement> set;
protected ENamedElement lastENamedElement;
protected Random random = new Random(0);
public ENamedElementHashSetContains()
{
super(1000);
set = new HashSet<ENamedElement>();
for (int i = 0; i < count; ++i)
{
switch (random.nextInt(10))
{
case 0:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEAttribute());
break;
}
case 1:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEClass());
break;
}
case 2:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEDataType());
break;
}
case 3:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEEnum());
break;
}
case 4:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEEnumLiteral());
break;
}
case 5:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEOperation());
break;
}
case 6:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEPackage());
break;
}
case 7:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEParameter());
break;
}
case 8:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEReference());
break;
}
case 9:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createETypeParameter());
break;
}
}
lastENamedElement.setName("_" + random.nextInt());
}
}
@Override
public int run()
{
HashSet<ENamedElement> set = this.set;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (set.contains(lastENamedElement) ? 1 : 0);
}
return total;
}
@Override
public String getLogic()
{
return " total += i + (set.contains(lastENamedElement) ? 1 : 0);";
}
}
public static class ENamedElementSynchronizedWrapperHashSetContains extends Benchmark
{
protected Set<ENamedElement> set;
protected ENamedElement lastENamedElement;
protected Random random = new Random(0);
public ENamedElementSynchronizedWrapperHashSetContains()
{
super(1000);
set = Collections.synchronizedSet(new HashSet<ENamedElement>());
for (int i = 0; i < count; ++i)
{
switch (random.nextInt(10))
{
case 0:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEAttribute());
break;
}
case 1:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEClass());
break;
}
case 2:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEDataType());
break;
}
case 3:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEEnum());
break;
}
case 4:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEEnumLiteral());
break;
}
case 5:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEOperation());
break;
}
case 6:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEPackage());
break;
}
case 7:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEParameter());
break;
}
case 8:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEReference());
break;
}
case 9:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createETypeParameter());
break;
}
}
lastENamedElement.setName("_" + random.nextInt());
}
}
@Override
public int run()
{
Set<ENamedElement> synchronizedSet = this.set;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (synchronizedSet.contains(lastENamedElement) ? 1 : 0);
}
return total;
}
@Override
public String getLogic()
{
return " total += i + (set.contains(lastENamedElement) ? 1 : 0); // Wrapped";
}
}
public static class ENamedElementSynchronizedOverrideHashSetContains extends Benchmark
{
protected Set<ENamedElement> set;
protected ENamedElement lastENamedElement;
protected Random random = new Random(0);
private static class MyHashSet<E> extends HashSet<E>
{
private static final long serialVersionUID = 1L;
@Override
public synchronized boolean contains(Object o)
{
return super.contains(o);
}
}
public ENamedElementSynchronizedOverrideHashSetContains()
{
super(1000);
set = new MyHashSet<ENamedElement>();
for (int i = 0; i < count; ++i)
{
switch (random.nextInt(10))
{
case 0:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEAttribute());
break;
}
case 1:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEClass());
break;
}
case 2:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEDataType());
break;
}
case 3:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEEnum());
break;
}
case 4:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEEnumLiteral());
break;
}
case 5:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEOperation());
break;
}
case 6:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEPackage());
break;
}
case 7:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEParameter());
break;
}
case 8:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createEReference());
break;
}
case 9:
{
set.add(lastENamedElement = EcoreFactory.eINSTANCE.createETypeParameter());
break;
}
}
lastENamedElement.setName("_" + random.nextInt());
}
}
@Override
public int run()
{
Set<ENamedElement> synchronizedSet = this.set;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (synchronizedSet.contains(lastENamedElement) ? 1 : 0);
}
return total;
}
@Override
public String getLogic()
{
return " total += i + (set.contains(lastENamedElement) ? 1 : 0); // Override";
}
}
public static class StringArrayListContains extends Benchmark
{
protected ArrayList<String> list;
protected String lastString;
protected Random random = new Random(0);
public StringArrayListContains()
{
super(1000);
list = new ArrayList<String>(count);
for (int i = 0; i < count; ++i)
{
list.add(lastString = new String(String.valueOf(random.nextInt())));
}
}
@Override
public int run()
{
ArrayList<String> list = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (list.contains(lastString) ? 0 : 1);
}
return total;
}
@Override
public String getLogic()
{
return "total += i + (list.contains(lastString) ? 0 : 1)";
}
}
public static class StringFastEListContains extends Benchmark
{
protected BasicEList.FastCompare<String> list;
protected String lastString;
protected Random random = new Random(0);
public StringFastEListContains()
{
super(1000);
list = new BasicEList.FastCompare<String>(count);
for (int i = 0; i < count; ++i)
{
list.add(lastString = new String(String.valueOf(random.nextInt())));
}
}
@Override
public int run()
{
BasicEList.FastCompare<String> list = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (list.contains(lastString) ? 0 : 1);
}
return total;
}
@Override
public String getLogic()
{
return "total += i + (list.contains(lastString) ? 0 : 1)";
}
}
public static class ObjectAllocation extends Benchmark
{
protected Object[] objects;
public ObjectAllocation()
{
super(10000);
objects = new Object[count];
}
@Override
public int run()
{
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (objects[i] = new Object()).hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + (objects[i] = new Object()).hashCode();";
}
}
public static class ObjectAllocation2 extends Benchmark
{
public ObjectAllocation2()
{
super(1000000);
}
@Override
public int run()
{
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + new Object().hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + new Object().hashCode();";
}
}
protected static class URICreation extends Benchmark
{
protected long counter;
protected int repetition;
protected String[][] strings;
protected URI[][] uris;
public URICreation()
{
super(10000);
reset();
}
@Override
public int run()
{
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (uris[repetition][i] = URI.createURI(strings[repetition][i])).hashCode();
}
++repetition;
return total;
}
@Override
public String getLogic()
{
return "total += i + (uris[repetition][i] = URI.createURI(strings[repetition][i])).hashCode();";
}
@Override
public void reset()
{
repetition = 0;
System.out.println("Reseting");
uris = new URI[repeat][];
strings = new String[repeat][];
System.gc();
System.gc();
for (int i = 0; i < repeat; ++i)
{
uris[i] = new URI[count];
strings[i] = new String[count];
for (int j = 0; j < count; ++j)
{
strings[i][j] = "platform:/resource/project/path/file/" + counter++;
}
}
System.gc();
System.gc();
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
// Let any daemons work for a while.
}
System.out.println("Finished reseting");
System.out.flush();
}
}
protected static class URI2Creation extends Benchmark
{
protected long counter;
protected int repetition;
protected String[][] strings;
protected URITest.URI2[][] uris;
public URI2Creation()
{
super(10000);
reset();
}
@Override
public int run()
{
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (uris[repetition][i] = URITest.URI2.createURI(strings[repetition][i])).hashCode();
}
++repetition;
return total;
}
@Override
public String getLogic()
{
return "total += i + (uris[repetition][i] = URITest.URI2.createURI(strings[repetition][i])).hashCode();";
}
@Override
public void reset()
{
repetition = 0;
System.out.println("Reseting");
uris = new URITest.URI2[repeat][];
strings = new String[repeat][];
System.gc();
System.gc();
for (int i = 0; i < repeat; ++i)
{
uris[i] = new URITest.URI2[count];
strings[i] = new String[count];
for (int j = 0; j < count; ++j)
{
strings[i][j] = "platform:/resource/project/path/file/" + counter++;
}
}
System.gc();
System.gc();
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
// Let any daemons work for a while.
}
System.out.println("Finished reseting");
System.out.flush();
}
}
public static class URIComparison extends Benchmark
{
protected URI uri1 = URI.createURI("platform:/resource/project/path/file/").appendSegment("0");
protected URI uri2 = URI.createURI("platform:/resource/project/path/file/").appendSegment("1");
protected URI uri3 = URI.createURI("platform:/resource/project/path/file/").appendSegment("2");
protected URI uri4 = URI.createURI("platform:/resource/project/path/file/").appendSegment("3");
protected Object[] choose = { uri1, uri2, uri3, uri4 };
public URIComparison()
{
super(100000);
}
@Override
public int run()
{
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (uri1.equals(choose[i & 3]) ? 1 : 0);
}
return total;
}
@Override
public String getLogic()
{
return "compare1";
}
}
public static class URI2Comparison extends Benchmark
{
protected URITest.URI2 uri1 = URITest.URI2.createURI("platform:/resource/project/path/file/").appendSegment("0");
protected URITest.URI2 uri2 = URITest.URI2.createURI("platform:/resource/project/path/file/").appendSegment("1");
protected URITest.URI2 uri3 = URITest.URI2.createURI("platform:/resource/project/path/file/").appendSegment("2");
protected URITest.URI2 uri4 = URITest.URI2.createURI("platform:/resource/project/path/file/").appendSegment("3");
protected Object[] choose = { uri1, uri2, uri3, uri4 };
public URI2Comparison()
{
super(100000);
}
@Override
public int run()
{
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + (uri1.equals(choose[i & 3]) ? 1 : 0);
}
return total;
}
@Override
public String getLogic()
{
return "compare2";
}
}
public static class HashMapGet extends Benchmark
{
protected HashMap<Object, String> map = new HashMap<Object, String>();
protected Object[] choose = { new Object(), new Object(), new Object(), new Object() };
public HashMapGet()
{
super(100000);
for (Object key : choose)
{
map.put(key, "x");
}
}
@Override
public int run()
{
Map<Object, String> map = this.map;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + map.get(choose[i & 3]).hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + map.get(choose[i & 3]).hashCode();";
}
}
public static class EObjectEGet extends Benchmark
{
protected EObject eObject = EcorePackage.eINSTANCE;
protected EStructuralFeature[] choose = { EcorePackage.Literals.EPACKAGE__NS_PREFIX, EcorePackage.Literals.ENAMED_ELEMENT__NAME, EcorePackage.Literals.EPACKAGE__NS_PREFIX, EcorePackage.Literals.EPACKAGE__NS_URI };
public EObjectEGet()
{
super(100000);
}
@Override
public int run()
{
EObject eObject = this.eObject;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + eObject.eGet(choose[i & 3]).hashCode();
}
return total;
}
@Override
public String getLogic()
{
return "total += i + eObject.eGet(choose[i & 3]).hashCode();";
}
}
public static class ReflectiveAccess extends Benchmark
{
protected Object object = EcorePackage.eINSTANCE;
protected Field[] choose;
public ReflectiveAccess()
{
super(100000);
try
{
Class<?> packageClass = EPackageImpl.class;
Class<?> namedElementClass = ENamedElementImpl.class;
choose =
new Field[]
{
packageClass.getDeclaredField("nsPrefix"),
namedElementClass.getDeclaredField("name"),
packageClass.getDeclaredField("nsPrefix"),
packageClass.getDeclaredField("nsURI"),
};
for (Field field : choose)
{
field.setAccessible(true);
}
}
catch (Throwable throwable)
{
throw new RuntimeException(throwable);
}
}
@Override
public int run()
{
try
{
Object object = this.object;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
total += i + choose[i & 3].get(object).hashCode();
}
return total;
}
catch (Exception exception)
{
throw new RuntimeException(exception);
}
}
@Override
public String getLogic()
{
return "total += i + choose[i & 3].get(object).hashCode();";
}
}
public static class LoopCounterEmpty extends Benchmark
{
protected int size ;
protected List<Object> list;
public LoopCounterEmpty(int size)
{
super(100000);
list = new ArrayList<Object>(size);
this.size = size;
for (int i = 0; i < size; ++i)
{
list.add(new Object());
}
}
@Override
public int run()
{
List<Object> list = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
for (int j = 0, size = list.size(); j < size; ++j)
{
total += i + list.get(j).hashCode();
}
}
return total;
}
@Override
public String getLogic()
{
return "for (int j = 0, size = list.size(); j < size; ++j)\n{\n total += i + list.get(j).hashCode();\n} // " + size;
}
}
public static class LoopForEachEmpty extends Benchmark
{
protected int size ;
protected List<Object> list;
public LoopForEachEmpty(int size)
{
super(100000);
list = new ArrayList<Object>(size);
this.size = size;
for (int i = 0; i < size; ++i)
{
list.add(new Object());
}
}
@Override
public int run()
{
List<Object> list = this.list;
int total = 0;
for (int i = 0, count = this.count; i < count; ++i)
{
for (Object object : list)
{
total += i + object.hashCode();
}
}
return total;
}
@Override
public String getLogic()
{
return "for (Object object : list)\n{\n total += i + object.hashCode();\n} // " + size;
}
}
public static void main(String[] args)
{
Benchmark[] benchmarks =
{
// new CountedLoop(),
// new CountedLoopWithLocalCounter(),
// new CountedLoopWithAdd(),
// new ArrayReadAtIndex(),
// new ArrayReadAtIndexAndAddIndex(),
// new ArrayReadAtIndexAndAddIndexWithArrayLengthGuard(),
// new ArrayReadAtIndexAddTwice(),
// new ArrayUpdateIndex(),
// new ObjectArrayHashCode(),
// new StringArrayHashCode(),
// new StringArrayListHashCode(),
// new StringArrayListHashCodeWithSizeCall(),
// new StringArrayListHashCodeWithForEachLoop(),
// new StringBasicEListHashCode(),
// new StringBasicEListHashCodeWithForEachLoop(),
// new ENamedElementArrayGetName(),
// new ENamedElementArrayListGetName(),
// new StringArrayCharAt(),
//new StringArrayListCharAt(),
// new EModelElementArrayListGetName(),
// new ENamedElementSynchronizedWrapperHashSetContains(),
// new ENamedElementSynchronizedOverrideHashSetContains(),
// new ENamedElementHashSetContains(),
// new ENamedElementContainmentEListContains(),
// new ENamedElementArrayListContains(),
// new ENamedElementFastEListContains(),
// new StringArrayListContains(),
// new StringFastEListContains(),
// new ObjectAllocation2(),
// new URICreation(),
// new URI2Creation(),
// new URI2Comparison(),
// new URIComparison(),
// new HashMapGet(),
// new EObjectEGet(),
// new ReflectiveAccess(),
// new LoopCounterEmpty(0),
// new LoopForEachEmpty(0),
// new LoopCounterEmpty(10),
// new LoopForEachEmpty(10),
};
new BenchmarkHarness(1).run(20, benchmarks);
}
}