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 
main(String[] args)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 
casTest(int nthreads, int incs)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 
adderTest(int nthreads, int incs)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 
report(int nthreads, int incs, long elapsedNanos, long sum)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 
timeTasks(Phaser phaser)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;
AdderTask(LongAdder adder, Phaser phaser, int incs)119         AdderTask(LongAdder adder, Phaser phaser, int incs) {
120             this.adder = adder;
121             this.phaser = phaser;
122             this.incs = incs;
123         }
124 
run()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;
CasTask(AtomicLong adder, Phaser phaser, int incs)141         CasTask(AtomicLong adder, Phaser phaser, int incs) {
142             this.adder = adder;
143             this.phaser = phaser;
144             this.incs = incs;
145         }
146 
run()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 }
159