ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/jtreg/util/ArrayList/IteratorMicroBenchmark.java
Revision: 1.6
Committed: Tue Oct 25 15:52:07 2016 UTC (7 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.5: +3 -5 lines
Log Message:
optimize test

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
219 // Also test "short" collections
220 final int shortSize = 5;
221 final Vector<Integer> sv = new Vector<Integer>(v.subList(0, shortSize));
222 final ArrayList<Integer> sal = new ArrayList<Integer>(sv);
223
224 // Checks for correctness *and* prevents loop optimizations
225 class Check {
226 private int sum;
227 public void sum(int sum) {
228 if (this.sum == 0)
229 this.sum = sum;
230 if (this.sum != sum)
231 throw new AssertionError("Sum mismatch");
232 }
233 }
234 final Check check = new Check();
235 final Check shortCheck = new Check();
236
237 Job[] jobs = {
238 // new Job("Vector iterate desugared") {
239 // public void work() throws Throwable {
240 // for (int i = 0; i < iterations; i++) {
241 // int sum = 0;
242 // for (Iterator<Integer> it = v.iterator(); it.hasNext();)
243 // sum += it.next();
244 // check.sum(sum);}}},
245 new Job("array loop") {
246 public void work() throws Throwable {
247 Integer[] a = al.toArray(new Integer[0]);
248 for (int i = 0; i < iterations; i++) {
249 int sum = 0;
250 int size = a.length;
251 for (int j = 0; j < size; ++j)
252 sum += a[j];
253 check.sum(sum);}}},
254 new Job("descending array loop") {
255 public void work() throws Throwable {
256 Integer[] a = al.toArray(new Integer[0]);
257 for (int i = 0; i < iterations; i++) {
258 int sum = 0;
259 int size = a.length;
260 for (int j = size - 1; j >= 0; j--)
261 sum += a[j];
262 check.sum(sum);}}},
263 new Job("Vector get loop") {
264 public void work() throws Throwable {
265 for (int i = 0; i < iterations; i++) {
266 int sum = 0;
267 int size = v.size();
268 for (int j = 0; j < size; ++j)
269 sum += v.get(j);
270 check.sum(sum);}}},
271 new Job("Vector iterate for loop") {
272 public void work() throws Throwable {
273 for (int i = 0; i < iterations; i++) {
274 int sum = 0;
275 for (Integer n : v)
276 sum += n;
277 check.sum(sum);}}},
278 new Job("Vector descending listIterator loop") {
279 public void work() throws Throwable {
280 for (int i = 0; i < iterations; i++) {
281 int sum = 0;
282 ListIterator<Integer> it = v.listIterator(al.size());
283 while (it.hasPrevious())
284 sum += it.previous();
285 check.sum(sum);}}},
286 new Job("Vector Enumeration loop") {
287 public void work() throws Throwable {
288 for (int i = 0; i < iterations; i++) {
289 int sum = 0;
290 Enumeration<Integer> it = v.elements();
291 while (it.hasMoreElements())
292 sum += it.nextElement();
293 check.sum(sum);}}},
294 new Job("Vector subList iterate for loop") {
295 public void work() throws Throwable {
296 for (int i = 0; i < iterations; i++) {
297 int sum = 0;
298 for (Integer n : asSubList(v))
299 sum += n;
300 check.sum(sum);}}},
301 new Job("Vector subList subList subList iterate for loop") {
302 public void work() throws Throwable {
303 for (int i = 0; i < iterations; i++) {
304 int sum = 0;
305 for (Integer n : asSubList(asSubList(asSubList(v))))
306 sum += n;
307 check.sum(sum);}}},
308 new Job("Vector backwards wrapper ListIterator for loop") {
309 public void work() throws Throwable {
310 for (int i = 0; i < iterations; i++) {
311 int sum = 0;
312 for (Integer n : backwards(v))
313 sum += n;
314 check.sum(sum);}}},
315 new Job("Vector backwards wrapper subList ListIterator for loop") {
316 public void work() throws Throwable {
317 for (int i = 0; i < iterations; i++) {
318 int sum = 0;
319 for (Integer n : backwards(asSubList(v)))
320 sum += n;
321 check.sum(sum);}}},
322 // new Job("Vector iterate for loop invokeinterface") {
323 // public void work() throws Throwable {
324 // final List<Integer> l = v;
325 // for (int i = 0; i < iterations; i++) {
326 // int sum = 0;
327 // for (Integer n : l)
328 // sum += n;
329 // check.sum(sum);}}},
330 // new Job("Vector subList iterate for loop invokeinterface") {
331 // public void work() throws Throwable {
332 // final List<Integer> l = v;
333 // for (int i = 0; i < iterations; i++) {
334 // int sum = 0;
335 // for (Integer n : asSubList(l))
336 // sum += n;
337 // check.sum(sum);}}},
338 new Job("Short Vector get loop") {
339 public void work() throws Throwable {
340 for (int i = 0; i < (iterations * size / shortSize); i++) {
341 int sum = 0;
342 int size = sv.size();
343 for (int j = 0; j < size; ++j)
344 sum += sv.get(j);
345 shortCheck.sum(sum);}}},
346 new Job("Short Vector iterate for loop") {
347 public void work() throws Throwable {
348 for (int i = 0; i < (iterations * size / shortSize); i++) {
349 int sum = 0;
350 for (Integer n : sv)
351 sum += n;
352 shortCheck.sum(sum);}}},
353 new Job("Short Vector sublist iterate for loop") {
354 public void work() throws Throwable {
355 for (int i = 0; i < (iterations * size / shortSize); i++) {
356 int sum = 0;
357 for (Integer n : asSubList(sv))
358 sum += n;
359 shortCheck.sum(sum);}}},
360 new Job("ArrayList get loop") {
361 public void work() throws Throwable {
362 for (int i = 0; i < iterations; i++) {
363 int sum = 0;
364 int size = al.size();
365 for (int j = 0; j < size; ++j)
366 sum += al.get(j);
367 check.sum(sum);}}},
368 new Job("ArrayList iterate for loop") {
369 public void work() throws Throwable {
370 for (int i = 0; i < iterations; i++) {
371 int sum = 0;
372 for (Integer n : al)
373 sum += n;
374 check.sum(sum);}}},
375 new Job("ArrayDeque iterate for loop") {
376 public void work() throws Throwable {
377 for (int i = 0; i < iterations; i++) {
378 int sum = 0;
379 for (Integer n : ad)
380 sum += n;
381 check.sum(sum);}}},
382 new Job("ArrayList descending listIterator loop") {
383 public void work() throws Throwable {
384 for (int i = 0; i < iterations; i++) {
385 int sum = 0;
386 ListIterator<Integer> it = al.listIterator(al.size());
387 while (it.hasPrevious())
388 sum += it.previous();
389 check.sum(sum);}}},
390 new Job("ArrayList listIterator loop") {
391 public void work() throws Throwable {
392 for (int i = 0; i < iterations; i++) {
393 int sum = 0;
394 ListIterator<Integer> it = al.listIterator();
395 while (it.hasNext())
396 sum += it.next();
397 check.sum(sum);}}},
398 new Job("ArrayDeque descending iterator loop") {
399 public void work() throws Throwable {
400 for (int i = 0; i < iterations; i++) {
401 int sum = 0;
402 Iterator<Integer> it = ad.descendingIterator();
403 while (it.hasNext())
404 sum += it.next();
405 check.sum(sum);}}},
406 new Job("ArrayList.forEach") {
407 public void work() throws Throwable {
408 int[] sum = new int[1];
409 for (int i = 0; i < iterations; i++) {
410 sum[0] = 0;
411 al.forEach(n -> sum[0] += n);
412 check.sum(sum[0]);}}},
413 new Job("ArrayDeque.forEach") {
414 public void work() throws Throwable {
415 int[] sum = new int[1];
416 for (int i = 0; i < iterations; i++) {
417 sum[0] = 0;
418 ad.forEach(n -> sum[0] += n);
419 check.sum(sum[0]);}}},
420 new Job("Vector.forEach") {
421 public void work() throws Throwable {
422 int[] sum = new int[1];
423 for (int i = 0; i < iterations; i++) {
424 sum[0] = 0;
425 v.forEach(n -> sum[0] += n);
426 check.sum(sum[0]);}}},
427 new Job("ArrayList.iterator().forEachRemaining()") {
428 public void work() throws Throwable {
429 int[] sum = new int[1];
430 for (int i = 0; i < iterations; i++) {
431 sum[0] = 0;
432 al.iterator().forEachRemaining(n -> sum[0] += n);
433 check.sum(sum[0]);}}},
434 new Job("ArrayDeque.descendingIterator().forEachRemaining()") {
435 public void work() throws Throwable {
436 int[] sum = new int[1];
437 for (int i = 0; i < iterations; i++) {
438 sum[0] = 0;
439 ad.descendingIterator().forEachRemaining(n -> sum[0] += n);
440 check.sum(sum[0]);}}},
441 new Job("ArrayDeque.iterator().forEachRemaining()") {
442 public void work() throws Throwable {
443 int[] sum = new int[1];
444 for (int i = 0; i < iterations; i++) {
445 sum[0] = 0;
446 ad.iterator().forEachRemaining(n -> sum[0] += n);
447 check.sum(sum[0]);}}},
448 new Job("Vector.iterator().forEachRemaining()") {
449 public void work() throws Throwable {
450 int[] sum = new int[1];
451 for (int i = 0; i < iterations; i++) {
452 sum[0] = 0;
453 v.iterator().forEachRemaining(n -> sum[0] += n);
454 check.sum(sum[0]);}}},
455 new Job("ArrayList.spliterator().forEachRemaining()") {
456 public void work() throws Throwable {
457 int[] sum = new int[1];
458 for (int i = 0; i < iterations; i++) {
459 sum[0] = 0;
460 al.spliterator().forEachRemaining(n -> sum[0] += n);
461 check.sum(sum[0]);}}},
462 new Job("ArrayDeque.spliterator().forEachRemaining()") {
463 public void work() throws Throwable {
464 int[] sum = new int[1];
465 for (int i = 0; i < iterations; i++) {
466 sum[0] = 0;
467 ad.spliterator().forEachRemaining(n -> sum[0] += n);
468 check.sum(sum[0]);}}},
469 new Job("Vector.spliterator().forEachRemaining()") {
470 public void work() throws Throwable {
471 int[] sum = new int[1];
472 for (int i = 0; i < iterations; i++) {
473 sum[0] = 0;
474 v.spliterator().forEachRemaining(n -> sum[0] += n);
475 check.sum(sum[0]);}}},
476 new Job("ArrayList subList get loop") {
477 public void work() throws Throwable {
478 List<Integer> sl = asSubList(al);
479 for (int i = 0; i < iterations; i++) {
480 int sum = 0;
481 int size = sl.size();
482 for (int j = 0; j < size; ++j)
483 sum += sl.get(j);
484 check.sum(sum);}}},
485 new Job("ArrayList subList iterate for loop") {
486 public void work() throws Throwable {
487 for (int i = 0; i < iterations; i++) {
488 int sum = 0;
489 for (Integer n : asSubList(al))
490 sum += n;
491 check.sum(sum);}}},
492 new Job("ArrayList subList subList subList iterate for loop") {
493 public void work() throws Throwable {
494 for (int i = 0; i < iterations; i++) {
495 int sum = 0;
496 for (Integer n : asSubList(asSubList(asSubList(al))))
497 sum += n;
498 check.sum(sum);}}},
499 new Job("ArrayList backwards wrapper ListIterator for loop") {
500 public void work() throws Throwable {
501 for (int i = 0; i < iterations; i++) {
502 int sum = 0;
503 for (Integer n : backwards(al))
504 sum += n;
505 check.sum(sum);}}},
506 new Job("ArrayList backwards wrapper subList ListIterator for loop") {
507 public void work() throws Throwable {
508 for (int i = 0; i < iterations; i++) {
509 int sum = 0;
510 for (Integer n : backwards(asSubList(al)))
511 sum += n;
512 check.sum(sum);}}},
513 // new Job("ArrayList iterate desugared") {
514 // public void work() throws Throwable {
515 // for (int i = 0; i < iterations; i++) {
516 // int sum = 0;
517 // for (Iterator<Integer> it = al.iterator(); it.hasNext();)
518 // sum += it.next();
519 // check.sum(sum);}}},
520 new Job("Short ArrayList get loop") {
521 public void work() throws Throwable {
522 for (int i = 0; i < (iterations * size / shortSize); i++) {
523 int sum = 0;
524 int size = sal.size();
525 for (int j = 0; j < size; ++j)
526 sum += sal.get(j);
527 shortCheck.sum(sum);}}},
528 new Job("Short ArrayList iterate for loop") {
529 public void work() throws Throwable {
530 for (int i = 0; i < (iterations * size / shortSize); i++) {
531 int sum = 0;
532 for (Integer n : sal)
533 sum += n;
534 shortCheck.sum(sum);}}},
535 new Job("Short ArrayList sublist iterate for loop") {
536 public void work() throws Throwable {
537 for (int i = 0; i < (iterations * size / shortSize); i++) {
538 int sum = 0;
539 for (Integer n : asSubList(sal))
540 sum += n;
541 shortCheck.sum(sum);}}},
542 new Job("Vector ArrayList alternating iteration") {
543 public void work() throws Throwable {
544 for (int i = 0; i < iterations; i++) {
545 int sum = 0;
546 Iterator<Integer> it1 = v.iterator();
547 Iterator<Integer> it2 = al.iterator();
548 while (it1.hasNext())
549 sum += it1.next() + it2.next();
550 check.sum(sum/2);}}},
551 new Job("Vector ArrayList alternating invokeVirtual iteration") {
552 public void work() throws Throwable {
553 for (int i = 0; i < iterations; i++) {
554 int sum = 0;
555 List<Iterator<Integer>> its
556 = new ArrayList<Iterator<Integer>>(2);
557 its.add(v.iterator());
558 its.add(al.iterator());
559 for (int k = 0; its.get(k).hasNext(); k = (k == 0) ? 1 : 0)
560 sum += its.get(k).next();
561 check.sum(sum/2);}}},
562 new Job("ConcurrentSkipListMap entrySet iterate") {
563 public void work() throws Throwable {
564 for (int i = 0; i < iterations; i++) {
565 int sum = 0;
566 for (Map.Entry<Integer,Integer> e : m.entrySet())
567 sum += e.getKey();
568 deoptimize(sum);}}}
569 };
570
571 time(filter(filter, jobs));
572 }
573 }