1 /*
   2  * Copyright (c) 2013, 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  * Written by Doug Lea with assistance from members of JCP JSR-166
  26  * Expert Group and released to the public domain, as explained at
  27  * http://creativecommons.org/publicdomain/zero/1.0/
  28  */
  29 
  30 /* Adapted from Dougs CVS test/jsr166e/LongAdderDemo.java
  31  *
  32  * The demo is a micro-benchmark to compare AtomicLong and LongAdder (run
  33  * without any args), this restricted version simply exercises the basic
  34  * functionality of LongAdder, suitable for automated testing (-shortrun).
  35  */
  36 
  37 /*
  38  * @test
  39  * @bug 8005311
  40  * @run main LongAdderDemo -shortrun
  41  * @summary Basic test for LongAdder
  42  */
  43 
  44 import java.util.concurrent.ExecutorService;
  45 import java.util.concurrent.Executors;
  46 import java.util.concurrent.Phaser;
  47 import java.util.concurrent.atomic.AtomicLong;
  48 import java.util.concurrent.atomic.LongAdder;
  49 
  50 public class LongAdderDemo {
  51     static final int INCS_PER_THREAD = 10000000;
  52     static final int NCPU = Runtime.getRuntime().availableProcessors();
  53     static final int SHORT_RUN_MAX_THREADS = NCPU > 1 ? NCPU / 2 : 1;
  54     static final int LONG_RUN_MAX_THREADS = NCPU * 2;
  55     static final ExecutorService pool = Executors.newCachedThreadPool();
  56 
  57     public static void main(String[] args) {
  58         boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
  59         int maxNumThreads = shortRun ? SHORT_RUN_MAX_THREADS : LONG_RUN_MAX_THREADS;
  60 
  61         System.out.println("Warmup...");
  62         int half = NCPU > 1 ? NCPU / 2 : 1;
  63         if (!shortRun)
  64             casTest(half, 1000);
  65         adderTest(half, 1000);
  66 
  67         for (int reps = 0; reps < 2; ++reps) {
  68             System.out.println("Running...");
  69             for (int i = 1; i <= maxNumThreads; i <<= 1) {
  70                 if (!shortRun)
  71                     casTest(i, INCS_PER_THREAD);
  72                 adderTest(i, INCS_PER_THREAD);
  73             }
  74         }
  75         pool.shutdown();
  76     }
  77 
  78     static void casTest(int nthreads, int incs) {
  79         System.out.print("AtomicLong ");
  80         Phaser phaser = new Phaser(nthreads + 1);
  81         AtomicLong a = new AtomicLong();
  82         for (int i = 0; i < nthreads; ++i)
  83             pool.execute(new CasTask(a, phaser, incs));
  84         report(nthreads, incs, timeTasks(phaser), a.get());
  85     }
  86 
  87     static void adderTest(int nthreads, int incs) {
  88         System.out.print("LongAdder  ");
  89         Phaser phaser = new Phaser(nthreads + 1);
  90         LongAdder a = new LongAdder();
  91         for (int i = 0; i < nthreads; ++i)
  92             pool.execute(new AdderTask(a, phaser, incs));
  93         report(nthreads, incs, timeTasks(phaser), a.sum());
  94     }
  95 
  96     static void report(int nthreads, int incs, long elapsedNanos, long sum) {
  97         long total = (long)nthreads * incs;
  98         if (sum != total)
  99             throw new Error(sum + " != " + total);
 100         double elapsedSecs = (double)elapsedNanos / (1000L * 1000 * 1000);
 101         long rate = total * 1000L / elapsedNanos;
 102         System.out.printf("threads:%3d  Time: %7.3fsec  Incs per microsec: %4d\n",
 103                           nthreads, elapsedSecs, rate);
 104     }
 105 
 106     static long timeTasks(Phaser phaser) {
 107         phaser.arriveAndAwaitAdvance();
 108         long start = System.nanoTime();
 109         phaser.arriveAndAwaitAdvance();
 110         phaser.arriveAndAwaitAdvance();
 111         return System.nanoTime() - start;
 112     }
 113 
 114     static final class AdderTask implements Runnable {
 115         final LongAdder adder;
 116         final Phaser phaser;
 117         final int incs;
 118         volatile long result;
 119         AdderTask(LongAdder adder, Phaser phaser, int incs) {
 120             this.adder = adder;
 121             this.phaser = phaser;
 122             this.incs = incs;
 123         }
 124 
 125         public void run() {
 126             phaser.arriveAndAwaitAdvance();
 127             phaser.arriveAndAwaitAdvance();
 128             LongAdder a = adder;
 129             for (int i = 0; i < incs; ++i)
 130                 a.increment();
 131             result = a.sum();
 132             phaser.arrive();
 133         }
 134     }
 135 
 136     static final class CasTask implements Runnable {
 137         final AtomicLong adder;
 138         final Phaser phaser;
 139         final int incs;
 140         volatile long result;
 141         CasTask(AtomicLong adder, Phaser phaser, int incs) {
 142             this.adder = adder;
 143             this.phaser = phaser;
 144             this.incs = incs;
 145         }
 146 
 147         public void run() {
 148             phaser.arriveAndAwaitAdvance();
 149             phaser.arriveAndAwaitAdvance();
 150             AtomicLong a = adder;
 151             for (int i = 0; i < incs; ++i)
 152                 a.getAndIncrement();
 153             result = a.get();
 154             phaser.arrive();
 155         }
 156     }
 157 
 158 }