Added the rest of the performance tests

Will probably need tweaking.
This commit is contained in:
Bruce Eckel 2016-08-09 10:21:47 -06:00
parent 0346fc747b
commit a17f939fd9
12 changed files with 217 additions and 428 deletions

View File

@ -1,4 +1,4 @@
// understandingcollections/RandomBounds.java
// control/RandomBounds.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
@ -7,16 +7,9 @@
import onjava.*;
public class RandomBounds {
static void usage() {
System.out.println("Usage:");
System.out.println("\tRandomBounds lower");
System.out.println("\tRandomBounds upper");
System.exit(1);
}
public static void main(String[] args) {
if(args.length != 1) usage();
new TimedAbort(3);
switch(args[0]) {
switch(args.length == 0 ? "" : args[0]) {
case "lower":
while(Math.random() != 0.0)
; // Keep trying
@ -28,7 +21,10 @@ public class RandomBounds {
System.out.println("Produced 1.0!");
break;
default:
usage();
System.out.println("Usage:");
System.out.println("\tRandomBounds lower");
System.out.println("\tRandomBounds upper");
System.exit(1);
}
}
}

View File

@ -1,4 +1,4 @@
// understandingcollections/Lists.java
// understandingcollections/ListOps.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
@ -6,7 +6,7 @@
import java.util.*;
import onjava.*;
public class Lists {
public class ListOps {
private static boolean b;
private static String s;
private static int i;

View File

@ -1,211 +0,0 @@
// understandingcollections/ListPerformance.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
// Demonstrates performance differences in Lists
// Small to keep build testing short:
// {java ListPerformance 100 500}
import java.util.*;
import onjava.*;
public class ListPerformance {
static SplittableRandom rand = new SplittableRandom();
static int reps = 1000;
static List<Test<List<Integer>>> tests =
new ArrayList<>();
static List<Test<LinkedList<Integer>>> qTests =
new ArrayList<>();
static {
tests.add(new Test<List<Integer>>("add") {
@Override
int test(List<Integer> list, TestParam tp) {
int loops = tp.loops;
int listSize = tp.size;
for(int i = 0; i < loops; i++) {
list.clear();
for(int j = 0; j < listSize; j++)
list.add(j);
}
return loops * listSize;
}
});
tests.add(new Test<List<Integer>>("get") {
@Override
int test(List<Integer> list, TestParam tp) {
int loops = tp.loops * reps;
int listSize = list.size();
for(int i = 0; i < loops; i++)
list.get(rand.nextInt(listSize));
return loops;
}
});
tests.add(new Test<List<Integer>>("set") {
@Override
int test(List<Integer> list, TestParam tp) {
int loops = tp.loops * reps;
int listSize = list.size();
for(int i = 0; i < loops; i++)
list.set(rand.nextInt(listSize), 47);
return loops;
}
});
tests.add(new Test<List<Integer>>("iteradd") {
@Override
int test(List<Integer> list, TestParam tp) {
final int LOOPS = 1000000;
int half = list.size() / 2;
ListIterator<Integer> it =
list.listIterator(half);
for(int i = 0; i < LOOPS; i++)
it.add(47);
return LOOPS;
}
});
tests.add(new Test<List<Integer>>("insert") {
@Override
int test(List<Integer> list, TestParam tp) {
int loops = tp.loops;
for(int i = 0; i < loops; i++)
list.add(5, 47); // Minimize random-access cost
return loops;
}
});
tests.add(new Test<List<Integer>>("remove") {
@Override
int test(List<Integer> list, TestParam tp) {
int loops = tp.loops;
int size = tp.size;
for(int i = 0; i < loops; i++) {
list.clear();
list.addAll(new CountingIntegerList(size));
while(list.size() > 5)
list.remove(5); // Minimize random-access cost
}
return loops * size;
}
});
// Tests for queue behavior:
qTests.add(new Test<LinkedList<Integer>>("addFirst") {
@Override
int test(LinkedList<Integer> list, TestParam tp) {
int loops = tp.loops;
int size = tp.size;
for(int i = 0; i < loops; i++) {
list.clear();
for(int j = 0; j < size; j++)
list.addFirst(47);
}
return loops * size;
}
});
qTests.add(new Test<LinkedList<Integer>>("addLast") {
@Override
int test(LinkedList<Integer> list, TestParam tp) {
int loops = tp.loops;
int size = tp.size;
for(int i = 0; i < loops; i++) {
list.clear();
for(int j = 0; j < size; j++)
list.addLast(47);
}
return loops * size;
}
});
qTests.add(
new Test<LinkedList<Integer>>("rmFirst") {
@Override
int test(LinkedList<Integer> list, TestParam tp) {
int loops = tp.loops;
int size = tp.size;
for(int i = 0; i < loops; i++) {
list.clear();
list.addAll(new CountingIntegerList(size));
while(list.size() > 0)
list.removeFirst();
}
return loops * size;
}
});
qTests.add(new Test<LinkedList<Integer>>("rmLast") {
@Override
int test(LinkedList<Integer> list, TestParam tp) {
int loops = tp.loops;
int size = tp.size;
for(int i = 0; i < loops; i++) {
list.clear();
list.addAll(new CountingIntegerList(size));
while(list.size() > 0)
list.removeLast();
}
return loops * size;
}
});
}
static class ListTester extends Tester<List<Integer>> {
public ListTester(List<Integer> collection,
List<Test<List<Integer>>> tests) {
super(collection, tests);
}
// Fill to the appropriate size before each test:
@Override
protected List<Integer> initialize(int size) {
collection.clear();
collection.addAll(new CountingIntegerList(size));
return collection;
}
// Convenience method:
public static void run(List<Integer> list,
List<Test<List<Integer>>> tests) {
new ListTester(list, tests).timedTest();
}
}
public static void main(String[] args) {
if(args.length > 0)
Tester.defaultParams = TestParam.array(args);
// Can only do these two tests on an array:
Tester<List<Integer>> arrayTest =
new Tester<List<Integer>>(null,
tests.subList(1, 3)) {
// This is called before each test. It
// produces a non-resizeable array-backed list:
@Override protected
List<Integer> initialize(int size) {
Integer[] ia = new Integer[size];
Arrays.setAll(ia, new Count.Integer()::get);
return Arrays.asList(ia);
}
};
arrayTest.setHeadline("Array as List");
arrayTest.timedTest();
Tester.defaultParams= TestParam.array(
10, 5000, 100, 5000, 1000, 1000, 10000, 200);
if(args.length > 0)
Tester.defaultParams = TestParam.array(args);
ListTester.run(new ArrayList<>(), tests);
ListTester.run(new LinkedList<>(), tests);
ListTester.run(new Vector<>(), tests);
Tester.fieldWidth = 12;
Tester<LinkedList<Integer>> qTest =
new Tester<LinkedList<Integer>>(
new LinkedList<>(), qTests);
qTest.setHeadline("Queue tests");
qTest.timedTest();
}
}
/* Output:
--- Array as List ---
size get set
100 50 68
--------------------- ArrayList ---------------------
size add get set iteradd insert remove
100 60 76 74 103 0 360
--------------------- LinkedList ---------------------
size add get set iteradd insert remove
100 200 166 114 201 0 120
----------------------- Vector -----------------------
size add get set iteradd insert remove
100 60 76 84 159 0 220
-------------------- Queue tests --------------------
size addFirst addLast rmFirst rmLast
100 80 160 100 120
*/

View File

@ -1,4 +1,4 @@
// understandingcollections/Maps.java
// understandingcollections/MapOps.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
@ -7,7 +7,7 @@ import java.util.concurrent.*;
import java.util.*;
import onjava.*;
public class Maps {
public class MapOps {
public static void printKeys(Map<Integer,String> map) {
System.out.print("Size = " + map.size() + ", ");
System.out.print("Keys: ");

View File

@ -1,70 +0,0 @@
// understandingcollections/SetPerformance.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
// Demonstrates performance differences in Sets
// Small to keep build testing short:
// {java SetPerformance 100 5000}
import java.util.*;
public class SetPerformance {
static List<Test<Set<Integer>>> tests =
new ArrayList<>();
static {
tests.add(new Test<Set<Integer>>("add") {
@Override
int test(Set<Integer> set, TestParam tp) {
int loops = tp.loops;
int size = tp.size;
for(int i = 0; i < loops; i++) {
set.clear();
for(int j = 0; j < size; j++)
set.add(j);
}
return loops * size;
}
});
tests.add(new Test<Set<Integer>>("contains") {
@Override
int test(Set<Integer> set, TestParam tp) {
int loops = tp.loops;
int span = tp.size * 2;
for(int i = 0; i < loops; i++)
for(int j = 0; j < span; j++)
set.contains(j);
return loops * span;
}
});
tests.add(new Test<Set<Integer>>("iterate") {
@Override
int test(Set<Integer> set, TestParam tp) {
int loops = tp.loops * 10;
for(int i = 0; i < loops; i++) {
Iterator<Integer> it = set.iterator();
while(it.hasNext())
it.next();
}
return loops * set.size();
}
});
}
public static void main(String[] args) {
if(args.length > 0)
Tester.defaultParams = TestParam.array(args);
Tester.fieldWidth = 10;
Tester.run(new TreeSet<>(), tests);
Tester.run(new HashSet<>(), tests);
Tester.run(new LinkedHashSet<>(), tests);
}
}
/* Output:
------------- TreeSet -------------
size add contains iterate
100 256 162 31
------------- HashSet -------------
size add contains iterate
100 88 58 43
---------- LinkedHashSet ----------
size add contains iterate
100 100 46 23
*/

View File

@ -1,13 +0,0 @@
// understandingcollections/Test.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
// Framework for performing timed tests of collections
public abstract class Test<C> {
String name;
public Test(String name) { this.name = name; }
// Override this method for different tests.
// Returns actual number of repetitions of test.
abstract int test(C collection, TestParam tp);
}

View File

@ -1,30 +0,0 @@
// understandingcollections/TestParam.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
// A "data transfer object."
public class TestParam {
public final int size;
public final int loops;
public TestParam(int size, int loops) {
this.size = size;
this.loops = loops;
}
// Create an array of TestParam from a varargs sequence:
public static TestParam[] array(int... values) {
int size = values.length/2;
TestParam[] result = new TestParam[size];
int n = 0;
for(int i = 0; i < size; i++)
result[i] = new TestParam(values[n++], values[n++]);
return result;
}
// Convert a String array to a TestParam array:
public static TestParam[] array(String[] values) {
int[] vals = new int[values.length];
for(int i = 0; i < vals.length; i++)
vals[i] = Integer.decode(values[i]);
return array(vals);
}
}

View File

@ -1,84 +0,0 @@
// understandingcollections/Tester.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
// Applies Test objects to lists of different collections
import java.util.*;
import java.time.*;
public class Tester<C> {
public static int fieldWidth = 8;
public static
TestParam[] defaultParams= TestParam.array(
10, 5000, 100, 5000, 1000, 5000, 10000, 500);
// Override this to modify pre-test initialization:
protected C initialize(int size) { return collection; }
protected C collection;
private String headline = "";
private List<Test<C>> tests;
private static int sizeWidth = 5;
private static String sizeField = "%" + sizeWidth + "s";
private TestParam[] paramList = defaultParams;
public Tester(C collection, List<Test<C>> tests) {
this.collection = collection;
this.tests = tests;
if(collection != null)
headline = collection.getClass().getSimpleName();
}
public Tester(C collection, List<Test<C>> tests,
TestParam[] paramList) {
this(collection, tests);
this.paramList = paramList;
}
public void setHeadline(String newHeadline) {
headline = newHeadline;
}
// Generic methods for convenience :
public static
<C> void run(C cntnr, List<Test<C>> tests) {
new Tester<>(cntnr, tests).timedTest();
}
public static <C> void run(C cntnr,
List<Test<C>> tests, TestParam[] paramList) {
new Tester<>(cntnr, tests, paramList).timedTest();
}
private void displayHeader() {
// Calculate width and pad with '-':
int width = fieldWidth * tests.size() + sizeWidth;
int dashLength = width - headline.length() - 1;
StringBuilder head = new StringBuilder(width);
for(int i = 0; i < dashLength/2; i++)
head.append('-');
head.append(' ');
head.append(headline);
head.append(' ');
for(int i = 0; i < dashLength/2; i++)
head.append('-');
System.out.println(head);
// Print column headers:
System.out.format(sizeField, "size");
for(Test<C> test : tests)
System.out.format(
"%" + fieldWidth + "s", test.name);
System.out.println();
}
// Run the tests for this collection:
public void timedTest() {
displayHeader();
for(TestParam param : paramList) {
System.out.format(sizeField, param.size);
for(Test<C> test : tests) {
C kontainer = initialize(param.size);
Instant start = Instant.now();
// Call the overriden method:
int reps = test.test(kontainer, param);
Duration elapsed =
Duration.between(start, Instant.now());
Duration timePerRep = elapsed.dividedBy(reps);
System.out.format("%" + fieldWidth + "d",
timePerRep.toNanos());
}
System.out.println();
}
}
}

View File

@ -0,0 +1,81 @@
// understandingcollections/jmhtests/Lists.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
// Demonstrates performance differences in Lists
package understandingcollections.jmhtests;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import java.util.*;
import static java.util.concurrent.TimeUnit.*;
@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = SECONDS)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(MICROSECONDS)
public class Lists {
private List<Integer> list;
@Param({"ArrayList", "LinkedList", "Vector"})
private String type;
private int begin;
private int end;
@Setup
public void setup() {
switch(type) {
case "ArrayList":
list = new ArrayList<>();
break;
case "LinkedList":
list = new LinkedList<>();
break;
case "Vector":
list = new Vector<>();
break;
default:
throw new IllegalStateException("Unknown " + type);
}
begin = 0;
end = 256;
for(int i = begin; i < end; i++) {
list.add(i);
}
}
@Benchmark
public void add() {
for(int i = begin; i < end; i++)
list.add(i);
}
@Benchmark
public void get(Blackhole bh) {
for(int i = begin; i < end; i++)
bh.consume(list.get(i));
}
@Benchmark
public void set() {
for(int i = begin; i < end; i++)
list.set(i, 47);
}
@Benchmark
public void iteradd() {
int half = list.size() / 2;
ListIterator<Integer> it =
list.listIterator(half);
for(int i = begin; i < end; i++)
it.add(47);
}
@Benchmark
public void insert() {
for(int i = begin; i < end; i++)
list.add(5, 47);
}
@Benchmark
public void remove() {
while(list.size() > 5)
list.remove(5);
}
}

View File

@ -14,7 +14,7 @@ import static java.util.concurrent.TimeUnit.*;
@Measurement(iterations = 5, time = 1, timeUnit = SECONDS)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(NANOSECONDS)
@OutputTimeUnit(MICROSECONDS)
public class Maps {
private Map<Integer, Integer> map;
@ -49,33 +49,28 @@ public class Maps {
default:
throw new IllegalStateException("Unknown " + type);
}
begin = 1;
end = 256;
for (int i = begin; i < end; i++) {
map.put(i, i);
}
}
@Benchmark
public void get(Blackhole bh) {
for (int i = begin; i < end; i++) {
bh.consume(map.get(i));
}
}
@Benchmark
public void put() {
for (int i = begin; i < end; i++) {
map.put(i, i);
}
}
@Benchmark
public void iterate(Blackhole bh) {
Iterator it = map.entrySet().iterator();
while(it.hasNext())
bh.consume(it.next());
}
}

View File

@ -0,0 +1,62 @@
// understandingcollections/jmhtests/Queues.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
// Demonstrates performance differences in Queues
package understandingcollections.jmhtests;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import java.util.*;
import static java.util.concurrent.TimeUnit.*;
@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = SECONDS)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(MICROSECONDS)
public class Queues {
private LinkedList<Integer> queue;
@Param({"LinkedList"})
private String type;
private int begin;
private int end;
@Setup
public void setup() {
switch(type) {
case "LinkedList":
queue = new LinkedList<>();
break;
default:
throw new IllegalStateException("Unknown " + type);
}
begin = 1;
end = 256;
for(int i = begin; i < end; i++) {
queue.add(i);
}
}
@Benchmark
public void queue_addFirst() {
for(int i = begin; i < end; i++)
queue.addFirst(47);
}
@Benchmark
public void queue_addLast() {
for(int i = begin; i < end; i++)
queue.addLast(47);
}
@Benchmark
public void queue_removeFirst(Blackhole bh) {
while(queue.size() > 0)
bh.consume(queue.removeFirst());
}
@Benchmark
public void queue_removeLast(Blackhole bh) {
while(queue.size() > 0)
bh.consume(queue.removeLast());
}
}

View File

@ -0,0 +1,63 @@
// understandingcollections/jmhtests/Sets.java
// (c)2016 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
// Demonstrates performance differences in Sets
package understandingcollections.jmhtests;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import java.util.*;
import static java.util.concurrent.TimeUnit.*;
@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = SECONDS)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(MICROSECONDS)
public class Sets {
private Set<Integer> set;
@Param({"HashSet", "TreeSet", "LinkedHashSet"})
private String type;
private int begin;
private int end;
@Setup
public void setup() {
switch(type) {
case "HashSet":
set = new HashSet<>();
break;
case "TreeSet":
set = new TreeSet<>();
break;
case "LinkedHashSet":
set = new LinkedHashSet<>();
break;
default:
throw new IllegalStateException("Unknown " + type);
}
begin = 1;
end = 256;
for (int i = begin; i < end; i++)
set.add(i);
}
@Benchmark
public void add() {
for(int i = begin; i < end; i++)
set.add(i);
}
@Benchmark
public void contains(Blackhole bh) {
for(int i = begin; i < end; i++)
bh.consume(set.contains(i));
}
@Benchmark
public void iterate(Blackhole bh) {
Iterator<Integer> it = set.iterator();
while(it.hasNext())
bh.consume(it.next());
}
}