blob: 4185d553e31740a20ad769826c74052e3dd9ef05 [file] [log] [blame]
Jesse Wilsonf062bf42010-01-13 17:12:18 -08001/*
2 * Copyright (C) 2009 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package examples;
18
19import com.google.caliper.Param;
20import com.google.caliper.Runner;
21import com.google.caliper.SimpleBenchmark;
22import com.google.common.collect.ImmutableSet;
23import java.util.Arrays;
24import java.util.Collection;
25import java.util.Collections;
26import java.util.HashSet;
27import java.util.LinkedHashSet;
28import java.util.Random;
29import java.util.Set;
30
31/**
32 * A microbenchmark that tests the performance of contains() on various Set
33 * implementations.
34 *
35 * @author Kevin Bourrillion
36 */
37public class SetContainsBenchmark extends SimpleBenchmark {
38 @Param private Impl impl;
39
40 // So far, this is the best way to test various implementations
41 public enum Impl {
42 Hash {
43 @Override Set<Integer> create(Collection<Integer> contents) {
44 return new HashSet<Integer>(contents);
45 }
46 },
47 LinkedHash {
48 @Override Set<Integer> create(Collection<Integer> contents) {
49 return new LinkedHashSet<Integer>(contents);
50 }
51 },
52 UnmodHS {
53 @Override Set<Integer> create(Collection<Integer> contents) {
54 return Collections.unmodifiableSet(new HashSet<Integer>(contents));
55 }
56 },
57 SyncHS {
58 @Override Set<Integer> create(Collection<Integer> contents) {
59 return Collections.synchronizedSet(new HashSet<Integer>(contents));
60 }
61 },
62
63 // Kind of cheating here -- Caliper just happens to bundle Google Collections so I'm testing
64 // this from it; this might not work at the command line since GC are jarjar'd for caliper.jar
65 Immutable {
66 @Override Set<Integer> create(Collection<Integer> contents) {
67 return ImmutableSet.copyOf(contents);
68 }
69 };
70
71 abstract Set<Integer> create(Collection<Integer> contents);
72 }
73
74 @Param private int size;
75 public static final Collection<Integer> sizeValues = Arrays.asList(
76 (1<<2) - 1,
77 (1<<2),
78 (1<<6) - 1,
79 (1<<6),
80 (1<<10) - 1,
81 (1<<10),
82 (1<<14) - 1,
83 (1<<14),
84 (1<<18) - 1,
85 (1<<18)
86 );
87
88 // "" means no fixed seed
89 @Param("") private SpecialRandom random;
90
91 // the following must be set during setUp
92 private Integer[] queries;
93 private Set<Integer> setToTest;
94
95 // Queries are just sequential integers. Since the contents of the set were
96 // chosen randomly, this shouldn't cause any undue bias.
97 @Override public void setUp() {
98 this.queries = new Integer[size * 2];
99 for (int i = 0; i < size * 2; i++) {
100 queries[i] = i;
101 }
102 Collections.shuffle(Arrays.asList(queries), random);
103
104 setToTest = impl.create(createData());
105 }
106
107 private Collection<Integer> createData() {
108 Set<Integer> tempSet = new HashSet<Integer>(size * 3 / 2);
109
110 // Choose 50% of the numbers between 0 and max to be in the set; thus we
111 // are measuring performance of contains() when there is a 50% hit rate
112 int max = size * 2;
113 while (tempSet.size() < size) {
114 tempSet.add(random.nextInt(max));
115 }
116 return tempSet;
117 }
118
119 public boolean timeContains(int reps) {
120 // Paranoia: acting on hearsay that accessing fields might be slow
121 // Should write a benchmark to test that!
122 Set<Integer> set = setToTest;
123 Integer[] queries = this.queries;
124
125 // Allows us to use & instead of %, acting on hearsay that division operators (/%) are
126 // disproportionately expensive; should test this too!
127 int mask = Integer.highestOneBit(size * 2) - 1;
128
129 boolean dummy = false;
130 for (int i = 0; i < reps; i++) {
131 dummy ^= set.contains(queries[i & mask]);
132 }
133 return dummy;
134 }
135
136 // TODO: remove this from all examples when IDE plugins are ready
137 public static void main(String[] args) throws Exception {
138 Runner.main(SetContainsBenchmark.class, args);
139 }
140
141
142 // Just an experiment with a slightly nicer way to create Randoms for benchies
143
144 public static class SpecialRandom extends Random {
145 public static SpecialRandom valueOf(String s) {
146 return (s.length() == 0)
147 ? new SpecialRandom()
148 : new SpecialRandom(Long.parseLong(s));
149 }
150
151 private final boolean hasSeed;
152 private final long seed;
153
154 public SpecialRandom() {
155 this.hasSeed = false;
156 this.seed = 0;
157 }
158
159 public SpecialRandom(long seed) {
160 super(seed);
161 this.hasSeed = true;
162 this.seed = seed;
163 }
164
165 @Override public String toString() {
166 return hasSeed ? "(seed:" + seed : "(default seed)";
167 }
168
169 private static final long serialVersionUID = 0;
170 }
171}