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 performance with dependence on threshold. 41 */ 42 @OutputTimeUnit(TimeUnit.MINUTES) 43 @State(Scope.Benchmark) 44 public class ForkJoinPoolThresholdAutoSurplus { 45 46 /** 47 * Implementation notes: 48 * 49 * This test solves the problem with threshold = 1, and adaptive heuristics. The optimal level is static, 50 * and lies somewhere in 1..2 interval. Note the test degrades significantly when heuristic starts to fail, 51 * and the throughput is buried under FJP overheads. 52 * 53 * Baseline includes solving problem sequentially. Hence, each test provides the speedup for parallel execution 54 * versus sequential version. 55 */ 56 57 @Param("0") 58 private int workers; 59 60 @Param("10000000") 61 private int size; 62 63 @Param({"1", "2", "3", "4", "5", "6", "7", "8"}) 64 private int threshold; 65 66 private ForkJoinPool fjp; 67 private Problem problem; 68 69 @Setup 70 public void setup() { 71 if (workers == 0) { 72 workers = Runtime.getRuntime().availableProcessors(); 73 } 74 75 problem = new Problem(size); 76 fjp = new ForkJoinPool(workers); 77 } 78 79 @TearDown 80 public void teardown() { 81 fjp.shutdownNow(); 82 } 83 84 @Benchmark 85 public long baselineRaw() { 86 return problem.solve(); 87 } 88 89 @Benchmark 90 public Long test() throws ExecutionException, InterruptedException { 91 return fjp.invoke(new AutoQueuedTask(threshold, problem, 0, problem.size())); 92 } 93 94 private static class AutoQueuedTask extends RecursiveTask<Long> { 95 private final int thr; 96 private final Problem problem; 97 private final int l; 98 private final int r; 99 100 public AutoQueuedTask(int thr, Problem p, int l, int r) { 101 this.thr = thr; 102 this.problem = p; 103 this.l = l; 104 this.r = r; 105 } 106 107 @Override 108 protected Long compute() { 109 if (r - l <= 1 || getSurplusQueuedTaskCount() >= thr) { 110 return problem.solve(l, r); 111 } 112 113 int mid = (l + r) >>> 1; 114 ForkJoinTask<Long> t1 = new AutoQueuedTask(thr, problem, l, mid); 115 ForkJoinTask<Long> t2 = new AutoQueuedTask(thr, problem, mid, r); 116 117 t2.fork(); 118 119 long res = 0; 120 res += t1.invoke(); 121 res += t2.join(); 122 return res; 123 } 124 } 125 126 127 128 }