ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/jtreg/util/Collection/RemoveMicroBenchmark.java
Revision: 1.7
Committed: Sun Nov 27 22:13:19 2016 UTC (7 years, 6 months ago) by jsr166
Branch: MAIN
Changes since 1.6: +32 -0 lines
Log Message:
add timed pollFirst, pollLast

File Contents

# User Rev Content
1 jsr166 1.1 /*
2     * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
3     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4     *
5     * This code is free software; you can redistribute it and/or modify it
6     * under the terms of the GNU General Public License version 2 only, as
7     * published by the Free Software Foundation.
8     *
9     * This code is distributed in the hope that it will be useful, but WITHOUT
10     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11     * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12     * version 2 for more details (a copy is included in the LICENSE file that
13     * accompanied this code).
14     *
15     * You should have received a copy of the GNU General Public License version
16     * 2 along with this work; if not, write to the Free Software Foundation,
17     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18     *
19     * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20     * or visit www.oracle.com if you need additional information or have any
21     * questions.
22     */
23    
24     /*
25     * @test
26     * @summary micro-benchmark correctness mode
27     * @run main RemoveMicroBenchmark iterations=1 size=8 warmup=0
28     */
29    
30     import java.lang.ref.WeakReference;
31     import java.util.ArrayDeque;
32     import java.util.Arrays;
33     import java.util.ArrayList;
34     import java.util.Collection;
35 jsr166 1.5 import java.util.Collections;
36 jsr166 1.1 import java.util.Deque;
37     import java.util.Enumeration;
38     import java.util.Iterator;
39     import java.util.LinkedList;
40     import java.util.List;
41     import java.util.ListIterator;
42     import java.util.Map;
43 jsr166 1.2 import java.util.PriorityQueue;
44 jsr166 1.1 import java.util.Spliterator;
45     import java.util.Vector;
46     import java.util.concurrent.ArrayBlockingQueue;
47 jsr166 1.7 import java.util.concurrent.BlockingDeque;
48 jsr166 1.3 import java.util.concurrent.BlockingQueue;
49 jsr166 1.1 import java.util.concurrent.ConcurrentLinkedDeque;
50     import java.util.concurrent.ConcurrentLinkedQueue;
51 jsr166 1.2 import java.util.concurrent.CountDownLatch;
52 jsr166 1.1 import java.util.concurrent.LinkedBlockingDeque;
53     import java.util.concurrent.LinkedBlockingQueue;
54     import java.util.concurrent.LinkedTransferQueue;
55 jsr166 1.2 import java.util.concurrent.PriorityBlockingQueue;
56 jsr166 1.1 import java.util.concurrent.ThreadLocalRandom;
57     import java.util.concurrent.TimeUnit;
58     import java.util.regex.Pattern;
59     import java.util.function.Supplier;
60    
61     /**
62     * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
63     *
64     * To run this in micro-benchmark mode, simply run as a normal java program.
65     * Be patient; this program runs for a very long time.
66     * For faster runs, restrict execution using command line args.
67     *
68     * @author Martin Buchholz
69     */
70     public class RemoveMicroBenchmark {
71     abstract static class Job {
72     private final String name;
73     public Job(String name) { this.name = name; }
74     public String name() { return name; }
75     public abstract void work() throws Throwable;
76     }
77    
78 jsr166 1.5 final int iterations;
79     final int size; // number of elements in collections
80     final double warmupSeconds;
81     final long warmupNanos;
82     final Pattern filter; // select subset of Jobs to run
83     final boolean reverse; // reverse order of Jobs
84     final boolean shuffle; // randomize order of Jobs
85    
86     RemoveMicroBenchmark(String[] args) {
87     iterations = intArg(args, "iterations", 10_000);
88     size = intArg(args, "size", 1000);
89     warmupSeconds = doubleArg(args, "warmup", 7.0);
90     filter = patternArg(args, "filter");
91     reverse = booleanArg(args, "reverse");
92     shuffle = booleanArg(args, "shuffle");
93    
94     warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
95     }
96 jsr166 1.1
97     // --------------- GC finalization infrastructure ---------------
98    
99     /** No guarantees, but effective in practice. */
100     static void forceFullGc() {
101     CountDownLatch finalizeDone = new CountDownLatch(1);
102     WeakReference<?> ref = new WeakReference<Object>(new Object() {
103     protected void finalize() { finalizeDone.countDown(); }});
104     try {
105     for (int i = 0; i < 10; i++) {
106     System.gc();
107     if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
108     System.runFinalization(); // try to pick up stragglers
109     return;
110     }
111     }
112     } catch (InterruptedException unexpected) {
113     throw new AssertionError("unexpected InterruptedException");
114     }
115     throw new AssertionError("failed to do a \"full\" gc");
116     }
117    
118     /**
119     * Runs each job for long enough that all the runtime compilers
120     * have had plenty of time to warm up, i.e. get around to
121     * compiling everything worth compiling.
122     * Returns array of average times per job per run.
123     */
124     long[] time0(List<Job> jobs) throws Throwable {
125     final int size = jobs.size();
126     long[] nanoss = new long[size];
127     for (int i = 0; i < size; i++) {
128     if (warmupNanos > 0) forceFullGc();
129 jsr166 1.4 Job job = jobs.get(i);
130     long totalTime;
131     int runs = 0;
132     long startTime = System.nanoTime();
133     do { job.work(); runs++; }
134     while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
135     nanoss[i] = totalTime/runs;
136 jsr166 1.1 }
137     return nanoss;
138     }
139    
140     void time(List<Job> jobs) throws Throwable {
141 jsr166 1.4 if (warmupNanos > 0) time0(jobs); // Warm up run
142 jsr166 1.1 final int size = jobs.size();
143     final long[] nanoss = time0(jobs); // Real timing run
144     final long[] milliss = new long[size];
145     final double[] ratios = new double[size];
146    
147     final String nameHeader = "Method";
148     final String millisHeader = "Millis";
149     final String ratioHeader = "Ratio";
150    
151     int nameWidth = nameHeader.length();
152     int millisWidth = millisHeader.length();
153     int ratioWidth = ratioHeader.length();
154    
155     for (int i = 0; i < size; i++) {
156     nameWidth = Math.max(nameWidth, jobs.get(i).name().length());
157    
158     milliss[i] = nanoss[i]/(1000L * 1000L);
159     millisWidth = Math.max(millisWidth,
160     String.format("%d", milliss[i]).length());
161    
162     ratios[i] = (double) nanoss[i] / (double) nanoss[0];
163     ratioWidth = Math.max(ratioWidth,
164     String.format("%.3f", ratios[i]).length());
165     }
166    
167     String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
168     nameWidth, millisWidth, ratioWidth);
169     String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
170     nameWidth, millisWidth, ratioWidth);
171     System.out.printf(headerFormat, "Method", "Millis", "Ratio");
172    
173     // Print out absolute and relative times, calibrated against first job
174     for (int i = 0; i < size; i++)
175     System.out.printf(format, jobs.get(i).name(), milliss[i], ratios[i]);
176     }
177    
178     private static String keywordValue(String[] args, String keyword) {
179     for (String arg : args)
180     if (arg.startsWith(keyword))
181     return arg.substring(keyword.length() + 1);
182     return null;
183     }
184    
185     private static int intArg(String[] args, String keyword, int defaultValue) {
186     String val = keywordValue(args, keyword);
187     return (val == null) ? defaultValue : Integer.parseInt(val);
188     }
189    
190     private static double doubleArg(String[] args, String keyword, double defaultValue) {
191     String val = keywordValue(args, keyword);
192     return (val == null) ? defaultValue : Double.parseDouble(val);
193     }
194    
195     private static Pattern patternArg(String[] args, String keyword) {
196     String val = keywordValue(args, keyword);
197     return (val == null) ? null : Pattern.compile(val);
198     }
199    
200 jsr166 1.5 private static boolean booleanArg(String[] args, String keyword) {
201     String val = keywordValue(args, keyword);
202     if (val == null || val.equals("false")) return false;
203     if (val.equals("true")) return true;
204     throw new IllegalArgumentException(val);
205     }
206    
207 jsr166 1.1 private static List<Job> filter(Pattern filter, List<Job> jobs) {
208     if (filter == null) return jobs;
209     ArrayList<Job> newJobs = new ArrayList<>();
210     for (Job job : jobs)
211     if (filter.matcher(job.name()).find())
212     newJobs.add(job);
213     return newJobs;
214     }
215    
216     private static void deoptimize(int sum) {
217     if (sum == 42)
218     System.out.println("the answer");
219     }
220    
221     private static <T> List<T> asSubList(List<T> list) {
222     return list.subList(0, list.size());
223     }
224    
225     private static <T> Iterable<T> backwards(final List<T> list) {
226     return new Iterable<T>() {
227     public Iterator<T> iterator() {
228     return new Iterator<T>() {
229     final ListIterator<T> it = list.listIterator(list.size());
230     public boolean hasNext() { return it.hasPrevious(); }
231     public T next() { return it.previous(); }
232     public void remove() { it.remove(); }};}};
233     }
234    
235     // Checks for correctness *and* prevents loop optimizations
236     class Check {
237     private int sum;
238     public void sum(int sum) {
239     if (this.sum == 0)
240     this.sum = sum;
241     if (this.sum != sum)
242     throw new AssertionError("Sum mismatch");
243     }
244     }
245     volatile Check check = new Check();
246    
247     public static void main(String[] args) throws Throwable {
248 jsr166 1.5 new RemoveMicroBenchmark(args).run();
249 jsr166 1.1 }
250    
251 jsr166 1.5 void run() throws Throwable {
252 jsr166 1.1 // System.out.printf(
253     // "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
254     // iterations, size, warmupSeconds, filter);
255    
256     final ArrayList<Integer> al = new ArrayList<Integer>(size);
257    
258     // Populate collections with random data
259     final ThreadLocalRandom rnd = ThreadLocalRandom.current();
260     for (int i = 0; i < size; i++)
261     al.add(rnd.nextInt(size));
262    
263     ArrayList<Job> jobs = new ArrayList<>();
264    
265     List.<Collection<Integer>>of(
266     new ArrayList<>(),
267     new LinkedList<>(),
268     new Vector<>(),
269     new ArrayDeque<>(),
270 jsr166 1.2 new PriorityQueue<>(),
271 jsr166 1.1 new ArrayBlockingQueue<>(al.size()),
272     new ConcurrentLinkedQueue<>(),
273     new ConcurrentLinkedDeque<>(),
274     new LinkedBlockingQueue<>(),
275     new LinkedBlockingDeque<>(),
276 jsr166 1.2 new LinkedTransferQueue<>(),
277     new PriorityBlockingQueue<>())
278 jsr166 1.1 .stream().forEach(
279     x -> {
280     String klazz = x.getClass().getSimpleName();
281     jobs.addAll(collectionJobs(klazz, () -> x, al));
282     if (x instanceof Deque) {
283     Deque<Integer> deque = (Deque<Integer>) x;
284     jobs.addAll(dequeJobs(klazz, () -> deque, al));
285     }
286 jsr166 1.3 if (x instanceof BlockingQueue) {
287     BlockingQueue<Integer> q = (BlockingQueue<Integer>) x;
288     jobs.addAll(blockingQueueJobs(klazz, () -> q, al));
289     }
290 jsr166 1.7 if (x instanceof BlockingDeque) {
291     BlockingDeque<Integer> q = (BlockingDeque<Integer>) x;
292     jobs.addAll(blockingDequeJobs(klazz, () -> q, al));
293     }
294 jsr166 1.1 if (x instanceof List) {
295     List<Integer> list = (List<Integer>) x;
296     jobs.addAll(
297     collectionJobs(
298     klazz + " subList",
299     () -> list.subList(0, x.size()),
300     al));
301     }
302     });
303    
304 jsr166 1.5 if (reverse) Collections.reverse(jobs);
305     if (shuffle) Collections.shuffle(jobs);
306    
307 jsr166 1.1 time(filter(filter, jobs));
308     }
309    
310     Collection<Integer> universeRecorder(int[] sum) {
311     return new ArrayList<>() {
312     public boolean contains(Object x) {
313     sum[0] += (Integer) x;
314     return true;
315     }};
316     }
317    
318     Collection<Integer> emptyRecorder(int[] sum) {
319     return new ArrayList<>() {
320     public boolean contains(Object x) {
321     sum[0] += (Integer) x;
322     return false;
323     }};
324     }
325    
326     List<Job> collectionJobs(
327     String description,
328     Supplier<Collection<Integer>> supplier,
329     ArrayList<Integer> al) {
330     return List.of(
331     new Job(description + " .removeIf") {
332     public void work() throws Throwable {
333     Collection<Integer> x = supplier.get();
334     int[] sum = new int[1];
335     for (int i = 0; i < iterations; i++) {
336     sum[0] = 0;
337     x.addAll(al);
338     x.removeIf(n -> { sum[0] += n; return true; });
339     check.sum(sum[0]);}}},
340     new Job(description + " .removeAll") {
341     public void work() throws Throwable {
342     Collection<Integer> x = supplier.get();
343     int[] sum = new int[1];
344     Collection<Integer> universe = universeRecorder(sum);
345     for (int i = 0; i < iterations; i++) {
346     sum[0] = 0;
347     x.addAll(al);
348     x.removeAll(universe);
349     check.sum(sum[0]);}}},
350     new Job(description + " .retainAll") {
351     public void work() throws Throwable {
352     Collection<Integer> x = supplier.get();
353     int[] sum = new int[1];
354     Collection<Integer> empty = emptyRecorder(sum);
355     for (int i = 0; i < iterations; i++) {
356     sum[0] = 0;
357     x.addAll(al);
358     x.retainAll(empty);
359     check.sum(sum[0]);}}},
360     new Job(description + " Iterator.remove") {
361     public void work() throws Throwable {
362     Collection<Integer> x = supplier.get();
363     int[] sum = new int[1];
364     for (int i = 0; i < iterations; i++) {
365     sum[0] = 0;
366     x.addAll(al);
367     Iterator<Integer> it = x.iterator();
368     while (it.hasNext()) {
369     sum[0] += it.next();
370     it.remove();
371     }
372     check.sum(sum[0]);}}},
373     new Job(description + " clear") {
374     public void work() throws Throwable {
375     Collection<Integer> x = supplier.get();
376     int[] sum = new int[1];
377     for (int i = 0; i < iterations; i++) {
378     sum[0] = 0;
379     x.addAll(al);
380     x.forEach(e -> sum[0] += e);
381     x.clear();
382     check.sum(sum[0]);}}});
383     }
384    
385     List<Job> dequeJobs(
386     String description,
387     Supplier<Deque<Integer>> supplier,
388     ArrayList<Integer> al) {
389     return List.of(
390     new Job(description + " descendingIterator().remove") {
391     public void work() throws Throwable {
392     Deque<Integer> x = supplier.get();
393     int[] sum = new int[1];
394     for (int i = 0; i < iterations; i++) {
395     sum[0] = 0;
396     x.addAll(al);
397     Iterator<Integer> it = x.descendingIterator();
398     while (it.hasNext()) {
399     sum[0] += it.next();
400     it.remove();
401     }
402 jsr166 1.6 check.sum(sum[0]);}}},
403     new Job(description + " pollFirst()") {
404     public void work() throws Throwable {
405     Deque<Integer> x = supplier.get();
406     int[] sum = new int[1];
407     for (int i = 0; i < iterations; i++) {
408     sum[0] = 0;
409     x.addAll(al);
410     for (Integer e; (e = x.pollFirst()) != null; )
411     sum[0] += e;
412     check.sum(sum[0]);}}},
413     new Job(description + " pollLast()") {
414     public void work() throws Throwable {
415     Deque<Integer> x = supplier.get();
416     int[] sum = new int[1];
417     for (int i = 0; i < iterations; i++) {
418     sum[0] = 0;
419     x.addAll(al);
420     for (Integer e; (e = x.pollLast()) != null; )
421     sum[0] += e;
422 jsr166 1.1 check.sum(sum[0]);}}});
423     }
424 jsr166 1.3
425     List<Job> blockingQueueJobs(
426     String description,
427     Supplier<BlockingQueue<Integer>> supplier,
428     ArrayList<Integer> al) {
429     return List.of(
430     new Job(description + " drainTo(sink)") {
431     public void work() throws Throwable {
432     BlockingQueue<Integer> x = supplier.get();
433     ArrayList<Integer> sink = new ArrayList<>();
434     int[] sum = new int[1];
435     for (int i = 0; i < iterations; i++) {
436     sum[0] = 0;
437     sink.clear();
438     x.addAll(al);
439     x.drainTo(sink);
440     sink.forEach(e -> sum[0] += e);
441     check.sum(sum[0]);}}},
442     new Job(description + " drainTo(sink, n)") {
443     public void work() throws Throwable {
444     BlockingQueue<Integer> x = supplier.get();
445     ArrayList<Integer> sink = new ArrayList<>();
446     int[] sum = new int[1];
447     for (int i = 0; i < iterations; i++) {
448     sum[0] = 0;
449     sink.clear();
450     x.addAll(al);
451     x.drainTo(sink, al.size());
452     sink.forEach(e -> sum[0] += e);
453     check.sum(sum[0]);}}});
454     }
455 jsr166 1.7
456     List<Job> blockingDequeJobs(
457     String description,
458     Supplier<BlockingDeque<Integer>> supplier,
459     ArrayList<Integer> al) {
460     return List.of(
461     new Job(description + " timed pollFirst()") {
462     public void work() throws Throwable {
463     BlockingDeque<Integer> x = supplier.get();
464     int[] sum = new int[1];
465     for (int i = 0; i < iterations; i++) {
466     sum[0] = 0;
467     x.addAll(al);
468     for (Integer e; (e = x.pollFirst(0L, TimeUnit.DAYS)) != null; )
469     sum[0] += e;
470     check.sum(sum[0]);}}},
471     new Job(description + " timed pollLast()") {
472     public void work() throws Throwable {
473     BlockingDeque<Integer> x = supplier.get();
474     int[] sum = new int[1];
475     for (int i = 0; i < iterations; i++) {
476     sum[0] = 0;
477     x.addAll(al);
478     for (Integer e; (e = x.pollLast(0L, TimeUnit.DAYS)) != null; )
479     sum[0] += e;
480     check.sum(sum[0]);}}});
481     }
482 jsr166 1.1 }