1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  */
  22 
  23 /*
  24  * This file is available under and governed by the GNU General Public
  25  * License version 2 only, as published by the Free Software Foundation.
  26  * However, the following notice accompanied the original version of this
  27  * file:
  28  *
  29  * Written by Doug Lea with assistance from members of JCP JSR-166
  30  * Expert Group and released to the public domain, as explained at
  31  * http://creativecommons.org/publicdomain/zero/1.0/
  32  */
  33 
  34 /*
  35  * @test
  36  * @bug 4486658
  37  * @summary checks to make sure a pipeline of exchangers passes data.
  38  * @library /lib/testlibrary/
  39  */
  40 
  41 import static java.util.concurrent.TimeUnit.MILLISECONDS;
  42 
  43 import java.util.concurrent.CyclicBarrier;
  44 import java.util.concurrent.Exchanger;
  45 import java.util.concurrent.ExecutorService;
  46 import java.util.concurrent.Executors;
  47 import jdk.testlibrary.Utils;
  48 
  49 public class ExchangeLoops {
  50     static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
  51     static final ExecutorService pool = Executors.newCachedThreadPool();
  52     static boolean print = false;
  53 
  54     static class Int {
  55         public int value;
  56         Int(int i) { value = i; }
  57     }
  58 
  59     public static void main(String[] args) throws Exception {
  60         int maxStages = 5;
  61         int iters = 2000;
  62 
  63         if (args.length > 0)
  64             maxStages = Integer.parseInt(args[0]);
  65 
  66         print = false;
  67         System.out.println("Warmup...");
  68         oneRun(2, iters);
  69         print = true;
  70 
  71         for (int i = 2; i <= maxStages; i += (i+1) >>> 1) {
  72             System.out.print("Threads: " + i + "\t: ");
  73             oneRun(i, iters);
  74         }
  75         pool.shutdown();
  76         if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
  77             throw new Error();
  78    }
  79 
  80     static class Stage implements Runnable {
  81         final int iters;
  82         final Exchanger<Int> left;
  83         final Exchanger<Int> right;
  84         final CyclicBarrier barrier;
  85         volatile int result;
  86         Stage(Exchanger<Int> left,
  87               Exchanger<Int> right,
  88               CyclicBarrier b, int iters) {
  89             this.left = left;
  90             this.right = right;
  91             barrier = b;
  92             this.iters = iters;
  93         }
  94 
  95         public void run() {
  96             try {
  97                 barrier.await();
  98                 Int item = new Int(hashCode());
  99                 for (int i = 0; i < iters; ++i) {
 100                     if (left != null) {
 101                         item.value = LoopHelpers.compute1(item.value);
 102                         Int other = left.exchange(item);
 103                         if (other == item || other == null)
 104                             throw new Error("Failed Exchange");
 105                         item = other;
 106 
 107                     }
 108                     if (right != null) {
 109                         item.value = LoopHelpers.compute2(item.value);
 110                         Int other = right.exchange(item);
 111                         if (other == item || other == null)
 112                             throw new Error("Failed Exchange");
 113                         item = other;
 114                     }
 115                 }
 116                 barrier.await();
 117 
 118             }
 119             catch (Exception ex) {
 120                 ex.printStackTrace();
 121                 return;
 122             }
 123         }
 124     }
 125 
 126     static void oneRun(int nthreads, int iters) throws Exception {
 127         LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
 128         CyclicBarrier barrier = new CyclicBarrier(nthreads + 1, timer);
 129         Exchanger<Int> l = null;
 130         Exchanger<Int> r = new Exchanger<>();
 131         for (int i = 0; i < nthreads; ++i) {
 132             pool.execute(new Stage(l, r, barrier, iters));
 133             l = r;
 134             r = (i+2 < nthreads) ? new Exchanger<Int>() : null;
 135         }
 136         barrier.await();
 137         barrier.await();
 138         long time = timer.getTime();
 139         if (print)
 140             System.out.println(LoopHelpers.rightJustify(time / (iters * nthreads + iters * (nthreads-2))) + " ns per transfer");
 141     }
 142 
 143 }