ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/jtreg/util/ArrayList/IteratorMicroBenchmark.java
Revision: 1.7
Committed: Thu Oct 27 03:05:39 2016 UTC (7 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.6: +3 -0 lines
Log Message:
shuffle ArrayDeque to ensure wrapping

File Contents

# Content
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 IteratorMicroBenchmark 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.Enumeration;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.ListIterator;
37 import java.util.Map;
38 import java.util.Vector;
39 import java.util.concurrent.ConcurrentSkipListMap;
40 import java.util.concurrent.CountDownLatch;
41 import java.util.concurrent.ThreadLocalRandom;
42 import java.util.concurrent.TimeUnit;
43 import java.util.regex.Pattern;
44
45 /**
46 * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
47 *
48 * To run this in micro-benchmark mode, simply run as a normal java program.
49 * Be patient; this runs for an hour!
50 * For faster runs, restrict execution using command line args.
51 *
52 * @author Martin Buchholz
53 */
54 public class IteratorMicroBenchmark {
55 abstract static class Job {
56 private final String name;
57 public Job(String name) { this.name = name; }
58 public String name() { return name; }
59 public abstract void work() throws Throwable;
60 }
61
62 static double warmupSeconds = 10;
63
64 // --------------- GC finalization infrastructure ---------------
65
66 /** No guarantees, but effective in practice. */
67 static void forceFullGc() {
68 CountDownLatch finalizeDone = new CountDownLatch(1);
69 WeakReference<?> ref = new WeakReference<Object>(new Object() {
70 protected void finalize() { finalizeDone.countDown(); }});
71 try {
72 for (int i = 0; i < 10; i++) {
73 System.gc();
74 if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
75 System.runFinalization(); // try to pick up stragglers
76 return;
77 }
78 }
79 } catch (InterruptedException unexpected) {
80 throw new AssertionError("unexpected InterruptedException");
81 }
82 throw new AssertionError("failed to do a \"full\" gc");
83 }
84
85 /**
86 * Runs each job for long enough that all the runtime compilers
87 * have had plenty of time to warm up, i.e. get around to
88 * compiling everything worth compiling.
89 * Returns array of average times per job per run.
90 */
91 private static long[] time0(Job ... jobs) throws Throwable {
92 final long warmupNanos = (long) (warmupSeconds * 1000L * 1000L * 1000L);
93 long[] nanoss = new long[jobs.length];
94 for (int i = 0; i < jobs.length; i++) {
95 if (warmupNanos > 0) forceFullGc();
96 long t0 = System.nanoTime();
97 long t;
98 int j = 0;
99 do { jobs[i].work(); j++; }
100 while ((t = System.nanoTime() - t0) < warmupNanos);
101 nanoss[i] = t/j;
102 }
103 return nanoss;
104 }
105
106 private static void time(Job ... jobs) throws Throwable {
107 if (warmupSeconds > 0) time0(jobs); // Warm up run
108 long[] nanoss = time0(jobs); // Real timing run
109 long[] milliss = new long[jobs.length];
110 double[] ratios = new double[jobs.length];
111
112 final String nameHeader = "Method";
113 final String millisHeader = "Millis";
114 final String ratioHeader = "Ratio";
115
116 int nameWidth = nameHeader.length();
117 int millisWidth = millisHeader.length();
118 int ratioWidth = ratioHeader.length();
119
120 for (int i = 0; i < jobs.length; i++) {
121 nameWidth = Math.max(nameWidth, jobs[i].name().length());
122
123 milliss[i] = nanoss[i]/(1000L * 1000L);
124 millisWidth = Math.max(millisWidth,
125 String.format("%d", milliss[i]).length());
126
127 ratios[i] = (double) nanoss[i] / (double) nanoss[0];
128 ratioWidth = Math.max(ratioWidth,
129 String.format("%.3f", ratios[i]).length());
130 }
131
132 String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
133 nameWidth, millisWidth, ratioWidth);
134 String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
135 nameWidth, millisWidth, ratioWidth);
136 System.out.printf(headerFormat, "Method", "Millis", "Ratio");
137
138 // Print out absolute and relative times, calibrated against first job
139 for (int i = 0; i < jobs.length; i++)
140 System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]);
141 }
142
143 private static String keywordValue(String[] args, String keyword) {
144 for (String arg : args)
145 if (arg.startsWith(keyword))
146 return arg.substring(keyword.length() + 1);
147 return null;
148 }
149
150 private static int intArg(String[] args, String keyword, int defaultValue) {
151 String val = keywordValue(args, keyword);
152 return (val == null) ? defaultValue : Integer.parseInt(val);
153 }
154
155 private static double doubleArg(String[] args, String keyword, double defaultValue) {
156 String val = keywordValue(args, keyword);
157 return (val == null) ? defaultValue : Double.parseDouble(val);
158 }
159
160 private static Pattern patternArg(String[] args, String keyword) {
161 String val = keywordValue(args, keyword);
162 return (val == null) ? null : Pattern.compile(val);
163 }
164
165 private static Job[] filter(Pattern filter, Job[] jobs) {
166 if (filter == null) return jobs;
167 Job[] newJobs = new Job[jobs.length];
168 int n = 0;
169 for (Job job : jobs)
170 if (filter.matcher(job.name()).find())
171 newJobs[n++] = job;
172 // Arrays.copyOf not available in JDK 5
173 Job[] ret = new Job[n];
174 System.arraycopy(newJobs, 0, ret, 0, n);
175 return ret;
176 }
177
178 private static void deoptimize(int sum) {
179 if (sum == 42)
180 System.out.println("the answer");
181 }
182
183 private static <T> List<T> asSubList(List<T> list) {
184 return list.subList(0, list.size());
185 }
186
187 private static <T> Iterable<T> backwards(final List<T> list) {
188 return new Iterable<T>() {
189 public Iterator<T> iterator() {
190 return new Iterator<T>() {
191 final ListIterator<T> it = list.listIterator(list.size());
192 public boolean hasNext() { return it.hasPrevious(); }
193 public T next() { return it.previous(); }
194 public void remove() { it.remove(); }};}};
195 }
196
197 public static void main(String[] args) throws Throwable {
198 final int iterations = intArg(args, "iterations", 100_000);
199 final int size = intArg(args, "size", 1000);
200 warmupSeconds = doubleArg(args, "warmup", 10);
201 final Pattern filter = patternArg(args, "filter");
202 // System.out.printf(
203 // "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
204 // iterations, size, warmupSeconds, filter);
205
206 final ConcurrentSkipListMap<Integer,Integer> m
207 = new ConcurrentSkipListMap<Integer,Integer>();
208 final ArrayList<Integer> al = new ArrayList<Integer>(size);
209
210 // Populate collections with random data
211 final ThreadLocalRandom rnd = ThreadLocalRandom.current();
212 for (int i = 0; i < size; i++) {
213 m.put(rnd.nextInt(size), rnd.nextInt(size));
214 al.add(rnd.nextInt(size));
215 }
216 final Vector<Integer> v = new Vector<Integer>(al);
217 final ArrayDeque<Integer> ad = new ArrayDeque<Integer>(al);
218 // shuffle ArrayDeque elements so they wrap
219 for (int i = 0, n = rnd.nextInt(size); i < n; i++)
220 ad.addLast(ad.removeFirst());
221
222 // Also test "short" collections
223 final int shortSize = 5;
224 final Vector<Integer> sv = new Vector<Integer>(v.subList(0, shortSize));
225 final ArrayList<Integer> sal = new ArrayList<Integer>(sv);
226
227 // Checks for correctness *and* prevents loop optimizations
228 class Check {
229 private int sum;
230 public void sum(int sum) {
231 if (this.sum == 0)
232 this.sum = sum;
233 if (this.sum != sum)
234 throw new AssertionError("Sum mismatch");
235 }
236 }
237 final Check check = new Check();
238 final Check shortCheck = new Check();
239
240 Job[] jobs = {
241 // new Job("Vector iterate desugared") {
242 // public void work() throws Throwable {
243 // for (int i = 0; i < iterations; i++) {
244 // int sum = 0;
245 // for (Iterator<Integer> it = v.iterator(); it.hasNext();)
246 // sum += it.next();
247 // check.sum(sum);}}},
248 new Job("array loop") {
249 public void work() throws Throwable {
250 Integer[] a = al.toArray(new Integer[0]);
251 for (int i = 0; i < iterations; i++) {
252 int sum = 0;
253 int size = a.length;
254 for (int j = 0; j < size; ++j)
255 sum += a[j];
256 check.sum(sum);}}},
257 new Job("descending array loop") {
258 public void work() throws Throwable {
259 Integer[] a = al.toArray(new Integer[0]);
260 for (int i = 0; i < iterations; i++) {
261 int sum = 0;
262 int size = a.length;
263 for (int j = size - 1; j >= 0; j--)
264 sum += a[j];
265 check.sum(sum);}}},
266 new Job("Vector get loop") {
267 public void work() throws Throwable {
268 for (int i = 0; i < iterations; i++) {
269 int sum = 0;
270 int size = v.size();
271 for (int j = 0; j < size; ++j)
272 sum += v.get(j);
273 check.sum(sum);}}},
274 new Job("Vector iterate for loop") {
275 public void work() throws Throwable {
276 for (int i = 0; i < iterations; i++) {
277 int sum = 0;
278 for (Integer n : v)
279 sum += n;
280 check.sum(sum);}}},
281 new Job("Vector descending listIterator loop") {
282 public void work() throws Throwable {
283 for (int i = 0; i < iterations; i++) {
284 int sum = 0;
285 ListIterator<Integer> it = v.listIterator(al.size());
286 while (it.hasPrevious())
287 sum += it.previous();
288 check.sum(sum);}}},
289 new Job("Vector Enumeration loop") {
290 public void work() throws Throwable {
291 for (int i = 0; i < iterations; i++) {
292 int sum = 0;
293 Enumeration<Integer> it = v.elements();
294 while (it.hasMoreElements())
295 sum += it.nextElement();
296 check.sum(sum);}}},
297 new Job("Vector subList iterate for loop") {
298 public void work() throws Throwable {
299 for (int i = 0; i < iterations; i++) {
300 int sum = 0;
301 for (Integer n : asSubList(v))
302 sum += n;
303 check.sum(sum);}}},
304 new Job("Vector subList subList subList iterate for loop") {
305 public void work() throws Throwable {
306 for (int i = 0; i < iterations; i++) {
307 int sum = 0;
308 for (Integer n : asSubList(asSubList(asSubList(v))))
309 sum += n;
310 check.sum(sum);}}},
311 new Job("Vector backwards wrapper ListIterator for loop") {
312 public void work() throws Throwable {
313 for (int i = 0; i < iterations; i++) {
314 int sum = 0;
315 for (Integer n : backwards(v))
316 sum += n;
317 check.sum(sum);}}},
318 new Job("Vector backwards wrapper subList ListIterator for loop") {
319 public void work() throws Throwable {
320 for (int i = 0; i < iterations; i++) {
321 int sum = 0;
322 for (Integer n : backwards(asSubList(v)))
323 sum += n;
324 check.sum(sum);}}},
325 // new Job("Vector iterate for loop invokeinterface") {
326 // public void work() throws Throwable {
327 // final List<Integer> l = v;
328 // for (int i = 0; i < iterations; i++) {
329 // int sum = 0;
330 // for (Integer n : l)
331 // sum += n;
332 // check.sum(sum);}}},
333 // new Job("Vector subList iterate for loop invokeinterface") {
334 // public void work() throws Throwable {
335 // final List<Integer> l = v;
336 // for (int i = 0; i < iterations; i++) {
337 // int sum = 0;
338 // for (Integer n : asSubList(l))
339 // sum += n;
340 // check.sum(sum);}}},
341 new Job("Short Vector get loop") {
342 public void work() throws Throwable {
343 for (int i = 0; i < (iterations * size / shortSize); i++) {
344 int sum = 0;
345 int size = sv.size();
346 for (int j = 0; j < size; ++j)
347 sum += sv.get(j);
348 shortCheck.sum(sum);}}},
349 new Job("Short Vector iterate for loop") {
350 public void work() throws Throwable {
351 for (int i = 0; i < (iterations * size / shortSize); i++) {
352 int sum = 0;
353 for (Integer n : sv)
354 sum += n;
355 shortCheck.sum(sum);}}},
356 new Job("Short Vector sublist iterate for loop") {
357 public void work() throws Throwable {
358 for (int i = 0; i < (iterations * size / shortSize); i++) {
359 int sum = 0;
360 for (Integer n : asSubList(sv))
361 sum += n;
362 shortCheck.sum(sum);}}},
363 new Job("ArrayList get loop") {
364 public void work() throws Throwable {
365 for (int i = 0; i < iterations; i++) {
366 int sum = 0;
367 int size = al.size();
368 for (int j = 0; j < size; ++j)
369 sum += al.get(j);
370 check.sum(sum);}}},
371 new Job("ArrayList iterate for loop") {
372 public void work() throws Throwable {
373 for (int i = 0; i < iterations; i++) {
374 int sum = 0;
375 for (Integer n : al)
376 sum += n;
377 check.sum(sum);}}},
378 new Job("ArrayDeque iterate for loop") {
379 public void work() throws Throwable {
380 for (int i = 0; i < iterations; i++) {
381 int sum = 0;
382 for (Integer n : ad)
383 sum += n;
384 check.sum(sum);}}},
385 new Job("ArrayList descending listIterator loop") {
386 public void work() throws Throwable {
387 for (int i = 0; i < iterations; i++) {
388 int sum = 0;
389 ListIterator<Integer> it = al.listIterator(al.size());
390 while (it.hasPrevious())
391 sum += it.previous();
392 check.sum(sum);}}},
393 new Job("ArrayList listIterator loop") {
394 public void work() throws Throwable {
395 for (int i = 0; i < iterations; i++) {
396 int sum = 0;
397 ListIterator<Integer> it = al.listIterator();
398 while (it.hasNext())
399 sum += it.next();
400 check.sum(sum);}}},
401 new Job("ArrayDeque descending iterator loop") {
402 public void work() throws Throwable {
403 for (int i = 0; i < iterations; i++) {
404 int sum = 0;
405 Iterator<Integer> it = ad.descendingIterator();
406 while (it.hasNext())
407 sum += it.next();
408 check.sum(sum);}}},
409 new Job("ArrayList.forEach") {
410 public void work() throws Throwable {
411 int[] sum = new int[1];
412 for (int i = 0; i < iterations; i++) {
413 sum[0] = 0;
414 al.forEach(n -> sum[0] += n);
415 check.sum(sum[0]);}}},
416 new Job("ArrayDeque.forEach") {
417 public void work() throws Throwable {
418 int[] sum = new int[1];
419 for (int i = 0; i < iterations; i++) {
420 sum[0] = 0;
421 ad.forEach(n -> sum[0] += n);
422 check.sum(sum[0]);}}},
423 new Job("Vector.forEach") {
424 public void work() throws Throwable {
425 int[] sum = new int[1];
426 for (int i = 0; i < iterations; i++) {
427 sum[0] = 0;
428 v.forEach(n -> sum[0] += n);
429 check.sum(sum[0]);}}},
430 new Job("ArrayList.iterator().forEachRemaining()") {
431 public void work() throws Throwable {
432 int[] sum = new int[1];
433 for (int i = 0; i < iterations; i++) {
434 sum[0] = 0;
435 al.iterator().forEachRemaining(n -> sum[0] += n);
436 check.sum(sum[0]);}}},
437 new Job("ArrayDeque.descendingIterator().forEachRemaining()") {
438 public void work() throws Throwable {
439 int[] sum = new int[1];
440 for (int i = 0; i < iterations; i++) {
441 sum[0] = 0;
442 ad.descendingIterator().forEachRemaining(n -> sum[0] += n);
443 check.sum(sum[0]);}}},
444 new Job("ArrayDeque.iterator().forEachRemaining()") {
445 public void work() throws Throwable {
446 int[] sum = new int[1];
447 for (int i = 0; i < iterations; i++) {
448 sum[0] = 0;
449 ad.iterator().forEachRemaining(n -> sum[0] += n);
450 check.sum(sum[0]);}}},
451 new Job("Vector.iterator().forEachRemaining()") {
452 public void work() throws Throwable {
453 int[] sum = new int[1];
454 for (int i = 0; i < iterations; i++) {
455 sum[0] = 0;
456 v.iterator().forEachRemaining(n -> sum[0] += n);
457 check.sum(sum[0]);}}},
458 new Job("ArrayList.spliterator().forEachRemaining()") {
459 public void work() throws Throwable {
460 int[] sum = new int[1];
461 for (int i = 0; i < iterations; i++) {
462 sum[0] = 0;
463 al.spliterator().forEachRemaining(n -> sum[0] += n);
464 check.sum(sum[0]);}}},
465 new Job("ArrayDeque.spliterator().forEachRemaining()") {
466 public void work() throws Throwable {
467 int[] sum = new int[1];
468 for (int i = 0; i < iterations; i++) {
469 sum[0] = 0;
470 ad.spliterator().forEachRemaining(n -> sum[0] += n);
471 check.sum(sum[0]);}}},
472 new Job("Vector.spliterator().forEachRemaining()") {
473 public void work() throws Throwable {
474 int[] sum = new int[1];
475 for (int i = 0; i < iterations; i++) {
476 sum[0] = 0;
477 v.spliterator().forEachRemaining(n -> sum[0] += n);
478 check.sum(sum[0]);}}},
479 new Job("ArrayList subList get loop") {
480 public void work() throws Throwable {
481 List<Integer> sl = asSubList(al);
482 for (int i = 0; i < iterations; i++) {
483 int sum = 0;
484 int size = sl.size();
485 for (int j = 0; j < size; ++j)
486 sum += sl.get(j);
487 check.sum(sum);}}},
488 new Job("ArrayList subList iterate for loop") {
489 public void work() throws Throwable {
490 for (int i = 0; i < iterations; i++) {
491 int sum = 0;
492 for (Integer n : asSubList(al))
493 sum += n;
494 check.sum(sum);}}},
495 new Job("ArrayList subList subList subList iterate for loop") {
496 public void work() throws Throwable {
497 for (int i = 0; i < iterations; i++) {
498 int sum = 0;
499 for (Integer n : asSubList(asSubList(asSubList(al))))
500 sum += n;
501 check.sum(sum);}}},
502 new Job("ArrayList backwards wrapper ListIterator for loop") {
503 public void work() throws Throwable {
504 for (int i = 0; i < iterations; i++) {
505 int sum = 0;
506 for (Integer n : backwards(al))
507 sum += n;
508 check.sum(sum);}}},
509 new Job("ArrayList backwards wrapper subList ListIterator for loop") {
510 public void work() throws Throwable {
511 for (int i = 0; i < iterations; i++) {
512 int sum = 0;
513 for (Integer n : backwards(asSubList(al)))
514 sum += n;
515 check.sum(sum);}}},
516 // new Job("ArrayList iterate desugared") {
517 // public void work() throws Throwable {
518 // for (int i = 0; i < iterations; i++) {
519 // int sum = 0;
520 // for (Iterator<Integer> it = al.iterator(); it.hasNext();)
521 // sum += it.next();
522 // check.sum(sum);}}},
523 new Job("Short ArrayList get loop") {
524 public void work() throws Throwable {
525 for (int i = 0; i < (iterations * size / shortSize); i++) {
526 int sum = 0;
527 int size = sal.size();
528 for (int j = 0; j < size; ++j)
529 sum += sal.get(j);
530 shortCheck.sum(sum);}}},
531 new Job("Short ArrayList iterate for loop") {
532 public void work() throws Throwable {
533 for (int i = 0; i < (iterations * size / shortSize); i++) {
534 int sum = 0;
535 for (Integer n : sal)
536 sum += n;
537 shortCheck.sum(sum);}}},
538 new Job("Short ArrayList sublist iterate for loop") {
539 public void work() throws Throwable {
540 for (int i = 0; i < (iterations * size / shortSize); i++) {
541 int sum = 0;
542 for (Integer n : asSubList(sal))
543 sum += n;
544 shortCheck.sum(sum);}}},
545 new Job("Vector ArrayList alternating iteration") {
546 public void work() throws Throwable {
547 for (int i = 0; i < iterations; i++) {
548 int sum = 0;
549 Iterator<Integer> it1 = v.iterator();
550 Iterator<Integer> it2 = al.iterator();
551 while (it1.hasNext())
552 sum += it1.next() + it2.next();
553 check.sum(sum/2);}}},
554 new Job("Vector ArrayList alternating invokeVirtual iteration") {
555 public void work() throws Throwable {
556 for (int i = 0; i < iterations; i++) {
557 int sum = 0;
558 List<Iterator<Integer>> its
559 = new ArrayList<Iterator<Integer>>(2);
560 its.add(v.iterator());
561 its.add(al.iterator());
562 for (int k = 0; its.get(k).hasNext(); k = (k == 0) ? 1 : 0)
563 sum += its.get(k).next();
564 check.sum(sum/2);}}},
565 new Job("ConcurrentSkipListMap entrySet iterate") {
566 public void work() throws Throwable {
567 for (int i = 0; i < iterations; i++) {
568 int sum = 0;
569 for (Map.Entry<Integer,Integer> e : m.entrySet())
570 sum += e.getKey();
571 deoptimize(sum);}}}
572 };
573
574 time(filter(filter, jobs));
575 }
576 }