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
44import java.util.concurrent.ExecutorService;
45import java.util.concurrent.Executors;
46import java.util.concurrent.Phaser;
47import java.util.concurrent.atomic.AtomicLong;
48import java.util.concurrent.atomic.LongAdder;
49
50public 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 time, long sum) {
97        long total = (long)nthreads * incs;
98        if (sum != total)
99            throw new Error(sum + " != " + total);
100        double secs = (double)time / (1000L * 1000 * 1000);
101        long rate = total * (1000L) / time;
102        System.out.printf("threads:%3d  Time: %7.3fsec  Incs per microsec: %4d\n",
103                          nthreads, secs, 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}
159