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/DoubleAdderDemo.java
31 *
32 * The demo is a micro-benchmark to compare synchronized access to a primitive
33 * double and DoubleAdder (run without any args), this restricted version simply
34 * exercises the basic functionality of DoubleAdder, suitable for automated
35 * testing (-shortrun).
36 */
37
38/*
39 * @test
40 * @bug 8005311
41 * @run main DoubleAdderDemo -shortrun
42 * @summary Basic test for Doubledder
43 */
44
45import java.util.concurrent.ExecutorService;
46import java.util.concurrent.Executors;
47import java.util.concurrent.Phaser;
48import java.util.concurrent.atomic.DoubleAdder;
49
50public class DoubleAdderDemo {
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    static final class SynchronizedDoubleAdder {
58        double value;
59        synchronized double sum() { return value; }
60        synchronized void add(double x) { value += x; }
61    }
62
63    public static void main(String[] args) {
64        boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
65        int maxNumThreads = shortRun ? SHORT_RUN_MAX_THREADS : LONG_RUN_MAX_THREADS;
66
67        System.out.println("Warmup...");
68        int half = NCPU > 1 ? NCPU / 2 : 1;
69        if (!shortRun)
70            syncTest(half, 1000);
71        adderTest(half, 1000);
72
73        for (int reps = 0; reps < 2; ++reps) {
74            System.out.println("Running...");
75            for (int i = 1; i <= maxNumThreads; i <<= 1) {
76                if (!shortRun)
77                    syncTest(i, INCS_PER_THREAD);
78                adderTest(i, INCS_PER_THREAD);
79            }
80        }
81        pool.shutdown();
82    }
83
84    static void syncTest(int nthreads, int incs) {
85        System.out.print("Synchronized ");
86        Phaser phaser = new Phaser(nthreads + 1);
87        SynchronizedDoubleAdder a = new SynchronizedDoubleAdder();
88        for (int i = 0; i < nthreads; ++i)
89            pool.execute(new SyncTask(a, phaser, incs));
90        report(nthreads, incs, timeTasks(phaser), a.sum());
91    }
92
93    static void adderTest(int nthreads, int incs) {
94        System.out.print("DoubleAdder  ");
95        Phaser phaser = new Phaser(nthreads + 1);
96        DoubleAdder a = new DoubleAdder();
97        for (int i = 0; i < nthreads; ++i)
98            pool.execute(new AdderTask(a, phaser, incs));
99        report(nthreads, incs, timeTasks(phaser), a.sum());
100    }
101
102    static void report(int nthreads, int incs, long time, double sum) {
103        long total = (long)nthreads * incs;
104        if (sum != (double)total)
105            throw new Error(sum + " != " + total);
106        double secs = (double)time / (1000L * 1000 * 1000);
107        long rate = total * (1000L) / time;
108        System.out.printf("threads:%3d  Time: %7.3fsec  Incs per microsec: %4d\n",
109                          nthreads, secs, rate);
110    }
111
112    static long timeTasks(Phaser phaser) {
113        phaser.arriveAndAwaitAdvance();
114        long start = System.nanoTime();
115        phaser.arriveAndAwaitAdvance();
116        phaser.arriveAndAwaitAdvance();
117        return System.nanoTime() - start;
118    }
119
120    static final class AdderTask implements Runnable {
121        final DoubleAdder adder;
122        final Phaser phaser;
123        final int incs;
124        volatile double result;
125        AdderTask(DoubleAdder adder, Phaser phaser, int incs) {
126            this.adder = adder;
127            this.phaser = phaser;
128            this.incs = incs;
129        }
130
131        public void run() {
132            phaser.arriveAndAwaitAdvance();
133            phaser.arriveAndAwaitAdvance();
134            DoubleAdder a = adder;
135            for (int i = 0; i < incs; ++i)
136                a.add(1.0);
137            result = a.sum();
138            phaser.arrive();
139        }
140    }
141
142    static final class SyncTask implements Runnable {
143        final SynchronizedDoubleAdder adder;
144        final Phaser phaser;
145        final int incs;
146        volatile double result;
147        SyncTask(SynchronizedDoubleAdder adder, Phaser phaser, int incs) {
148            this.adder = adder;
149            this.phaser = phaser;
150            this.incs = incs;
151        }
152
153        public void run() {
154            phaser.arriveAndAwaitAdvance();
155            phaser.arriveAndAwaitAdvance();
156            SynchronizedDoubleAdder a = adder;
157            for (int i = 0; i < incs; ++i)
158                a.add(1.0);
159            result = a.sum();
160            phaser.arrive();
161        }
162    }
163
164}
165