Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/util/Collection/RemoveMicroBenchmark.java
41149 views
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 static java.util.concurrent.TimeUnit.MILLISECONDS;
31
import static java.util.stream.Collectors.toCollection;
32
33
import java.lang.ref.ReferenceQueue;
34
import java.lang.ref.WeakReference;
35
import java.util.ArrayDeque;
36
import java.util.ArrayList;
37
import java.util.Collection;
38
import java.util.Collections;
39
import java.util.Deque;
40
import java.util.HashMap;
41
import java.util.Iterator;
42
import java.util.LinkedList;
43
import java.util.List;
44
import java.util.ListIterator;
45
import java.util.PriorityQueue;
46
import java.util.Queue;
47
import java.util.Vector;
48
import java.util.concurrent.ArrayBlockingQueue;
49
import java.util.concurrent.BlockingDeque;
50
import java.util.concurrent.BlockingQueue;
51
import java.util.concurrent.ConcurrentLinkedDeque;
52
import java.util.concurrent.ConcurrentLinkedQueue;
53
import java.util.concurrent.CopyOnWriteArrayList;
54
import java.util.concurrent.CountDownLatch;
55
import java.util.concurrent.LinkedBlockingDeque;
56
import java.util.concurrent.LinkedBlockingQueue;
57
import java.util.concurrent.LinkedTransferQueue;
58
import java.util.concurrent.PriorityBlockingQueue;
59
import java.util.concurrent.ThreadLocalRandom;
60
import java.util.concurrent.TimeUnit;
61
import java.util.regex.Pattern;
62
import java.util.stream.Stream;
63
64
/**
65
* Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
66
*
67
* To run this in micro-benchmark mode, simply run as a normal java program.
68
* Be patient; this program runs for a very long time.
69
* For faster runs, restrict execution using command line args.
70
*
71
* @author Martin Buchholz
72
*/
73
public class RemoveMicroBenchmark {
74
abstract static class Job {
75
private final String name;
76
public Job(String name) { this.name = name; }
77
public String name() { return name; }
78
public abstract void work() throws Throwable;
79
public void run() {
80
try { work(); }
81
catch (Throwable ex) {
82
// current job cannot always be deduced from stacktrace.
83
throw new RuntimeException("Job failed: " + name(), ex);
84
}
85
}
86
}
87
88
final int iterations;
89
final int size; // number of elements in collections
90
final double warmupSeconds;
91
final long warmupNanos;
92
final Pattern nameFilter; // select subset of Jobs to run
93
final boolean reverse; // reverse order of Jobs
94
final boolean shuffle; // randomize order of Jobs
95
96
final ArrayList<Integer> elements; // contains size random Integers
97
98
RemoveMicroBenchmark(String[] args) {
99
iterations = intArg(args, "iterations", 10_000);
100
size = intArg(args, "size", 1000);
101
warmupSeconds = doubleArg(args, "warmup", 7.0);
102
nameFilter = patternArg(args, "filter");
103
reverse = booleanArg(args, "reverse");
104
shuffle = booleanArg(args, "shuffle");
105
106
warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
107
108
elements = ThreadLocalRandom.current().ints(size)
109
.mapToObj(x -> x)
110
.collect(toCollection(ArrayList::new));
111
}
112
113
// --------------- GC finalization infrastructure ---------------
114
115
/** No guarantees, but effective in practice. */
116
static void forceFullGc() {
117
long timeoutMillis = 1000L;
118
CountDownLatch finalized = new CountDownLatch(1);
119
ReferenceQueue<Object> queue = new ReferenceQueue<>();
120
WeakReference<Object> ref = new WeakReference<>(
121
new Object() { protected void finalize() { finalized.countDown(); }},
122
queue);
123
try {
124
for (int tries = 3; tries--> 0; ) {
125
System.gc();
126
if (finalized.await(timeoutMillis, MILLISECONDS)
127
&& queue.remove(timeoutMillis) != null
128
&& ref.get() == null) {
129
System.runFinalization(); // try to pick up stragglers
130
return;
131
}
132
timeoutMillis *= 4;
133
}
134
} catch (InterruptedException unexpected) {
135
throw new AssertionError("unexpected InterruptedException");
136
}
137
throw new AssertionError("failed to do a \"full\" gc");
138
}
139
140
/**
141
* Runs each job for long enough that all the runtime compilers
142
* have had plenty of time to warm up, i.e. get around to
143
* compiling everything worth compiling.
144
* Returns array of average times per job per run.
145
*/
146
long[] time0(List<Job> jobs) {
147
final int size = jobs.size();
148
long[] nanoss = new long[size];
149
for (int i = 0; i < size; i++) {
150
if (warmupNanos > 0) forceFullGc();
151
Job job = jobs.get(i);
152
long totalTime;
153
int runs = 0;
154
long startTime = System.nanoTime();
155
do { job.run(); runs++; }
156
while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
157
nanoss[i] = totalTime/runs;
158
}
159
return nanoss;
160
}
161
162
void time(List<Job> jobs) throws Throwable {
163
if (warmupNanos > 0) time0(jobs); // Warm up run
164
final int size = jobs.size();
165
final long[] nanoss = time0(jobs); // Real timing run
166
final long[] milliss = new long[size];
167
final double[] ratios = new double[size];
168
169
final String nameHeader = "Method";
170
final String millisHeader = "Millis";
171
final String ratioHeader = "Ratio";
172
173
int nameWidth = nameHeader.length();
174
int millisWidth = millisHeader.length();
175
int ratioWidth = ratioHeader.length();
176
177
for (int i = 0; i < size; i++) {
178
nameWidth = Math.max(nameWidth, jobs.get(i).name().length());
179
180
milliss[i] = nanoss[i]/(1000L * 1000L);
181
millisWidth = Math.max(millisWidth,
182
String.format("%d", milliss[i]).length());
183
184
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
185
ratioWidth = Math.max(ratioWidth,
186
String.format("%.3f", ratios[i]).length());
187
}
188
189
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
190
nameWidth, millisWidth, ratioWidth);
191
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
192
nameWidth, millisWidth, ratioWidth);
193
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
194
195
// Print out absolute and relative times, calibrated against first job
196
for (int i = 0; i < size; i++)
197
System.out.printf(format, jobs.get(i).name(), milliss[i], ratios[i]);
198
}
199
200
private static String keywordValue(String[] args, String keyword) {
201
for (String arg : args)
202
if (arg.startsWith(keyword))
203
return arg.substring(keyword.length() + 1);
204
return null;
205
}
206
207
private static int intArg(String[] args, String keyword, int defaultValue) {
208
String val = keywordValue(args, keyword);
209
return (val == null) ? defaultValue : Integer.parseInt(val);
210
}
211
212
private static double doubleArg(String[] args, String keyword, double defaultValue) {
213
String val = keywordValue(args, keyword);
214
return (val == null) ? defaultValue : Double.parseDouble(val);
215
}
216
217
private static Pattern patternArg(String[] args, String keyword) {
218
String val = keywordValue(args, keyword);
219
return (val == null) ? null : Pattern.compile(val);
220
}
221
222
private static boolean booleanArg(String[] args, String keyword) {
223
String val = keywordValue(args, keyword);
224
if (val == null || val.equals("false")) return false;
225
if (val.equals("true")) return true;
226
throw new IllegalArgumentException(val);
227
}
228
229
private static void deoptimize(int sum) {
230
if (sum == 42)
231
System.out.println("the answer");
232
}
233
234
private static <T> Iterable<T> backwards(final List<T> list) {
235
return new Iterable<T>() {
236
public Iterator<T> iterator() {
237
return new Iterator<T>() {
238
final ListIterator<T> it = list.listIterator(list.size());
239
public boolean hasNext() { return it.hasPrevious(); }
240
public T next() { return it.previous(); }
241
public void remove() { it.remove(); }};}};
242
}
243
244
// Checks for correctness *and* prevents loop optimizations
245
static class Check {
246
private int sum;
247
public void sum(int sum) {
248
if (this.sum == 0)
249
this.sum = sum;
250
if (this.sum != sum)
251
throw new AssertionError("Sum mismatch");
252
}
253
}
254
volatile Check check = new Check();
255
256
public static void main(String[] args) throws Throwable {
257
new RemoveMicroBenchmark(args).run();
258
}
259
260
HashMap<Class<?>, String> goodClassName = new HashMap<>();
261
262
String goodClassName(Class<?> klazz) {
263
return goodClassName.computeIfAbsent(
264
klazz,
265
k -> {
266
String simple = k.getSimpleName();
267
return (simple.equals("SubList")) // too simple!
268
? k.getName().replaceFirst(".*\\.", "")
269
: simple;
270
});
271
}
272
273
String goodClassName(Object x) {
274
return goodClassName(x.getClass());
275
}
276
277
static List<Integer> makeSubList(List<Integer> list) {
278
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
279
int size = rnd.nextInt(4);
280
for (int i = size; i--> 0; )
281
list.add(rnd.nextInt());
282
int index = rnd.nextInt(size + 1);
283
return list.subList(index, index);
284
}
285
286
private static <T> List<T> asSubList(List<T> list) {
287
return list.subList(0, list.size());
288
}
289
290
@SafeVarargs @SuppressWarnings("varargs")
291
private static <T> Stream<T> concatStreams(Stream<T> ... streams) {
292
return Stream.of(streams).flatMap(s -> s);
293
}
294
295
Class<?> topLevelClass(Object x) {
296
for (Class<?> k = x.getClass();; ) {
297
Class<?> enclosing = k.getEnclosingClass();
298
if (enclosing == null)
299
return k;
300
k = enclosing;
301
}
302
}
303
304
void run() throws Throwable {
305
ArrayList<Job> jobs = Stream.<Collection<Integer>>of(
306
new ArrayList<>(),
307
makeSubList(new ArrayList<>()),
308
new LinkedList<>(),
309
makeSubList(new LinkedList<>()),
310
new Vector<>(),
311
makeSubList(new Vector<>()),
312
new CopyOnWriteArrayList<>(),
313
makeSubList(new CopyOnWriteArrayList<>()),
314
new ArrayDeque<>(),
315
new PriorityQueue<>(),
316
new ArrayBlockingQueue<>(elements.size()),
317
new ConcurrentLinkedQueue<>(),
318
new ConcurrentLinkedDeque<>(),
319
new LinkedBlockingQueue<>(),
320
new LinkedBlockingDeque<>(),
321
new LinkedTransferQueue<>(),
322
new PriorityBlockingQueue<>())
323
.flatMap(x -> jobs(x))
324
.filter(job ->
325
nameFilter == null || nameFilter.matcher(job.name()).find())
326
.collect(toCollection(ArrayList::new));
327
328
if (reverse) Collections.reverse(jobs);
329
if (shuffle) Collections.shuffle(jobs);
330
331
time(jobs);
332
}
333
334
Stream<Job> jobs(Collection<Integer> x) {
335
return concatStreams(
336
collectionJobs(x),
337
338
(CopyOnWriteArrayList.class.isAssignableFrom(topLevelClass(x)))
339
? Stream.empty()
340
: iteratorRemoveJobs(x),
341
342
(x instanceof Queue)
343
? queueJobs((Queue<Integer>)x)
344
: Stream.empty(),
345
346
(x instanceof Deque)
347
? dequeJobs((Deque<Integer>)x)
348
: Stream.empty(),
349
350
(x instanceof BlockingQueue)
351
? blockingQueueJobs((BlockingQueue<Integer>)x)
352
: Stream.empty(),
353
354
(x instanceof BlockingDeque)
355
? blockingDequeJobs((BlockingDeque<Integer>)x)
356
: Stream.empty());
357
}
358
359
Collection<Integer> universeRecorder(int[] sum) {
360
return new ArrayList<>() {
361
public boolean contains(Object x) {
362
sum[0] += (Integer) x;
363
return true;
364
}};
365
}
366
367
Collection<Integer> emptyRecorder(int[] sum) {
368
return new ArrayList<>() {
369
public boolean contains(Object x) {
370
sum[0] += (Integer) x;
371
return false;
372
}};
373
}
374
375
Stream<Job> collectionJobs(Collection<Integer> x) {
376
final String klazz = goodClassName(x);
377
return Stream.of(
378
new Job(klazz + " removeIf") {
379
public void work() throws Throwable {
380
int[] sum = new int[1];
381
for (int i = 0; i < iterations; i++) {
382
sum[0] = 0;
383
x.addAll(elements);
384
x.removeIf(n -> { sum[0] += n; return true; });
385
check.sum(sum[0]);}}},
386
new Job(klazz + " removeIf rnd-two-pass") {
387
public void work() throws Throwable {
388
ThreadLocalRandom rnd = ThreadLocalRandom.current();
389
int[] sum = new int[1];
390
for (int i = 0; i < iterations; i++) {
391
sum[0] = 0;
392
x.addAll(elements);
393
x.removeIf(n -> {
394
boolean b = rnd.nextBoolean();
395
if (b) sum[0] += n;
396
return b; });
397
x.removeIf(n -> { sum[0] += n; return true; });
398
check.sum(sum[0]);}}},
399
new Job(klazz + " removeAll") {
400
public void work() throws Throwable {
401
int[] sum = new int[1];
402
Collection<Integer> universe = universeRecorder(sum);
403
for (int i = 0; i < iterations; i++) {
404
sum[0] = 0;
405
x.addAll(elements);
406
x.removeAll(universe);
407
check.sum(sum[0]);}}},
408
new Job(klazz + " retainAll") {
409
public void work() throws Throwable {
410
int[] sum = new int[1];
411
Collection<Integer> empty = emptyRecorder(sum);
412
for (int i = 0; i < iterations; i++) {
413
sum[0] = 0;
414
x.addAll(elements);
415
x.retainAll(empty);
416
check.sum(sum[0]);}}},
417
new Job(klazz + " clear") {
418
public void work() throws Throwable {
419
int[] sum = new int[1];
420
for (int i = 0; i < iterations; i++) {
421
sum[0] = 0;
422
x.addAll(elements);
423
x.forEach(e -> sum[0] += e);
424
x.clear();
425
check.sum(sum[0]);}}});
426
}
427
428
Stream<Job> iteratorRemoveJobs(Collection<Integer> x) {
429
final String klazz = goodClassName(x);
430
return Stream.of(
431
new Job(klazz + " Iterator.remove") {
432
public void work() throws Throwable {
433
int[] sum = new int[1];
434
for (int i = 0; i < iterations; i++) {
435
sum[0] = 0;
436
x.addAll(elements);
437
Iterator<Integer> it = x.iterator();
438
while (it.hasNext()) {
439
sum[0] += it.next();
440
it.remove();
441
}
442
check.sum(sum[0]);}}},
443
new Job(klazz + " Iterator.remove-rnd-two-pass") {
444
public void work() throws Throwable {
445
ThreadLocalRandom rnd = ThreadLocalRandom.current();
446
int[] sum = new int[1];
447
for (int i = 0; i < iterations; i++) {
448
sum[0] = 0;
449
x.addAll(elements);
450
for (Iterator<Integer> it = x.iterator();
451
it.hasNext(); ) {
452
Integer e = it.next();
453
if (rnd.nextBoolean()) {
454
sum[0] += e;
455
it.remove();
456
}
457
}
458
for (Iterator<Integer> it = x.iterator();
459
it.hasNext(); ) {
460
sum[0] += it.next();
461
it.remove();
462
}
463
check.sum(sum[0]);}}});
464
}
465
466
Stream<Job> queueJobs(Queue<Integer> x) {
467
final String klazz = goodClassName(x);
468
return Stream.of(
469
new Job(klazz + " poll()") {
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
x.addAll(elements);
475
for (Integer e; (e = x.poll()) != null; )
476
sum[0] += e;
477
check.sum(sum[0]);}}});
478
}
479
480
Stream<Job> dequeJobs(Deque<Integer> x) {
481
final String klazz = goodClassName(x);
482
return Stream.of(
483
new Job(klazz + " descendingIterator().remove") {
484
public void work() throws Throwable {
485
int[] sum = new int[1];
486
for (int i = 0; i < iterations; i++) {
487
sum[0] = 0;
488
x.addAll(elements);
489
Iterator<Integer> it = x.descendingIterator();
490
while (it.hasNext()) {
491
sum[0] += it.next();
492
it.remove();
493
}
494
check.sum(sum[0]);}}},
495
new Job(klazz + " pollFirst()") {
496
public void work() throws Throwable {
497
int[] sum = new int[1];
498
for (int i = 0; i < iterations; i++) {
499
sum[0] = 0;
500
x.addAll(elements);
501
for (Integer e; (e = x.pollFirst()) != null; )
502
sum[0] += e;
503
check.sum(sum[0]);}}},
504
new Job(klazz + " pollLast()") {
505
public void work() throws Throwable {
506
int[] sum = new int[1];
507
for (int i = 0; i < iterations; i++) {
508
sum[0] = 0;
509
x.addAll(elements);
510
for (Integer e; (e = x.pollLast()) != null; )
511
sum[0] += e;
512
check.sum(sum[0]);}}});
513
}
514
515
Stream<Job> blockingQueueJobs(BlockingQueue<Integer> x) {
516
final String klazz = goodClassName(x);
517
return Stream.of(
518
new Job(klazz + " timed poll()") {
519
public void work() throws Throwable {
520
int[] sum = new int[1];
521
for (int i = 0; i < iterations; i++) {
522
sum[0] = 0;
523
x.addAll(elements);
524
for (Integer e; (e = x.poll(0L, TimeUnit.DAYS)) != null; )
525
sum[0] += e;
526
check.sum(sum[0]);}}},
527
new Job(klazz + " drainTo(sink)") {
528
public void work() throws Throwable {
529
ArrayList<Integer> sink = new ArrayList<>();
530
int[] sum = new int[1];
531
for (int i = 0; i < iterations; i++) {
532
sum[0] = 0;
533
sink.clear();
534
x.addAll(elements);
535
x.drainTo(sink);
536
sink.forEach(e -> sum[0] += e);
537
check.sum(sum[0]);}}},
538
new Job(klazz + " drainTo(sink, n)") {
539
public void work() throws Throwable {
540
ArrayList<Integer> sink = new ArrayList<>();
541
int[] sum = new int[1];
542
for (int i = 0; i < iterations; i++) {
543
sum[0] = 0;
544
sink.clear();
545
x.addAll(elements);
546
x.drainTo(sink, elements.size());
547
sink.forEach(e -> sum[0] += e);
548
check.sum(sum[0]);}}});
549
}
550
551
Stream<Job> blockingDequeJobs(BlockingDeque<Integer> x) {
552
final String klazz = goodClassName(x);
553
return Stream.of(
554
new Job(klazz + " timed pollFirst()") {
555
public void work() throws Throwable {
556
int[] sum = new int[1];
557
for (int i = 0; i < iterations; i++) {
558
sum[0] = 0;
559
x.addAll(elements);
560
for (Integer e; (e = x.pollFirst(0L, TimeUnit.DAYS)) != null; )
561
sum[0] += e;
562
check.sum(sum[0]);}}},
563
new Job(klazz + " timed pollLast()") {
564
public void work() throws Throwable {
565
int[] sum = new int[1];
566
for (int i = 0; i < iterations; i++) {
567
sum[0] = 0;
568
x.addAll(elements);
569
for (Integer e; (e = x.pollLast(0L, TimeUnit.DAYS)) != null; )
570
sum[0] += e;
571
check.sum(sum[0]);}}});
572
}
573
}
574
575