1 /*
2  * Copyright (c) 2014, 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 package org.openjdk.bench.java.util.stream;
24 
25 import org.openjdk.jmh.annotations.Benchmark;
26 import org.openjdk.jmh.annotations.BenchmarkMode;
27 import org.openjdk.jmh.annotations.Level;
28 import org.openjdk.jmh.annotations.Mode;
29 import org.openjdk.jmh.annotations.OutputTimeUnit;
30 import org.openjdk.jmh.annotations.Param;
31 import org.openjdk.jmh.annotations.Scope;
32 import org.openjdk.jmh.annotations.Setup;
33 import org.openjdk.jmh.annotations.State;
34 
35 import java.util.concurrent.TimeUnit;
36 import java.util.stream.LongStream;
37 
38 /**
39  * This benchmark is the golden benchmark for decompositions.
40  * There are at least four parameters to juggle:
41  *   - pool parallelism (P), controlled via -Djava.util.concurrent.ForkJoinUtils.pool.parallelism
42  *   - problem size (N), controlled as benchmark param
43  *   - operation cost (Q), controlled as benchmark param
44  *   - number of clients (C), controlled via -t option in harness
45  *
46  * @author Aleksey Shipilev (aleksey.shipilev@oracle.com)
47  */
48 @BenchmarkMode(Mode.SampleTime)
49 @OutputTimeUnit(TimeUnit.MICROSECONDS)
50 @State(Scope.Thread)
51 public class Decomposition {
52 
53     @Param("1000")
54     private int N;
55 
56     @Param("1000")
57     private int Q;
58 
59     @State(Scope.Thread)
60     public static class Thinktime {
61         @Param("10")
62         private int S;
63 
64         @Setup(Level.Invocation)
sleep()65         public void sleep() throws InterruptedException {
66             TimeUnit.MILLISECONDS.sleep(S);
67         }
68     }
69 
70     @Benchmark
saturated_sequential()71     public long saturated_sequential() throws InterruptedException {
72         return LongStream.range(1, N).filter(k -> doWork(k, Q)).sum();
73     }
74 
75     @Benchmark
thinktime_sequential(Thinktime t)76     public long thinktime_sequential(Thinktime t) throws InterruptedException {
77         return LongStream.range(1, N).filter(k -> doWork(k, Q)).sum();
78     }
79 
80     @Benchmark
saturated_parallel()81     public long saturated_parallel() throws InterruptedException {
82         return LongStream.range(1, N).parallel().filter(k -> doWork(k, Q)).sum();
83     }
84 
85     @Benchmark
thinktime_parallel(Thinktime t)86     public long thinktime_parallel(Thinktime t) throws InterruptedException {
87         return LongStream.range(1, N).parallel().filter(k -> doWork(k, Q)).sum();
88     }
89 
90     /**
91      * Make some work.
92      * This method have a couple of distinguishable properties:
93      *   - the run time is linear with Q
94      *   - the computation is dependent on input, preventing common reductions
95      *   - the returned result is dependent on loop result, preventing dead code elimination
96      *   - the returned result is almost always false
97      *
98      * This code uses inlined version of ThreadLocalRandom.next() to mitigate the edge effects
99      * of acquiring TLR every single call.
100      *
101      * @param input input
102      * @return result
103      */
doWork(long input, long count)104     public static boolean doWork(long input, long count) {
105         long t = input;
106         for (int i = 0; i < count; i++) {
107             t += (t * 0x5DEECE66DL + 0xBL) & (0xFFFFFFFFFFFFL);
108         }
109         return (t == 0);
110     }
111 
112 }
113