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;
main(String[] args)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 }
159