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.concurrent; 24 25 import org.openjdk.jmh.annotations.Benchmark; 26 import org.openjdk.jmh.annotations.OutputTimeUnit; 27 import org.openjdk.jmh.annotations.Param; 28 import org.openjdk.jmh.annotations.Scope; 29 import org.openjdk.jmh.annotations.Setup; 30 import org.openjdk.jmh.annotations.State; 31 import org.openjdk.jmh.annotations.TearDown; 32 33 import java.util.concurrent.ExecutionException; 34 import java.util.concurrent.ForkJoinPool; 35 import java.util.concurrent.ForkJoinTask; 36 import java.util.concurrent.RecursiveTask; 37 import java.util.concurrent.TimeUnit; 38 39 /** 40 * Benchmark assesses ForkJoinPool forking infrastructure. 41 * 42 * @author Aleksey Shipilev (aleksey.shipilev@oracle.com) 43 */ 44 @OutputTimeUnit(TimeUnit.MINUTES) 45 @State(Scope.Benchmark) 46 public class ForkJoinPoolForking { 47 48 /** 49 * Implementation notes: 50 * 51 * This test harnesses forking infrastructure within FJP. 52 * As such, no slack is given for allocating any humble number of tasks: the goal is to fork a lot. 53 * The approximate number of tasks is (SIZE / THRESHOLD). 54 * 55 * Raw baseline gives the idea for compute bound for this benchmark. 56 * FJP could be faster than baseline, because the baseline is single-threaded. 57 */ 58 59 @Param("0") 60 private int workers; 61 62 @Param("10000000") 63 private int size; 64 65 @Param("10") 66 private int threshold; 67 68 private Problem problem; 69 private ForkJoinPool fjpSync; 70 private ForkJoinPool fjpAsync; 71 72 @Setup 73 public void setup() { 74 problem = new Problem(size); 75 if (workers == 0) { 76 workers = Runtime.getRuntime().availableProcessors(); 77 } 78 fjpSync = new ForkJoinPool(workers, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, false); 79 fjpAsync = new ForkJoinPool(workers, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); 80 } 81 82 @TearDown 83 public void teardown() { 84 fjpSync.shutdownNow(); 85 fjpAsync.shutdownNow(); 86 } 87 88 @Benchmark 89 public long baselineRaw() { 90 return problem.solve(); 91 } 92 93 @Benchmark 94 public Long testExplicit_Sync() throws ExecutionException, InterruptedException { 95 return fjpSync.invoke(new ExplicitTask(problem, 0, problem.size(), threshold)); 96 } 97 98 @Benchmark 99 public Long testExplicit_Async() throws ExecutionException, InterruptedException { 100 return fjpAsync.invoke(new ExplicitTask(problem, 0, problem.size(), threshold)); 101 } 102 103 @Benchmark 104 public Long testStandard_Sync() throws ExecutionException, InterruptedException { 105 return fjpSync.invoke(new StandardTask(problem, 0, problem.size(), threshold)); 106 } 107 108 @Benchmark 109 public Long testStandard_Async() throws ExecutionException, InterruptedException { 110 return fjpAsync.invoke(new StandardTask(problem, 0, problem.size(), threshold)); 111 } 112 113 private static class ExplicitTask extends RecursiveTask<Long> { 114 private final Problem problem; 115 private final int l; 116 private final int r; 117 private final int thresh; 118 119 public ExplicitTask(Problem p, int l, int r, int thresh) { 120 this.problem = p; 121 this.l = l; 122 this.r = r; 123 this.thresh = thresh; 124 } 125 126 @Override 127 protected Long compute() { 128 if (r - l <= thresh) { 129 return problem.solve(l, r); 130 } 131 132 int mid = (l + r) >>> 1; 133 ForkJoinTask<Long> t1 = new ExplicitTask(problem, l, mid, thresh); 134 ForkJoinTask<Long> t2 = new ExplicitTask(problem, mid, r, thresh); 135 136 t1.fork(); 137 t2.fork(); 138 139 long res = 0; 140 res += t2.join(); 141 res += t1.join(); 142 return res; 143 } 144 } 145 146 private static class StandardTask extends RecursiveTask<Long> { 147 private final Problem problem; 148 private final int l; 149 private final int r; 150 private final int thresh; 151 152 public StandardTask(Problem p, int l, int r, int thresh) { 153 this.problem = p; 154 this.l = l; 155 this.r = r; 156 this.thresh = thresh; 157 } 158 159 @Override 160 protected Long compute() { 161 if (r - l <= thresh) { 162 return problem.solve(l, r); 163 } 164 165 int mid = (l + r) >>> 1; 166 ForkJoinTask<Long> t1 = new StandardTask(problem, l, mid, thresh); 167 ForkJoinTask<Long> t2 = new StandardTask(problem, mid, r, thresh); 168 169 ForkJoinTask.invokeAll(t1, t2); 170 long res = 0; 171 res += t1.join(); 172 res += t2.join(); 173 return res; 174 } 175 } 176 177 178 }