ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/jtreg/util/Collection/RemoveMicroBenchmark.java
Revision: 1.19
Committed: Sun Jan 7 20:19:00 2018 UTC (6 years, 5 months ago) by jsr166
Branch: MAIN
Changes since 1.18: +1 -2 lines
Log Message:
simplify c.stream().forEach to c.forEach

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.ArrayList;
33     import java.util.Collection;
34 jsr166 1.5 import java.util.Collections;
35 jsr166 1.1 import java.util.Deque;
36     import java.util.Iterator;
37     import java.util.LinkedList;
38     import java.util.List;
39     import java.util.ListIterator;
40 jsr166 1.2 import java.util.PriorityQueue;
41 jsr166 1.8 import java.util.Queue;
42 jsr166 1.1 import java.util.Vector;
43     import java.util.concurrent.ArrayBlockingQueue;
44 jsr166 1.7 import java.util.concurrent.BlockingDeque;
45 jsr166 1.3 import java.util.concurrent.BlockingQueue;
46 jsr166 1.1 import java.util.concurrent.ConcurrentLinkedDeque;
47     import java.util.concurrent.ConcurrentLinkedQueue;
48 jsr166 1.2 import java.util.concurrent.CountDownLatch;
49 jsr166 1.1 import java.util.concurrent.LinkedBlockingDeque;
50     import java.util.concurrent.LinkedBlockingQueue;
51     import java.util.concurrent.LinkedTransferQueue;
52 jsr166 1.2 import java.util.concurrent.PriorityBlockingQueue;
53 jsr166 1.1 import java.util.concurrent.ThreadLocalRandom;
54     import java.util.concurrent.TimeUnit;
55     import java.util.regex.Pattern;
56     import java.util.function.Supplier;
57    
58     /**
59     * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
60     *
61     * To run this in micro-benchmark mode, simply run as a normal java program.
62     * Be patient; this program runs for a very long time.
63     * For faster runs, restrict execution using command line args.
64     *
65     * @author Martin Buchholz
66     */
67     public class RemoveMicroBenchmark {
68     abstract static class Job {
69     private final String name;
70     public Job(String name) { this.name = name; }
71     public String name() { return name; }
72     public abstract void work() throws Throwable;
73     }
74    
75 jsr166 1.5 final int iterations;
76     final int size; // number of elements in collections
77     final double warmupSeconds;
78     final long warmupNanos;
79     final Pattern filter; // select subset of Jobs to run
80     final boolean reverse; // reverse order of Jobs
81     final boolean shuffle; // randomize order of Jobs
82    
83     RemoveMicroBenchmark(String[] args) {
84     iterations = intArg(args, "iterations", 10_000);
85     size = intArg(args, "size", 1000);
86     warmupSeconds = doubleArg(args, "warmup", 7.0);
87     filter = patternArg(args, "filter");
88     reverse = booleanArg(args, "reverse");
89     shuffle = booleanArg(args, "shuffle");
90    
91     warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
92     }
93 jsr166 1.1
94     // --------------- GC finalization infrastructure ---------------
95    
96     /** No guarantees, but effective in practice. */
97     static void forceFullGc() {
98     CountDownLatch finalizeDone = new CountDownLatch(1);
99     WeakReference<?> ref = new WeakReference<Object>(new Object() {
100     protected void finalize() { finalizeDone.countDown(); }});
101     try {
102     for (int i = 0; i < 10; i++) {
103     System.gc();
104     if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
105     System.runFinalization(); // try to pick up stragglers
106     return;
107     }
108     }
109     } catch (InterruptedException unexpected) {
110     throw new AssertionError("unexpected InterruptedException");
111     }
112     throw new AssertionError("failed to do a \"full\" gc");
113     }
114    
115     /**
116     * Runs each job for long enough that all the runtime compilers
117     * have had plenty of time to warm up, i.e. get around to
118     * compiling everything worth compiling.
119     * Returns array of average times per job per run.
120     */
121     long[] time0(List<Job> jobs) throws Throwable {
122     final int size = jobs.size();
123     long[] nanoss = new long[size];
124     for (int i = 0; i < size; i++) {
125     if (warmupNanos > 0) forceFullGc();
126 jsr166 1.4 Job job = jobs.get(i);
127     long totalTime;
128     int runs = 0;
129     long startTime = System.nanoTime();
130     do { job.work(); runs++; }
131     while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
132     nanoss[i] = totalTime/runs;
133 jsr166 1.1 }
134     return nanoss;
135     }
136    
137     void time(List<Job> jobs) throws Throwable {
138 jsr166 1.4 if (warmupNanos > 0) time0(jobs); // Warm up run
139 jsr166 1.1 final int size = jobs.size();
140     final long[] nanoss = time0(jobs); // Real timing run
141     final long[] milliss = new long[size];
142     final double[] ratios = new double[size];
143    
144     final String nameHeader = "Method";
145     final String millisHeader = "Millis";
146     final String ratioHeader = "Ratio";
147    
148     int nameWidth = nameHeader.length();
149     int millisWidth = millisHeader.length();
150     int ratioWidth = ratioHeader.length();
151    
152     for (int i = 0; i < size; i++) {
153     nameWidth = Math.max(nameWidth, jobs.get(i).name().length());
154    
155     milliss[i] = nanoss[i]/(1000L * 1000L);
156     millisWidth = Math.max(millisWidth,
157     String.format("%d", milliss[i]).length());
158    
159     ratios[i] = (double) nanoss[i] / (double) nanoss[0];
160     ratioWidth = Math.max(ratioWidth,
161     String.format("%.3f", ratios[i]).length());
162     }
163    
164     String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
165     nameWidth, millisWidth, ratioWidth);
166     String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
167     nameWidth, millisWidth, ratioWidth);
168     System.out.printf(headerFormat, "Method", "Millis", "Ratio");
169    
170     // Print out absolute and relative times, calibrated against first job
171     for (int i = 0; i < size; i++)
172     System.out.printf(format, jobs.get(i).name(), milliss[i], ratios[i]);
173     }
174    
175     private static String keywordValue(String[] args, String keyword) {
176     for (String arg : args)
177     if (arg.startsWith(keyword))
178     return arg.substring(keyword.length() + 1);
179     return null;
180     }
181    
182     private static int intArg(String[] args, String keyword, int defaultValue) {
183     String val = keywordValue(args, keyword);
184     return (val == null) ? defaultValue : Integer.parseInt(val);
185     }
186    
187     private static double doubleArg(String[] args, String keyword, double defaultValue) {
188     String val = keywordValue(args, keyword);
189     return (val == null) ? defaultValue : Double.parseDouble(val);
190     }
191    
192     private static Pattern patternArg(String[] args, String keyword) {
193     String val = keywordValue(args, keyword);
194     return (val == null) ? null : Pattern.compile(val);
195     }
196    
197 jsr166 1.5 private static boolean booleanArg(String[] args, String keyword) {
198     String val = keywordValue(args, keyword);
199     if (val == null || val.equals("false")) return false;
200     if (val.equals("true")) return true;
201     throw new IllegalArgumentException(val);
202     }
203    
204 jsr166 1.1 private static List<Job> filter(Pattern filter, List<Job> jobs) {
205     if (filter == null) return jobs;
206     ArrayList<Job> newJobs = new ArrayList<>();
207     for (Job job : jobs)
208     if (filter.matcher(job.name()).find())
209     newJobs.add(job);
210     return newJobs;
211     }
212    
213     private static void deoptimize(int sum) {
214     if (sum == 42)
215     System.out.println("the answer");
216     }
217    
218     private static <T> List<T> asSubList(List<T> list) {
219     return list.subList(0, list.size());
220     }
221    
222     private static <T> Iterable<T> backwards(final List<T> list) {
223     return new Iterable<T>() {
224     public Iterator<T> iterator() {
225     return new Iterator<T>() {
226     final ListIterator<T> it = list.listIterator(list.size());
227     public boolean hasNext() { return it.hasPrevious(); }
228     public T next() { return it.previous(); }
229     public void remove() { it.remove(); }};}};
230     }
231    
232     // Checks for correctness *and* prevents loop optimizations
233 jsr166 1.18 static class Check {
234 jsr166 1.1 private int sum;
235     public void sum(int sum) {
236     if (this.sum == 0)
237     this.sum = sum;
238     if (this.sum != sum)
239     throw new AssertionError("Sum mismatch");
240     }
241     }
242     volatile Check check = new Check();
243    
244     public static void main(String[] args) throws Throwable {
245 jsr166 1.5 new RemoveMicroBenchmark(args).run();
246 jsr166 1.1 }
247    
248 jsr166 1.5 void run() throws Throwable {
249 jsr166 1.1 // System.out.printf(
250     // "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
251     // iterations, size, warmupSeconds, filter);
252    
253 jsr166 1.13 final ArrayList<Integer> al = new ArrayList<>(size);
254 jsr166 1.1
255     // Populate collections with random data
256     final ThreadLocalRandom rnd = ThreadLocalRandom.current();
257     for (int i = 0; i < size; i++)
258     al.add(rnd.nextInt(size));
259    
260     ArrayList<Job> jobs = new ArrayList<>();
261    
262     List.<Collection<Integer>>of(
263     new ArrayList<>(),
264     new LinkedList<>(),
265     new Vector<>(),
266     new ArrayDeque<>(),
267 jsr166 1.2 new PriorityQueue<>(),
268 jsr166 1.1 new ArrayBlockingQueue<>(al.size()),
269     new ConcurrentLinkedQueue<>(),
270     new ConcurrentLinkedDeque<>(),
271     new LinkedBlockingQueue<>(),
272     new LinkedBlockingDeque<>(),
273 jsr166 1.2 new LinkedTransferQueue<>(),
274 jsr166 1.19 new PriorityBlockingQueue<>()).forEach(
275 jsr166 1.1 x -> {
276     String klazz = x.getClass().getSimpleName();
277     jobs.addAll(collectionJobs(klazz, () -> x, al));
278 jsr166 1.8 if (x instanceof Queue) {
279     Queue<Integer> queue = (Queue<Integer>) x;
280     jobs.addAll(queueJobs(klazz, () -> queue, al));
281     }
282 jsr166 1.1 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 jsr166 1.14 new Job(description + " removeIf") {
332 jsr166 1.1 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 jsr166 1.14 new Job(description + " removeIf rnd-two-pass") {
341 jsr166 1.9 public void work() throws Throwable {
342     ThreadLocalRandom rnd = ThreadLocalRandom.current();
343     Collection<Integer> x = supplier.get();
344     int[] sum = new int[1];
345     for (int i = 0; i < iterations; i++) {
346     sum[0] = 0;
347     x.addAll(al);
348     x.removeIf(n -> {
349     boolean b = rnd.nextBoolean();
350     if (b) sum[0] += n;
351     return b; });
352     x.removeIf(n -> { sum[0] += n; return true; });
353     check.sum(sum[0]);}}},
354 jsr166 1.14 new Job(description + " removeAll") {
355 jsr166 1.1 public void work() throws Throwable {
356     Collection<Integer> x = supplier.get();
357     int[] sum = new int[1];
358     Collection<Integer> universe = universeRecorder(sum);
359     for (int i = 0; i < iterations; i++) {
360     sum[0] = 0;
361     x.addAll(al);
362     x.removeAll(universe);
363     check.sum(sum[0]);}}},
364 jsr166 1.14 new Job(description + " retainAll") {
365 jsr166 1.1 public void work() throws Throwable {
366     Collection<Integer> x = supplier.get();
367     int[] sum = new int[1];
368     Collection<Integer> empty = emptyRecorder(sum);
369     for (int i = 0; i < iterations; i++) {
370     sum[0] = 0;
371     x.addAll(al);
372     x.retainAll(empty);
373     check.sum(sum[0]);}}},
374     new Job(description + " Iterator.remove") {
375     public void work() throws Throwable {
376     Collection<Integer> x = supplier.get();
377     int[] sum = new int[1];
378     for (int i = 0; i < iterations; i++) {
379     sum[0] = 0;
380     x.addAll(al);
381     Iterator<Integer> it = x.iterator();
382     while (it.hasNext()) {
383     sum[0] += it.next();
384     it.remove();
385     }
386     check.sum(sum[0]);}}},
387 jsr166 1.10 new Job(description + " Iterator.remove-rnd-two-pass") {
388     public void work() throws Throwable {
389     ThreadLocalRandom rnd = ThreadLocalRandom.current();
390     Collection<Integer> x = supplier.get();
391     int[] sum = new int[1];
392     for (int i = 0; i < iterations; i++) {
393     sum[0] = 0;
394     x.addAll(al);
395 jsr166 1.12 for (Iterator<Integer> it = x.iterator();
396     it.hasNext(); ) {
397     Integer e = it.next();
398 jsr166 1.10 if (rnd.nextBoolean()) {
399 jsr166 1.12 sum[0] += e;
400 jsr166 1.10 it.remove();
401     }
402     }
403 jsr166 1.12 for (Iterator<Integer> it = x.iterator();
404     it.hasNext(); ) {
405 jsr166 1.10 sum[0] += it.next();
406     it.remove();
407     }
408     check.sum(sum[0]);}}},
409 jsr166 1.1 new Job(description + " clear") {
410     public void work() throws Throwable {
411     Collection<Integer> x = supplier.get();
412     int[] sum = new int[1];
413     for (int i = 0; i < iterations; i++) {
414     sum[0] = 0;
415     x.addAll(al);
416     x.forEach(e -> sum[0] += e);
417     x.clear();
418     check.sum(sum[0]);}}});
419     }
420    
421 jsr166 1.8 List<Job> queueJobs(
422     String description,
423     Supplier<Queue<Integer>> supplier,
424     ArrayList<Integer> al) {
425     return List.of(
426     new Job(description + " poll()") {
427     public void work() throws Throwable {
428     Queue<Integer> x = supplier.get();
429     int[] sum = new int[1];
430     for (int i = 0; i < iterations; i++) {
431     sum[0] = 0;
432     x.addAll(al);
433     for (Integer e; (e = x.poll()) != null; )
434     sum[0] += e;
435     check.sum(sum[0]);}}});
436     }
437    
438 jsr166 1.1 List<Job> dequeJobs(
439     String description,
440     Supplier<Deque<Integer>> supplier,
441     ArrayList<Integer> al) {
442     return List.of(
443     new Job(description + " descendingIterator().remove") {
444     public void work() throws Throwable {
445     Deque<Integer> x = supplier.get();
446     int[] sum = new int[1];
447     for (int i = 0; i < iterations; i++) {
448     sum[0] = 0;
449     x.addAll(al);
450     Iterator<Integer> it = x.descendingIterator();
451     while (it.hasNext()) {
452     sum[0] += it.next();
453     it.remove();
454     }
455 jsr166 1.6 check.sum(sum[0]);}}},
456     new Job(description + " pollFirst()") {
457     public void work() throws Throwable {
458     Deque<Integer> x = supplier.get();
459     int[] sum = new int[1];
460     for (int i = 0; i < iterations; i++) {
461     sum[0] = 0;
462     x.addAll(al);
463     for (Integer e; (e = x.pollFirst()) != null; )
464     sum[0] += e;
465     check.sum(sum[0]);}}},
466     new Job(description + " pollLast()") {
467     public void work() throws Throwable {
468     Deque<Integer> x = supplier.get();
469     int[] sum = new int[1];
470     for (int i = 0; i < iterations; i++) {
471     sum[0] = 0;
472     x.addAll(al);
473     for (Integer e; (e = x.pollLast()) != null; )
474     sum[0] += e;
475 jsr166 1.1 check.sum(sum[0]);}}});
476     }
477 jsr166 1.3
478     List<Job> blockingQueueJobs(
479     String description,
480     Supplier<BlockingQueue<Integer>> supplier,
481     ArrayList<Integer> al) {
482     return List.of(
483     new Job(description + " drainTo(sink)") {
484     public void work() throws Throwable {
485     BlockingQueue<Integer> x = supplier.get();
486     ArrayList<Integer> sink = new ArrayList<>();
487     int[] sum = new int[1];
488     for (int i = 0; i < iterations; i++) {
489     sum[0] = 0;
490     sink.clear();
491     x.addAll(al);
492     x.drainTo(sink);
493     sink.forEach(e -> sum[0] += e);
494     check.sum(sum[0]);}}},
495     new Job(description + " drainTo(sink, n)") {
496     public void work() throws Throwable {
497     BlockingQueue<Integer> x = supplier.get();
498     ArrayList<Integer> sink = new ArrayList<>();
499     int[] sum = new int[1];
500     for (int i = 0; i < iterations; i++) {
501     sum[0] = 0;
502     sink.clear();
503     x.addAll(al);
504     x.drainTo(sink, al.size());
505     sink.forEach(e -> sum[0] += e);
506     check.sum(sum[0]);}}});
507     }
508 jsr166 1.7
509     List<Job> blockingDequeJobs(
510     String description,
511     Supplier<BlockingDeque<Integer>> supplier,
512     ArrayList<Integer> al) {
513     return List.of(
514     new Job(description + " timed pollFirst()") {
515     public void work() throws Throwable {
516     BlockingDeque<Integer> x = supplier.get();
517     int[] sum = new int[1];
518     for (int i = 0; i < iterations; i++) {
519     sum[0] = 0;
520     x.addAll(al);
521     for (Integer e; (e = x.pollFirst(0L, TimeUnit.DAYS)) != null; )
522     sum[0] += e;
523     check.sum(sum[0]);}}},
524     new Job(description + " timed pollLast()") {
525     public void work() throws Throwable {
526     BlockingDeque<Integer> x = supplier.get();
527     int[] sum = new int[1];
528     for (int i = 0; i < iterations; i++) {
529     sum[0] = 0;
530     x.addAll(al);
531     for (Integer e; (e = x.pollLast(0L, TimeUnit.DAYS)) != null; )
532     sum[0] += e;
533     check.sum(sum[0]);}}});
534     }
535 jsr166 1.1 }